bool nsNativeTheme::IsFrameRTL(nsIFrame* aFrame) { if (!aFrame) { return false; } WritingMode wm = aFrame->GetWritingMode(); return !(wm.IsVertical() ? wm.IsVerticalLR() : wm.IsBidiLTR()); }
explicit GetWritingModeName(const WritingMode& aWritingMode) { if (!aWritingMode.IsVertical()) { Assign("Horizontal"); return; } if (aWritingMode.IsVerticalLR()) { Assign("Vertical (LTR)"); return; } Assign("Vertical (RTL)"); }
/* returns a Direction struct containing the horizontal and vertical direction */ nsResizerFrame::Direction nsResizerFrame::GetDirection() { static const nsIContent::AttrValuesArray strings[] = { &nsGkAtoms::topleft, &nsGkAtoms::top, &nsGkAtoms::topright, &nsGkAtoms::left, &nsGkAtoms::right, &nsGkAtoms::bottomleft, &nsGkAtoms::bottom, &nsGkAtoms::bottomright, &nsGkAtoms::bottomstart, &nsGkAtoms::bottomend, nullptr }; static const Direction directions[] = { {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}, {-1, 1}, {1, 1} }; if (!GetContent()) { return directions[0]; // default: topleft } int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::dir, strings, eCaseMatters); if (index < 0) { return directions[0]; // default: topleft } if (index >= 8) { // Directions 8 and higher are RTL-aware directions and should reverse the // horizontal component if RTL. WritingMode wm = GetWritingMode(); if (!(wm.IsVertical() ? wm.IsVerticalLR() : wm.IsBidiLTR())) { Direction direction = directions[index]; direction.mHorizontal *= -1; return direction; } } return directions[index]; }
void nsCaret::ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset, nsRect* aCaretRect, nsRect* aHookRect) { NS_ASSERTION(aFrame, "Should have a frame here"); WritingMode wm = aFrame->GetWritingMode(); bool isVertical = wm.IsVertical(); nscoord bidiIndicatorSize; *aCaretRect = GetGeometryForFrame(aFrame, aFrameOffset, &bidiIndicatorSize); // on RTL frames the right edge of mCaretRect must be equal to framePos const nsStyleVisibility* vis = aFrame->StyleVisibility(); if (NS_STYLE_DIRECTION_RTL == vis->mDirection) { if (isVertical) { aCaretRect->y -= aCaretRect->height; } else { aCaretRect->x -= aCaretRect->width; } } // Simon -- make a hook to draw to the left or right of the caret to show keyboard language direction aHookRect->SetEmpty(); if (!IsBidiUI()) { return; } bool isCaretRTL; nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard(); // if bidiKeyboard->IsLangRTL() fails, there is no way to tell the // keyboard direction, or the user has no right-to-left keyboard // installed, so we never draw the hook. if (bidiKeyboard && NS_SUCCEEDED(bidiKeyboard->IsLangRTL(&isCaretRTL))) { // If keyboard language is RTL, draw the hook on the left; if LTR, to the right // The height of the hook rectangle is the same as the width of the caret // rectangle. if (isVertical) { bool isSidewaysLR = wm.IsVerticalLR() && !wm.IsLineInverted(); if (isSidewaysLR) { aHookRect->SetRect(aCaretRect->x + bidiIndicatorSize, aCaretRect->y + (!isCaretRTL ? bidiIndicatorSize * -1 : aCaretRect->height), aCaretRect->height, bidiIndicatorSize); } else { aHookRect->SetRect(aCaretRect->XMost() - bidiIndicatorSize, aCaretRect->y + (isCaretRTL ? bidiIndicatorSize * -1 : aCaretRect->height), aCaretRect->height, bidiIndicatorSize); } } else { aHookRect->SetRect(aCaretRect->x + (isCaretRTL ? bidiIndicatorSize * -1 : aCaretRect->width), aCaretRect->y + bidiIndicatorSize, bidiIndicatorSize, aCaretRect->width); } } }
void nsFieldSetFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_PRECONDITION(aReflowState.ComputedISize() != NS_INTRINSICSIZE, "Should have a precomputed inline-size!"); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; nsOverflowAreas ocBounds; nsReflowStatus ocStatus = NS_FRAME_COMPLETE; if (GetPrevInFlow()) { ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0, ocStatus); } //------------ Handle Incremental Reflow ----------------- bool reflowInner; bool reflowLegend; nsIFrame* legend = GetLegend(); nsIFrame* inner = GetInner(); if (aReflowState.ShouldReflowAllKids()) { reflowInner = inner != nullptr; reflowLegend = legend != nullptr; } else { reflowInner = inner && NS_SUBTREE_DIRTY(inner); reflowLegend = legend && NS_SUBTREE_DIRTY(legend); } // We don't allow fieldsets to break vertically. If we did, we'd // need logic here to push and pull overflow frames. // Since we're not applying our padding in this frame, we need to add it here // to compute the available width for our children. WritingMode wm = GetWritingMode(); WritingMode innerWM = inner ? inner->GetWritingMode() : wm; WritingMode legendWM = legend ? legend->GetWritingMode() : wm; LogicalSize innerAvailSize = aReflowState.ComputedSizeWithPadding(innerWM); LogicalSize legendAvailSize = aReflowState.ComputedSizeWithPadding(legendWM); innerAvailSize.BSize(innerWM) = legendAvailSize.BSize(legendWM) = NS_UNCONSTRAINEDSIZE; NS_ASSERTION(!inner || nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext, inner, nsLayoutUtils::MIN_ISIZE) <= innerAvailSize.ISize(innerWM), "Bogus availSize.ISize; should be bigger"); NS_ASSERTION(!legend || nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext, legend, nsLayoutUtils::MIN_ISIZE) <= legendAvailSize.ISize(legendWM), "Bogus availSize.ISize; should be bigger"); // get our border and padding nsMargin border = aReflowState.ComputedPhysicalBorderPadding() - aReflowState.ComputedPhysicalPadding(); LogicalMargin logBorder(wm, border); // Figure out how big the legend is if there is one. // get the legend's margin LogicalMargin legendMargin(wm); // reflow the legend only if needed Maybe<nsHTMLReflowState> legendReflowState; if (legend) { legendReflowState.emplace(aPresContext, aReflowState, legend, legendAvailSize); } if (reflowLegend) { nsHTMLReflowMetrics legendDesiredSize(aReflowState); ReflowChild(legend, aPresContext, legendDesiredSize, *legendReflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); #ifdef NOISY_REFLOW printf(" returned (%d, %d)\n", legendDesiredSize.Width(), legendDesiredSize.Height()); #endif // figure out the legend's rectangle legendMargin = legend->GetLogicalUsedMargin(wm); mLegendRect = LogicalRect(wm, 0, 0, legendDesiredSize.ISize(wm) + legendMargin.IStartEnd(wm), legendDesiredSize.BSize(wm) + legendMargin.BStartEnd(wm)); nscoord oldSpace = mLegendSpace; mLegendSpace = 0; if (mLegendRect.BSize(wm) > logBorder.BStart(wm)) { // center the border on the legend mLegendSpace = mLegendRect.BSize(wm) - logBorder.BStart(wm); } else { mLegendRect.BStart(wm) = (logBorder.BStart(wm) - mLegendRect.BSize(wm)) / 2; } // if the legend space changes then we need to reflow the // content area as well. if (mLegendSpace != oldSpace && inner) { reflowInner = true; } // We'll move the legend to its proper place later. FinishReflowChild(legend, aPresContext, legendDesiredSize, legendReflowState.ptr(), 0, 0, NS_FRAME_NO_MOVE_FRAME); } else if (!legend) { mLegendRect.SetEmpty(); mLegendSpace = 0; } else { // mLegendSpace and mLegendRect haven't changed, but we need // the used margin when placing the legend. legendMargin = legend->GetLogicalUsedMargin(wm); } // reflow the content frame only if needed if (reflowInner) { nsHTMLReflowState kidReflowState(aPresContext, aReflowState, inner, innerAvailSize, -1, -1, nsHTMLReflowState::CALLER_WILL_INIT); // Override computed padding, in case it's percentage padding kidReflowState.Init(aPresContext, -1, -1, nullptr, &aReflowState.ComputedPhysicalPadding()); // Our child is "height:100%" but we actually want its height to be reduced // by the amount of content-height the legend is eating up, unless our // height is unconstrained (in which case the child's will be too). if (aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE) { kidReflowState.SetComputedHeight( std::max(0, aReflowState.ComputedHeight() - mLegendSpace)); } if (aReflowState.ComputedMinHeight() > 0) { kidReflowState.ComputedMinHeight() = std::max(0, aReflowState.ComputedMinHeight() - mLegendSpace); } if (aReflowState.ComputedMaxHeight() != NS_UNCONSTRAINEDSIZE) { kidReflowState.ComputedMaxHeight() = std::max(0, aReflowState.ComputedMaxHeight() - mLegendSpace); } nsHTMLReflowMetrics kidDesiredSize(kidReflowState, aDesiredSize.mFlags); // Reflow the frame NS_ASSERTION(kidReflowState.ComputedPhysicalMargin() == nsMargin(0,0,0,0), "Margins on anonymous fieldset child not supported!"); nsPoint pt(border.left, border.top); if (wm.IsVerticalLR()) { pt.x += mLegendSpace; } else if (!wm.IsVertical()) { pt.y += mLegendSpace; } ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState, pt.x, pt.y, 0, aStatus); FinishReflowChild(inner, aPresContext, kidDesiredSize, &kidReflowState, pt.x, pt.y, 0); NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus); } nscoord containerWidth = (wm.IsVertical() ? mLegendSpace : 0) + logBorder.LeftRight(wm) + (inner ? inner->GetSize().width : 0); LogicalRect contentRect(wm); if (inner) { // We don't support margins on inner, so our content rect is just the // inner's border-box. We don't care about container-width at this point, // as we'll figure out the actual positioning later. contentRect = inner->GetLogicalRect(wm, containerWidth); } // Our content rect must fill up the available width LogicalSize availSize = aReflowState.ComputedSizeWithPadding(wm); if (availSize.ISize(wm) > contentRect.ISize(wm)) { contentRect.ISize(wm) = innerAvailSize.ISize(wm); } if (legend) { // The legend is positioned inline-wards within the inner's content rect // (so that padding on the fieldset affects the legend position). LogicalRect innerContentRect = contentRect; innerContentRect.Deflate(wm, aReflowState.ComputedLogicalPadding()); // If the inner content rect is larger than the legend, we can align the // legend. if (innerContentRect.ISize(wm) > mLegendRect.ISize(wm)) { int32_t align = static_cast<nsLegendFrame*> (legend->GetContentInsertionFrame())->GetAlign(); if (!wm.IsBidiLTR()) { if (align == NS_STYLE_TEXT_ALIGN_LEFT || align == NS_STYLE_TEXT_ALIGN_MOZ_LEFT) { align = NS_STYLE_TEXT_ALIGN_END; } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT || align == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT) { align = NS_STYLE_TEXT_ALIGN_DEFAULT; } } switch (align) { case NS_STYLE_TEXT_ALIGN_END: mLegendRect.IStart(wm) = innerContentRect.IEnd(wm) - mLegendRect.ISize(wm); break; case NS_STYLE_TEXT_ALIGN_CENTER: case NS_STYLE_TEXT_ALIGN_MOZ_CENTER: // Note: rounding removed; there doesn't seem to be any need mLegendRect.IStart(wm) = innerContentRect.IStart(wm) + (innerContentRect.ISize(wm) - mLegendRect.ISize(wm)) / 2; break; default: mLegendRect.IStart(wm) = innerContentRect.IStart(wm); break; } } else { // otherwise make place for the legend mLegendRect.IStart(wm) = innerContentRect.IStart(wm); innerContentRect.ISize(wm) = mLegendRect.ISize(wm); contentRect.ISize(wm) = mLegendRect.ISize(wm) + aReflowState.ComputedLogicalPadding().IStartEnd(wm); } // place the legend LogicalRect actualLegendRect = mLegendRect; actualLegendRect.Deflate(wm, legendMargin); LogicalPoint actualLegendPos(actualLegendRect.Origin(wm)); legendReflowState->ApplyRelativePositioning(&actualLegendPos, containerWidth); legend->SetPosition(wm, actualLegendPos, containerWidth); nsContainerFrame::PositionFrameView(legend); nsContainerFrame::PositionChildViews(legend); } // Return our size and our result. LogicalSize finalSize(wm, contentRect.ISize(wm) + logBorder.IStartEnd(wm), mLegendSpace + logBorder.BStartEnd(wm) + (inner ? inner->GetLogicalSize(wm).BSize(wm) : 0)); aDesiredSize.SetSize(wm, finalSize); aDesiredSize.SetOverflowAreasToDesiredBounds(); if (legend) { ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend); } if (inner) { ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner); } // Merge overflow container bounds and status. aDesiredSize.mOverflowAreas.UnionWith(ocBounds); NS_MergeReflowStatusInto(&aStatus, ocStatus); FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); InvalidateFrame(); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }