nsRubyTextContainerFrame.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code is subject to the terms of the Mozilla Public License
  3. * version 2.0 (the "License"). You can obtain a copy of the License at
  4. * http://mozilla.org/MPL/2.0/. */
  5. /* rendering object for CSS "display: ruby-text-container" */
  6. #include "nsRubyTextContainerFrame.h"
  7. #include "mozilla/UniquePtr.h"
  8. #include "mozilla/WritingModes.h"
  9. #include "nsLineLayout.h"
  10. #include "nsPresContext.h"
  11. #include "nsStyleContext.h"
  12. using namespace mozilla;
  13. //----------------------------------------------------------------------
  14. // Frame class boilerplate
  15. // =======================
  16. NS_QUERYFRAME_HEAD(nsRubyTextContainerFrame)
  17. NS_QUERYFRAME_ENTRY(nsRubyTextContainerFrame)
  18. NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
  19. NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextContainerFrame)
  20. nsContainerFrame*
  21. NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
  22. nsStyleContext* aContext)
  23. {
  24. return new (aPresShell) nsRubyTextContainerFrame(aContext);
  25. }
  26. //----------------------------------------------------------------------
  27. // nsRubyTextContainerFrame Method Implementations
  28. // ===============================================
  29. nsIAtom*
  30. nsRubyTextContainerFrame::GetType() const
  31. {
  32. return nsGkAtoms::rubyTextContainerFrame;
  33. }
  34. #ifdef DEBUG_FRAME_DUMP
  35. nsresult
  36. nsRubyTextContainerFrame::GetFrameName(nsAString& aResult) const
  37. {
  38. return MakeFrameName(NS_LITERAL_STRING("RubyTextContainer"), aResult);
  39. }
  40. #endif
  41. /* virtual */ bool
  42. nsRubyTextContainerFrame::IsFrameOfType(uint32_t aFlags) const
  43. {
  44. if (aFlags & eSupportsCSSTransforms) {
  45. return false;
  46. }
  47. return nsContainerFrame::IsFrameOfType(aFlags);
  48. }
  49. /* virtual */ void
  50. nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID,
  51. nsFrameList& aChildList)
  52. {
  53. nsContainerFrame::SetInitialChildList(aListID, aChildList);
  54. if (aListID == kPrincipalList) {
  55. UpdateSpanFlag();
  56. }
  57. }
  58. /* virtual */ void
  59. nsRubyTextContainerFrame::AppendFrames(ChildListID aListID,
  60. nsFrameList& aFrameList)
  61. {
  62. nsContainerFrame::AppendFrames(aListID, aFrameList);
  63. UpdateSpanFlag();
  64. }
  65. /* virtual */ void
  66. nsRubyTextContainerFrame::InsertFrames(ChildListID aListID,
  67. nsIFrame* aPrevFrame,
  68. nsFrameList& aFrameList)
  69. {
  70. nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
  71. UpdateSpanFlag();
  72. }
  73. /* virtual */ void
  74. nsRubyTextContainerFrame::RemoveFrame(ChildListID aListID,
  75. nsIFrame* aOldFrame)
  76. {
  77. nsContainerFrame::RemoveFrame(aListID, aOldFrame);
  78. UpdateSpanFlag();
  79. }
  80. void
  81. nsRubyTextContainerFrame::UpdateSpanFlag()
  82. {
  83. bool isSpan = false;
  84. // The continuation checks are safe here because spans never break.
  85. if (!GetPrevContinuation() && !GetNextContinuation()) {
  86. nsIFrame* onlyChild = mFrames.OnlyChild();
  87. if (onlyChild && onlyChild->IsPseudoFrame(GetContent())) {
  88. // Per CSS Ruby spec, if the only child of an rtc frame is
  89. // a pseudo rt frame, it spans all bases in the segment.
  90. isSpan = true;
  91. }
  92. }
  93. if (isSpan) {
  94. AddStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN);
  95. } else {
  96. RemoveStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN);
  97. }
  98. }
  99. /* virtual */ void
  100. nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
  101. ReflowOutput& aDesiredSize,
  102. const ReflowInput& aReflowInput,
  103. nsReflowStatus& aStatus)
  104. {
  105. MarkInReflow();
  106. DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame");
  107. DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
  108. // Although a ruby text container may have continuations, returning
  109. // NS_FRAME_COMPLETE here is still safe, since its parent, ruby frame,
  110. // ignores the status, and continuations of the ruby base container
  111. // will take care of our continuations.
  112. aStatus = NS_FRAME_COMPLETE;
  113. WritingMode lineWM = aReflowInput.mLineLayout->GetWritingMode();
  114. nscoord minBCoord = nscoord_MAX;
  115. nscoord maxBCoord = nscoord_MIN;
  116. // The container size is not yet known, so we use a dummy (0, 0) size.
  117. // The block-dir position will be corrected below after containerSize
  118. // is finalized.
  119. const nsSize dummyContainerSize;
  120. for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
  121. nsIFrame* child = e.get();
  122. MOZ_ASSERT(child->GetType() == nsGkAtoms::rubyTextFrame);
  123. LogicalRect rect = child->GetLogicalRect(lineWM, dummyContainerSize);
  124. LogicalMargin margin = child->GetLogicalUsedMargin(lineWM);
  125. nscoord blockStart = rect.BStart(lineWM) - margin.BStart(lineWM);
  126. minBCoord = std::min(minBCoord, blockStart);
  127. nscoord blockEnd = rect.BEnd(lineWM) + margin.BEnd(lineWM);
  128. maxBCoord = std::max(maxBCoord, blockEnd);
  129. }
  130. LogicalSize size(lineWM, mISize, 0);
  131. if (!mFrames.IsEmpty()) {
  132. if (MOZ_UNLIKELY(minBCoord > maxBCoord)) {
  133. // XXX When bug 765861 gets fixed, this warning should be upgraded.
  134. NS_WARNING("bad block coord");
  135. minBCoord = maxBCoord = 0;
  136. }
  137. size.BSize(lineWM) = maxBCoord - minBCoord;
  138. nsSize containerSize = size.GetPhysicalSize(lineWM);
  139. for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
  140. nsIFrame* child = e.get();
  141. // We reflowed the child with a dummy container size, as the true size
  142. // was not yet known at that time.
  143. LogicalPoint pos = child->GetLogicalPosition(lineWM, dummyContainerSize);
  144. // Adjust block position to account for minBCoord,
  145. // then reposition child based on the true container width.
  146. pos.B(lineWM) -= minBCoord;
  147. // Relative positioning hasn't happened yet.
  148. // So MovePositionBy should not be used here.
  149. child->SetPosition(lineWM, pos, containerSize);
  150. nsContainerFrame::PlaceFrameView(child);
  151. }
  152. }
  153. aDesiredSize.SetSize(lineWM, size);
  154. }