Bug 1343819 - (Part 4) Adjust the height of line box. r?xidorn draft
authorKuoE0 <kuoe0.tw@gmail.com>
Sat, 18 Feb 2017 02:36:52 +0800
changeset 553965 17e07d412b71ff8146a6da9ebb7db4b5f764297c
parent 553964 a380df5199df3e0f0973ee8aee5284708b53745e
child 553966 d57453b9aa5c2f550809b1c5a82ff6cf384b37d0
push id51848
push userbmo:kuoe0@mozilla.com
push dateFri, 31 Mar 2017 05:09:20 +0000
reviewersxidorn
bugs1343819
milestone55.0a1
Bug 1343819 - (Part 4) Adjust the height of line box. r?xidorn MozReview-Commit-ID: DTlX114wPzB
layout/generic/nsLineLayout.cpp
layout/generic/nsLineLayout.h
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -1537,16 +1537,19 @@ nsLineLayout::VerticalAlignLine()
   // [1] maxBCoord - minBCoord (the distance between the first child's
   // block-start edge and the last child's block-end edge)
   //
   // [2] the maximum logical box block size (since not every frame may have
   // participated in #1; for example: "top" and "botttom" aligned frames)
   //
   // [3] the minimum line height ("line-height" property set on the
   // block frame)
+  //
+  // [4] the line-height-step property would make the height be the
+  // multiples of it
   nscoord lineBSize = psd->mMaxBCoord - psd->mMinBCoord;
 
   // Now that the line-height is computed, we need to know where the
   // baseline is in the line. Position baseline so that mMinBCoord is just
   // inside the start of the line box.
   nscoord baselineBCoord;
   if (psd->mMinBCoord < 0) {
     baselineBCoord = mBStartEdge - psd->mMinBCoord;
@@ -1572,16 +1575,20 @@ nsLineLayout::VerticalAlignLine()
     // When the line is shorter than the maximum block start aligned box
     nscoord extra = mMaxEndBoxBSize - lineBSize;
     baselineBCoord += extra;
     lineBSize = mMaxEndBoxBSize;
   }
   if (lineBSize < mMaxStartBoxBSize) {
     lineBSize = mMaxStartBoxBSize;
   }
+
+  // Adjust line-height according to line-height-step
+  ApplyLineHeightStep(psd, lineBSize, baselineBCoord);
+
 #ifdef NOISY_BLOCKDIR_ALIGN
   printf("  [line]==> lineBSize=%d baselineBCoord=%d\n", lineBSize, baselineBCoord);
 #endif
 
   // Now position all of the frames in the root span. We will also
   // recurse over the child spans and place any frames we find with
   // vertical-align: top or bottom.
   // XXX PERFORMANCE: set a bit per-span to avoid the extra work
@@ -2491,16 +2498,74 @@ nsLineLayout::VerticalAlignFrames(PerSpa
   if (maxStartBoxBSize > mMaxStartBoxBSize) {
     mMaxStartBoxBSize = maxStartBoxBSize;
   }
   if (maxEndBoxBSize > mMaxEndBoxBSize) {
     mMaxEndBoxBSize = maxEndBoxBSize;
   }
 }
 
+void
+nsLineLayout::ApplyLineHeightStep(PerSpanData* psd,
+                                  nscoord& aLineBSize,
+                                  nscoord& aBaselineBCoord)
+{
+  const nsStyleCoord& lhsCoord =
+    psd->mFrame->mFrame->StyleContext()->StyleText()->mLineHeightStep;
+  if (lhsCoord.GetUnit() == eStyleUnit_None || lhsCoord.GetCoordValue() == 0) {
+    return;
+  }
+
+  // calculate the extra space to add
+  nscoord lineHeightStep = lhsCoord.GetCoordValue();
+  int mod = aLineBSize % lineHeightStep;
+  nscoord extra = mod ? lineHeightStep - mod : 0;
+
+  // get max start/end leading affected by emphasis or ruby frame
+  nscoord maxStartLeading = 0;
+  nscoord maxEndLeading = 0;
+  for (auto pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
+    PerSpanData* frameSpan = pfd->mSpan;
+    if (!frameSpan) {
+      continue;
+    }
+
+    maxStartLeading = maxStartLeading > frameSpan->mBStartLeading
+                    ? maxStartLeading : frameSpan->mBStartLeading;
+    maxEndLeading = maxEndLeading > frameSpan->mBEndLeading
+                  ? maxEndLeading : frameSpan->mBEndLeading;
+  }
+
+  // Calculate baseline offset
+  //
+  // -------------------------------------
+  // |                 | baseline offset |
+  // | top extra space |-----------------|
+  // |                 | top ruby frame  |
+  // |-----------------------------------|
+  // |               text                |
+  // |---------------------------------- |
+  // |                 | end ruby frame  |
+  // | end extra space |-----------------|
+  // |                 |                 |
+  // -------------------------------------
+  //
+  // The extra space we calculated is affected by the height of ruby frame or
+  // emphasis. So, the real extra space corresponding to the text should be the
+  // sum of the extra space we calculated above, the height of the top ruby
+  // frame (emphasis) and the height of the end ruby frame (emphasis).
+  //
+  // And, the baseline offset would be the following calculation.
+  nscoord baselineOffset = (extra + maxStartLeading + maxEndLeading) / 2 - maxStartLeading;
+
+  // adjust new line height and baseline
+  aLineBSize += extra;
+  aBaselineBCoord += baselineOffset;
+}
+
 static void SlideSpanFrameRect(nsIFrame* aFrame, nscoord aDeltaWidth)
 {
   // This should not use nsIFrame::MovePositionBy because it happens
   // prior to relative positioning.  In particular, because
   // nsBlockFrame::PlaceLine calls aLineLayout.TrimTrailingWhiteSpace()
   // prior to calling aLineLayout.RelativePositionFrames().
   nsPoint p = aFrame->GetPosition();
   p.x -= aDeltaWidth;
--- a/layout/generic/nsLineLayout.h
+++ b/layout/generic/nsLineLayout.h
@@ -685,16 +685,20 @@ protected:
 
   void PlaceFrame(PerFrameData* pfd,
                   ReflowOutput& aMetrics);
 
   void AdjustLeadings(nsIFrame* spanFrame, PerSpanData* psd,
                       const nsStyleText* aStyleText, float aInflation,
                       bool* aZeroEffectiveSpanBox);
 
+  void ApplyLineHeightStep(PerSpanData* psd,
+                           nscoord& aLineBSize,
+                           nscoord& aBaselineBBCoord);
+
   void VerticalAlignFrames(PerSpanData* psd);
 
   void PlaceTopBottomFrames(PerSpanData* psd,
                             nscoord aDistanceFromStart,
                             nscoord aLineBSize);
 
   void ApplyRelativePositioning(PerFrameData* aPFD);