Skip to content

Commit c3e0caf

Browse files
authored
feat(css): add vertical-align property support and set the default line-height to 1.2 (#346)
1 parent ed0b6b2 commit c3e0caf

File tree

9 files changed

+376
-17
lines changed

9 files changed

+376
-17
lines changed

src/client/builtin_scene/web_content.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace builtin_scene
4141
, textDirection(skia::textlayout::TextDirection::kLtr)
4242
, textHeightBehavior(skia::textlayout::TextHeightBehavior::kAll)
4343
, textStyle()
44-
, lineHeight(1.5f)
44+
, lineHeight(1.2f)
4545
, useFixedLineHeight(false)
4646
, halfLeading(true)
4747
, leading(0.0f)
@@ -58,6 +58,7 @@ namespace builtin_scene
5858
, content_style_()
5959
, background_color_(1.0f, 1.0f, 1.0f, 0.0f)
6060
, device_pixel_ratio_(client_cssom::DevicePixelRatio)
61+
, texture_pad_(2)
6162
{
6263
resetSkSurface(initialWidth, initialHeight);
6364
}
@@ -227,6 +228,25 @@ namespace builtin_scene
227228
return texture_;
228229
}
229230

231+
glm::vec2 WebContent::measureText(const std::string &text, float max_width) const
232+
{
233+
auto paragraph_style = paragraphStyle();
234+
auto paragraph_builder = skia::textlayout::ParagraphBuilder::make(
235+
paragraph_style, TrClientContextPerProcess::Get()->getFontCacheManager());
236+
paragraph_builder->pushStyle(paragraph_style.getTextStyle());
237+
paragraph_builder->addText(text.c_str(), text.size());
238+
paragraph_builder->pop();
239+
240+
auto paragraph = paragraph_builder->Build();
241+
paragraph->layout(max_width > 0
242+
? max_width + 1.0f // Add a small margin to avoid rounding issues
243+
: numeric_limits<float>::infinity());
244+
245+
// Use longest line width and height as the constraint space.
246+
return glm::vec2(paragraph->getLongestLine() / device_pixel_ratio_,
247+
paragraph->getHeight() / device_pixel_ratio_);
248+
}
249+
230250
skia::textlayout::TextStyle WebContent::textStyle() const
231251
{
232252
const WebContentTextStyle &sourceTextStyle = content_style_.textStyle;

src/client/builtin_scene/web_content.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,15 @@ namespace builtin_scene
261261
*/
262262
std::shared_ptr<Texture> resizeOrInitTexture(TextureAtlas &textureAtlas);
263263

264+
/**
265+
* Measure the size of the given text with current text style.
266+
*
267+
* @param text The text to measure.
268+
* @param max_width The maximum width of the text, if the text exceeds the width, it will be wrapped.
269+
* @returns The size of the text in logical pixels.
270+
*/
271+
glm::vec2 measureText(const std::string &text, float max_width) const;
272+
264273
inline void setEnabled(bool enabled)
265274
{
266275
enabled_ = enabled;

src/client/cssom/computed_style.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,8 @@ namespace client_cssom
555555
text_align_ = Parse::ParseSingleValue<values::computed::TextAlign>(resolvedValue);
556556
else if (name == "direction")
557557
text_direction_ = Parse::ParseSingleValue<values::computed::Direction>(resolvedValue);
558+
else if (name == "vertical-align")
559+
vertical_align_ = Parse::ParseSingleValue<values::computed::VerticalAlign>(resolvedValue);
558560

559561
// Color properties
560562
else if (name == "color")

src/client/cssom/computed_style.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,10 @@ namespace client_cssom
377377
{
378378
return text_direction_;
379379
}
380+
inline const values::computed::VerticalAlign &verticalAlign() const
381+
{
382+
return vertical_align_;
383+
}
380384

381385
inline const values::computed::Color &color() const
382386
{
@@ -571,6 +575,7 @@ namespace client_cssom
571575
// Text
572576
values::computed::TextAlign text_align_;
573577
values::computed::Direction text_direction_;
578+
values::computed::VerticalAlign vertical_align_;
574579

575580
// Colors
576581
values::computed::Color color_ = values::computed::Color::Black();

src/client/cssom/units.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace client_cssom
1010
constexpr const int PPI = 92;
1111

1212
// The device pixel ratio.
13-
constexpr const float DevicePixelRatio = 2.0f;
13+
constexpr const float DevicePixelRatio = 1.0f;
1414

1515
// The screen width and height.
1616
constexpr const int ScreenWidth = 1920;

src/client/cssom/values/computed/text.hpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,42 @@ namespace client_cssom::values::computed
7575
: skia::textlayout::TextDirection::kRtl;
7676
}
7777
};
78+
79+
class VerticalAlign : public specified::VerticalAlign
80+
{
81+
using specified::VerticalAlign::VerticalAlign;
82+
83+
public:
84+
VerticalAlign(const specified::VerticalAlign &other)
85+
: specified::VerticalAlign(other)
86+
{
87+
}
88+
89+
// Check if this is a baseline alignment
90+
bool isBaseline() const
91+
{
92+
return tag() == Tag::kBaseline;
93+
}
94+
95+
// Check if this is a keyword alignment (not length/percentage)
96+
bool isKeyword() const
97+
{
98+
return tag() != Tag::kLength && tag() != Tag::kPercentage;
99+
}
100+
101+
// Get the offset in pixels for length/percentage values
102+
// For percentage, lineHeight should be provided
103+
float getOffset(float lineHeight = 0.0f) const
104+
{
105+
switch (tag())
106+
{
107+
case Tag::kLength:
108+
return value();
109+
case Tag::kPercentage:
110+
return (value() / 100.0f) * lineHeight;
111+
default:
112+
return 0.0f; // Keywords don't have numeric offsets
113+
}
114+
}
115+
};
78116
}

src/client/cssom/values/specified/text.hpp

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#pragma once
22

33
#include <cstdint>
4+
#include <string>
5+
#include <stdexcept>
6+
#include <cassert>
47
#include <client/cssom/style_traits.hpp>
58

69
namespace client_cssom::values::specified
@@ -159,4 +162,178 @@ namespace client_cssom::values::specified
159162
protected:
160163
Tag tag_ = Tag::kLTR;
161164
};
165+
166+
class VerticalAlign : public Parse,
167+
public ToCss
168+
{
169+
friend class Parse;
170+
171+
public:
172+
enum Tag : uint8_t
173+
{
174+
kBaseline,
175+
kSub,
176+
kSuper,
177+
kTop,
178+
kTextTop,
179+
kMiddle,
180+
kBottom,
181+
kTextBottom,
182+
kLength, // Custom length value
183+
kPercentage, // Percentage value
184+
};
185+
186+
public:
187+
static VerticalAlign Baseline()
188+
{
189+
return VerticalAlign(Tag::kBaseline);
190+
}
191+
static VerticalAlign Sub()
192+
{
193+
return VerticalAlign(Tag::kSub);
194+
}
195+
static VerticalAlign Super()
196+
{
197+
return VerticalAlign(Tag::kSuper);
198+
}
199+
static VerticalAlign Top()
200+
{
201+
return VerticalAlign(Tag::kTop);
202+
}
203+
static VerticalAlign TextTop()
204+
{
205+
return VerticalAlign(Tag::kTextTop);
206+
}
207+
static VerticalAlign Middle()
208+
{
209+
return VerticalAlign(Tag::kMiddle);
210+
}
211+
static VerticalAlign Bottom()
212+
{
213+
return VerticalAlign(Tag::kBottom);
214+
}
215+
static VerticalAlign TextBottom()
216+
{
217+
return VerticalAlign(Tag::kTextBottom);
218+
}
219+
static VerticalAlign Length(float value)
220+
{
221+
return VerticalAlign(Tag::kLength, value);
222+
}
223+
static VerticalAlign Percentage(float value)
224+
{
225+
return VerticalAlign(Tag::kPercentage, value);
226+
}
227+
228+
public:
229+
VerticalAlign()
230+
: tag_(Tag::kBaseline)
231+
, value_(0.0f)
232+
{
233+
}
234+
235+
protected:
236+
VerticalAlign(Tag tag, float value = 0.0f)
237+
: tag_(tag)
238+
, value_(value)
239+
{
240+
}
241+
242+
public:
243+
Tag tag() const
244+
{
245+
return tag_;
246+
}
247+
float value() const
248+
{
249+
return value_;
250+
}
251+
std::string toCss() const override
252+
{
253+
switch (tag_)
254+
{
255+
case Tag::kBaseline:
256+
return "baseline";
257+
case Tag::kSub:
258+
return "sub";
259+
case Tag::kSuper:
260+
return "super";
261+
case Tag::kTop:
262+
return "top";
263+
case Tag::kTextTop:
264+
return "text-top";
265+
case Tag::kMiddle:
266+
return "middle";
267+
case Tag::kBottom:
268+
return "bottom";
269+
case Tag::kTextBottom:
270+
return "text-bottom";
271+
case Tag::kLength:
272+
return std::to_string(value_) + "px";
273+
case Tag::kPercentage:
274+
return std::to_string(value_) + "%";
275+
}
276+
assert(false && "Invalid tag.");
277+
}
278+
279+
private:
280+
bool parse(const std::string &input) override
281+
{
282+
if (input == "baseline")
283+
tag_ = Tag::kBaseline;
284+
else if (input == "sub")
285+
tag_ = Tag::kSub;
286+
else if (input == "super")
287+
tag_ = Tag::kSuper;
288+
else if (input == "top")
289+
tag_ = Tag::kTop;
290+
else if (input == "text-top")
291+
tag_ = Tag::kTextTop;
292+
else if (input == "middle")
293+
tag_ = Tag::kMiddle;
294+
else if (input == "bottom")
295+
tag_ = Tag::kBottom;
296+
else if (input == "text-bottom")
297+
tag_ = Tag::kTextBottom;
298+
else
299+
{
300+
// Try to parse as length or percentage
301+
if (input.back() == '%')
302+
{
303+
try
304+
{
305+
float percentage = std::stof(input.substr(0, input.size() - 1));
306+
tag_ = Tag::kPercentage;
307+
value_ = percentage;
308+
}
309+
catch (const std::exception &)
310+
{
311+
return false;
312+
}
313+
}
314+
else if (input.find("px") != std::string::npos)
315+
{
316+
try
317+
{
318+
float length = std::stof(input.substr(0, input.size() - 2));
319+
tag_ = Tag::kLength;
320+
value_ = length;
321+
}
322+
catch (const std::exception &)
323+
{
324+
return false;
325+
}
326+
}
327+
else
328+
{
329+
return false;
330+
}
331+
}
332+
return true;
333+
}
334+
335+
protected:
336+
Tag tag_ = Tag::kBaseline;
337+
float value_ = 0.0f;
338+
};
162339
}

src/client/layout/layout_text.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,8 @@ namespace client_layout
7474
if (textContent.size() == 0)
7575
return ConstraintSpace::Zero();
7676

77-
auto paragraphStyle = webContentComponent->paragraphStyle();
78-
auto paragraphBuilder = ParagraphBuilder::make(paragraphStyle,
79-
TrClientContextPerProcess::Get()->getFontCacheManager());
80-
paragraphBuilder->pushStyle(paragraphStyle.getTextStyle());
81-
paragraphBuilder->addText(textContent.c_str(), textContent.size());
82-
paragraphBuilder->pop();
83-
84-
auto paragraph = paragraphBuilder->Build();
85-
paragraph->layout(maxWidth > 0
86-
? maxWidth + 1.0f // Add a small margin to avoid rounding issues
87-
: numeric_limits<float>::infinity());
88-
89-
// Use longest line width and height as the constraint space.
90-
return ConstraintSpace(paragraph->getLongestLine(),
91-
paragraph->getHeight());
77+
auto size = webContentComponent->measureText(textContent, maxWidth);
78+
return ConstraintSpace(size.x, size.y);
9279
}
9380

9481
void LayoutText::textDidChange()

0 commit comments

Comments
 (0)