@@ -68,91 +68,96 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText,
6868
6969    SymbolQuads quads;
7070
71-     for  (const  PositionedGlyph &positionedGlyph: shapedText.positionedGlyphs ) {
72-         auto  fontPositions = positions.find (positionedGlyph.font );
73-         if  (fontPositions == positions.end ())
74-             continue ;
75- 
76-         auto  positionsIt = fontPositions->second .glyphPositionMap .find (positionedGlyph.glyph );
77-         if  (positionsIt == fontPositions->second .glyphPositionMap .end ()) {
78-             continue ;
71+     if  (shapedText.lineCount  == 0 ) return  quads;
72+     const  float  lineHeight = (std::fabs (shapedText.bottom ) + std::fabs (shapedText.top )) / shapedText.lineCount ;
73+     for  (const  auto & positionedGlyphs : shapedText.positionedGlyphs ) {
74+         const  float  currentHeight = lineHeight * positionedGlyphs.first ;
75+         for  (const  PositionedGlyph& positionedGlyph : positionedGlyphs.second ) {
76+             auto  fontPositions = positions.find (positionedGlyph.font );
77+             if  (fontPositions == positions.end ()) continue ;
78+ 
79+             auto  positionsIt = fontPositions->second .glyphPositionMap .find (positionedGlyph.glyph );
80+             if  (positionsIt == fontPositions->second .glyphPositionMap .end ()) {
81+                 continue ;
82+             }
83+ 
84+             const  GlyphPosition& glyph = positionsIt->second ;
85+             const  Rect<uint16_t >& rect = glyph.rect ;
86+ 
87+             //  The rects have an additional buffer that is not included in their size;
88+             const  float  glyphPadding = 1 .0f ;
89+             const  float  rectBuffer = 3 .0f  + glyphPadding;
90+ 
91+             const  float  halfAdvance = glyph.metrics .advance  * positionedGlyph.scale  / 2.0 ;
92+ 
93+             const  Point<float > glyphOffset =
94+                 alongLine ? Point<float >{positionedGlyph.x  + halfAdvance, positionedGlyph.y } : Point<float >{0 .0f , 0 .0f };
95+ 
96+             Point<float > builtInOffset = alongLine ? Point<float >{0 .0f , 0 .0f }
97+                                                    : Point<float >{positionedGlyph.x  + halfAdvance + textOffset[0 ],
98+                                                                   positionedGlyph.y  + textOffset[1 ]};
99+ 
100+             Point<float > verticalizedLabelOffset = {0 .0f , 0 .0f };
101+             const  bool  rotateVerticalGlyph = (alongLine || allowVerticalPlacement) && positionedGlyph.vertical ;
102+             if  (rotateVerticalGlyph) {
103+                 //  Vertical POI labels, that are rotated 90deg CW and whose glyphs must preserve upright orientation
104+                 //  need to be rotated 90deg CCW. After quad is rotated, it is translated to the original built-in
105+                 //  offset.
106+                 verticalizedLabelOffset = builtInOffset;
107+                 builtInOffset = {0 .0f , 0 .0f };
108+             }
109+ 
110+             const  float  x1 = (glyph.metrics .left  - rectBuffer) * positionedGlyph.scale  - halfAdvance + builtInOffset.x ;
111+             const  float  y1 = (-glyph.metrics .top  - rectBuffer) * positionedGlyph.scale  + builtInOffset.y ;
112+             const  float  x2 = x1 + rect.w  * positionedGlyph.scale ;
113+             const  float  y2 = y1 + rect.h  * positionedGlyph.scale ;
114+ 
115+             Point<float > tl{x1, y1};
116+             Point<float > tr{x2, y1};
117+             Point<float > bl{x1, y2};
118+             Point<float > br{x2, y2};
119+ 
120+             if  (rotateVerticalGlyph) {
121+                 //  Vertical-supporting glyphs are laid out in 24x24 point boxes (1 square em)
122+                 //  In horizontal orientation, the y values for glyphs are below the midline.
123+                 //  If the glyph's baseline is applicable, we take the relative y offset of the
124+                 //   glyph, which needs to erase out current line height that added to the glyphs.
125+                 //  Otherwise, we use a "yOffset" of -17 to pull them up to the middle.
126+                 //  By rotating counter-clockwise around the point at the center of the left
127+                 //  edge of a 24x24 layout box centered below the midline, we align the center
128+                 //  of the glyphs with the horizontal midline, so the yOffset is no longer
129+                 //  necessary, but we also pull the glyph to the left along the x axis.
130+                 //  The y coordinate includes baseline yOffset, therefore, needs to be accounted
131+                 //  for when glyph is rotated and translated.
132+                 const  float  yShift = (shapedText.hasBaseline  ? (positionedGlyph.y  - currentHeight) : Shaping::yOffset);
133+                 const  Point<float > center{-halfAdvance, halfAdvance - yShift};
134+                 const  float  verticalRotation = -M_PI_2;
135+ 
136+                 //  xHalfWidhtOffsetcorrection is a difference between full-width and half-width
137+                 //  advance, should be 0 for full-width glyphs and will pull up half-width glyphs.
138+                 const  float  xHalfWidhtOffsetcorrection = util::ONE_EM / 2  - halfAdvance;
139+                 const  Point<float > xOffsetCorrection{5 .0f  - yShift - xHalfWidhtOffsetcorrection, 0 .0f };
140+ 
141+                 tl = util::rotate (tl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
142+                 tr = util::rotate (tr - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
143+                 bl = util::rotate (bl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
144+                 br = util::rotate (br - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
145+             }
146+ 
147+             if  (textRotate) {
148+                 //  Compute the transformation matrix.
149+                 float  angle_sin = std::sin (textRotate);
150+                 float  angle_cos = std::cos (textRotate);
151+                 std::array<float , 4 > matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
152+ 
153+                 tl = util::matrixMultiply (matrix, tl);
154+                 tr = util::matrixMultiply (matrix, tr);
155+                 bl = util::matrixMultiply (matrix, bl);
156+                 br = util::matrixMultiply (matrix, br);
157+             }
158+ 
159+             quads.emplace_back (tl, tr, bl, br, rect, shapedText.writingMode , glyphOffset, positionedGlyph.sectionIndex );
79160        }
80- 
81-         const  GlyphPosition& glyph = positionsIt->second ;
82-         const  Rect<uint16_t >& rect = glyph.rect ;
83- 
84-         //  The rects have an additional buffer that is not included in their size;
85-         const  float  glyphPadding = 1 .0f ;
86-         const  float  rectBuffer = 3 .0f  + glyphPadding;
87- 
88-         const  float  halfAdvance = glyph.metrics .advance  * positionedGlyph.scale  / 2.0 ;
89- 
90-         const  Point<float > glyphOffset = alongLine ?
91-             Point<float >{ positionedGlyph.x  + halfAdvance, positionedGlyph.y  } :
92-             Point<float >{ 0 .0f , 0 .0f  };
93- 
94-         Point<float > builtInOffset = alongLine ?
95-             Point<float >{ 0 .0f , 0 .0f  } :
96-             Point<float >{ positionedGlyph.x  + halfAdvance + textOffset[0 ], positionedGlyph.y  + textOffset[1 ] };
97- 
98-         Point<float > verticalizedLabelOffset = { 0 .0f , 0 .0f  };
99-         const  bool  rotateVerticalGlyph = (alongLine || allowVerticalPlacement) && positionedGlyph.vertical ;
100-         if  (rotateVerticalGlyph) {
101-             //  Vertical POI labels, that are rotated 90deg CW and whose glyphs must preserve upright orientation
102-             //  need to be rotated 90deg CCW. After quad is rotated, it is translated to the original built-in offset.
103-             verticalizedLabelOffset = builtInOffset;
104-             builtInOffset = { 0 .0f , 0 .0f  };
105-         }
106- 
107-         const  float  x1 = (glyph.metrics .left  - rectBuffer) * positionedGlyph.scale  - halfAdvance + builtInOffset.x ;
108-         const  float  y1 = (-glyph.metrics .top  - rectBuffer) * positionedGlyph.scale  + builtInOffset.y ;
109-         const  float  x2 = x1 + rect.w  * positionedGlyph.scale ;
110-         const  float  y2 = y1 + rect.h  * positionedGlyph.scale ;
111- 
112-         Point<float > tl{x1, y1};
113-         Point<float > tr{x2, y1};
114-         Point<float > bl{x1, y2};
115-         Point<float > br{x2, y2};
116- 
117-         if  (rotateVerticalGlyph) {
118-             //  Vertical-supporting glyphs are laid out in 24x24 point boxes (1 square em)
119-             //  In horizontal orientation, the y values for glyphs are below the midline.
120-             //  If the glyph's baseline is applicable, we take the y value of the glyph.
121-             //  Otherwise, we use a "yOffset" of -17 to pull them up to the middle.
122-             //  By rotating counter-clockwise around the point at the center of the left
123-             //  edge of a 24x24 layout box centered below the midline, we align the center
124-             //  of the glyphs with the horizontal midline, so the yOffset is no longer
125-             //  necessary, but we also pull the glyph to the left along the x axis.
126-             //  The y coordinate includes baseline yOffset, therefore, needs to be accounted
127-             //  for when glyph is rotated and translated.
128-             const  float  yShift = (shapedText.hasBaseline  ? positionedGlyph.y  : Shaping::yOffset);
129-             const  Point<float > center{-halfAdvance, halfAdvance - yShift};
130-             const  float  verticalRotation = -M_PI_2;
131- 
132-             //  xHalfWidhtOffsetcorrection is a difference between full-width and half-width
133-             //  advance, should be 0 for full-width glyphs and will pull up half-width glyphs.
134-             const  float  xHalfWidhtOffsetcorrection = util::ONE_EM / 2  - halfAdvance;
135-             const  Point<float > xOffsetCorrection{5 .0f  - yShift - xHalfWidhtOffsetcorrection, 0 .0f };
136- 
137-             tl = util::rotate (tl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
138-             tr = util::rotate (tr - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
139-             bl = util::rotate (bl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
140-             br = util::rotate (br - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset;
141-         }
142- 
143-         if  (textRotate) {
144-             //  Compute the transformation matrix.
145-             float  angle_sin = std::sin (textRotate);
146-             float  angle_cos = std::cos (textRotate);
147-             std::array<float , 4 > matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
148- 
149-             tl = util::matrixMultiply (matrix, tl);
150-             tr = util::matrixMultiply (matrix, tr);
151-             bl = util::matrixMultiply (matrix, bl);
152-             br = util::matrixMultiply (matrix, br);
153-         }
154- 
155-         quads.emplace_back (tl, tr, bl, br, rect, shapedText.writingMode , glyphOffset, positionedGlyph.sectionIndex );
156161    }
157162
158163    return  quads;
0 commit comments