Skip to content

Commit 86c4af7

Browse files
authored
feat(layout): implement text-align propagation from ComputedStyle to LayoutStyle and taffy (#333)
1 parent 2bc5661 commit 86c4af7

7 files changed

Lines changed: 272 additions & 31 deletions

File tree

crates/jsbindings/bindings.layout.hpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,14 @@ namespace crates::layout2
206206
XX(Wrap, "wrap") \
207207
XX(WrapReverse, "wrap-reverse")
208208

209+
#define TEXT_ALIGN_MAP(XX) \
210+
XX(Start, "start") \
211+
XX(End, "end") \
212+
XX(Left, "left") \
213+
XX(Right, "right") \
214+
XX(Center, "center") \
215+
XX(Justify, "justify")
216+
209217
class Display : public CSSKeyword<holocron::layout::Display,
210218
holocron::layout::Display::Block>
211219
{
@@ -531,6 +539,70 @@ namespace crates::layout2
531539
}
532540
};
533541

542+
class TextAlign : public CSSKeyword<holocron::layout::TextAlign,
543+
holocron::layout::TextAlign::Start>
544+
{
545+
using CSSKeyword::CSSKeyword;
546+
547+
public:
548+
static TextAlign Start()
549+
{
550+
return TextAlign(holocron::layout::TextAlign::Start);
551+
}
552+
static TextAlign End()
553+
{
554+
return TextAlign(holocron::layout::TextAlign::End);
555+
}
556+
static TextAlign Left()
557+
{
558+
return TextAlign(holocron::layout::TextAlign::Left);
559+
}
560+
static TextAlign Right()
561+
{
562+
return TextAlign(holocron::layout::TextAlign::Right);
563+
}
564+
static TextAlign Center()
565+
{
566+
return TextAlign(holocron::layout::TextAlign::Center);
567+
}
568+
static TextAlign Justify()
569+
{
570+
return TextAlign(holocron::layout::TextAlign::Justify);
571+
}
572+
573+
public:
574+
TextAlign(const std::string &input)
575+
{
576+
handle_ = parse(input).value_or(holocron::layout::TextAlign::Start);
577+
}
578+
579+
private:
580+
std::optional<holocron::layout::TextAlign> parse(const std::string &input) override
581+
{
582+
#define XX(tag, str) \
583+
if (input == str) \
584+
return holocron::layout::TextAlign::tag;
585+
TEXT_ALIGN_MAP(XX)
586+
#undef XX
587+
return std::nullopt;
588+
}
589+
590+
public:
591+
friend std::ostream &operator<<(std::ostream &os, const TextAlign &value)
592+
{
593+
switch (value.handle_)
594+
{
595+
#define XX(tag, str) \
596+
case holocron::layout::TextAlign::tag: \
597+
os << str; \
598+
break;
599+
TEXT_ALIGN_MAP(XX)
600+
#undef XX
601+
}
602+
return os;
603+
}
604+
};
605+
534606
template <typename T, typename I, I defaultValue = I::Normal>
535607
class BoxAlignmentProperty : public CSSKeyword<I, defaultValue>
536608
{
@@ -943,6 +1015,7 @@ namespace crates::layout2
9431015
#undef CONTENT_SPACING_MAP
9441016
#undef FLEX_DIRECTION_MAP
9451017
#undef FLEX_WRAP_MAP
1018+
#undef TEXT_ALIGN_MAP
9461019
}
9471020

9481021
class LayoutStyle
@@ -1036,6 +1109,8 @@ namespace crates::layout2
10361109
"auto", // grid-row-end
10371110
"auto", // grid-column-start
10381111
"auto", // grid-column-end
1112+
// text properties
1113+
styles::TextAlign::Start(),
10391114
})
10401115
{
10411116
}
@@ -1392,6 +1467,16 @@ namespace crates::layout2
13921467
style_.gridColumnEnd = value;
13931468
}
13941469

1470+
// Text properties
1471+
styles::TextAlign textAlign() const
1472+
{
1473+
return style_.textAlign;
1474+
}
1475+
void setTextAlign(styles::TextAlign value)
1476+
{
1477+
style_.textAlign = value;
1478+
}
1479+
13951480
public:
13961481
friend std::ostream &operator<<(std::ostream &os, const LayoutStyle &style)
13971482
{
@@ -1433,6 +1518,7 @@ namespace crates::layout2
14331518
<< " grid-row-end: " << std::string(style.style_.gridRowEnd) << std::endl
14341519
<< " grid-column-start: " << std::string(style.style_.gridColumnStart) << std::endl
14351520
<< " grid-column-end: " << std::string(style.style_.gridColumnEnd) << std::endl
1521+
<< " text-align: " << style.textAlign() << std::endl
14361522
<< "}";
14371523
return os;
14381524
}

crates/jsbindings/layout.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{cell::RefCell, ops::BitOr, rc::Rc};
1+
use std::{cell::RefCell, rc::Rc};
22

33
use paste::paste;
44
use style::values::{
@@ -344,6 +344,16 @@ mod ffi {
344344
SpaceAround,
345345
}
346346

347+
#[derive(Clone, Copy, Debug)]
348+
enum TextAlign {
349+
Start,
350+
End,
351+
Left,
352+
Right,
353+
Center,
354+
Justify,
355+
}
356+
347357
#[derive(Clone, Copy, Debug)]
348358
enum FlexDirection {
349359
Row,
@@ -513,6 +523,10 @@ mod ffi {
513523
pub grid_column_start: String,
514524
#[cxx_name = "gridColumnEnd"]
515525
pub grid_column_end: String,
526+
527+
// Text Properties
528+
#[cxx_name = "textAlign"]
529+
pub text_align: TextAlign,
516530
}
517531

518532
#[derive(Clone, Copy, Debug)]
@@ -922,6 +936,13 @@ impl_justify_items_like_from_taffy!(JustifyItems);
922936
impl_justify_items_like_from_taffy!(JustifySelf);
923937
impl_align_or_justify_content_from_taffy!(JustifyContent);
924938

939+
// TextAlign doesn't directly map to taffy types, so we'll provide a default
940+
impl Default for ffi::TextAlign {
941+
fn default() -> Self {
942+
ffi::TextAlign::Start
943+
}
944+
}
945+
925946
impl_default_for!(AlignItems, Normal);
926947
impl_default_for!(AlignSelf, Auto);
927948
impl_default_for!(AlignContent, Normal);
@@ -1077,6 +1098,31 @@ impl From<ffi::LengthPercentageXY> for taffy::Point<taffy::LengthPercentage> {
10771098
}
10781099
}
10791100

1101+
impl From<taffy::TextAlign> for ffi::TextAlign {
1102+
fn from(value: taffy::TextAlign) -> Self {
1103+
match value {
1104+
taffy::TextAlign::LegacyLeft => ffi::TextAlign::Left,
1105+
taffy::TextAlign::LegacyRight => ffi::TextAlign::Right,
1106+
taffy::TextAlign::LegacyCenter => ffi::TextAlign::Center,
1107+
_ => ffi::TextAlign::Start, // Default value since taffy doesn't handle text-align
1108+
}
1109+
}
1110+
}
1111+
1112+
impl From<ffi::TextAlign> for taffy::TextAlign {
1113+
fn from(value: ffi::TextAlign) -> Self {
1114+
match value {
1115+
ffi::TextAlign::Start => taffy::TextAlign::LegacyLeft,
1116+
ffi::TextAlign::End => taffy::TextAlign::LegacyRight,
1117+
ffi::TextAlign::Left => taffy::TextAlign::LegacyLeft,
1118+
ffi::TextAlign::Right => taffy::TextAlign::LegacyRight,
1119+
ffi::TextAlign::Center => taffy::TextAlign::LegacyCenter,
1120+
ffi::TextAlign::Justify => taffy::TextAlign::Auto,
1121+
_ => taffy::TextAlign::Auto,
1122+
}
1123+
}
1124+
}
1125+
10801126
impl_type_casting_simple!(FlexDirection, { Row, Column, RowReverse, ColumnReverse }, Row);
10811127
impl_type_casting_simple!(FlexWrap, { NoWrap, Wrap, WrapReverse}, NoWrap);
10821128

@@ -1096,6 +1142,8 @@ impl From<taffy::Style> for ffi::Style {
10961142
margin: style.margin.into(),
10971143
padding: style.padding.into(),
10981144
border: style.border.into(),
1145+
text_align: style.text_align.into(),
1146+
10991147
align_items: style.align_items.into(),
11001148
align_self: style.align_self.into(),
11011149
align_content: style.align_content.into(),
@@ -1320,6 +1368,8 @@ impl From<ffi::Style> for taffy::Style {
13201368
margin: value.margin.into(),
13211369
padding: value.padding.into(),
13221370
border: value.border.into(),
1371+
text_align: value.text_align.into(),
1372+
13231373
align_items: value.align_items.into(),
13241374
align_self: value.align_self.into(),
13251375
align_content: value.align_content.into(),

fixtures/html/text-rendering-test.html

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
margin: 15px 0;
5050
padding: 10px;
5151
border-left: 3px solid var(--highlight-color);
52-
background: white;
52+
background: rgb(251, 255, 14);
5353
}
5454

5555
.test-label {
@@ -714,32 +714,7 @@ <h2 class="section-title">性能测试 - Performance Test</h2>
714714
// Add interactive functionality
715715
document.addEventListener('DOMContentLoaded', function() {
716716
// Highlight sections on hover
717-
const sections = document.querySelectorAll('.section');
718-
sections.forEach(section => {
719-
section.addEventListener('mouseenter', function() {
720-
this.style.boxShadow = '0 4px 8px rgba(0,0,0,0.1)';
721-
});
722-
section.addEventListener('mouseleave', function() {
723-
this.style.boxShadow = 'none';
724-
});
725-
});
726-
727-
// Add click-to-copy functionality for test labels
728-
const testLabels = document.querySelectorAll('.test-label');
729-
testLabels.forEach(label => {
730-
label.style.cursor = 'pointer';
731-
label.title = 'Click to copy CSS property';
732-
label.addEventListener('click', function() {
733-
navigator.clipboard.writeText(this.textContent).then(() => {
734-
this.style.backgroundColor = '#4CAF50';
735-
this.style.color = 'white';
736-
setTimeout(() => {
737-
this.style.backgroundColor = '';
738-
this.style.color = '';
739-
}, 500);
740-
});
741-
});
742-
});
717+
743718
});
744719
</script>
745720
</body>

src/client/cssom/computed_style.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ namespace client_cssom
137137
LAYOUT_USE_PROPERTY_STRING("grid-column-end", GridColumnEnd)
138138
#undef LAYOUT_USE_PROPERTY_STRING
139139

140+
// Text properties
141+
layoutStyle.setTextAlign(text_align_.toLayoutValue());
142+
140143
return layoutStyle;
141144
}
142145

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

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@
22

33
#include <skia/modules/skparagraph/include/TextStyle.h>
44
#include <client/cssom/values/specified/text.hpp>
5+
#include <crates/bindings.hpp>
56

67
namespace client_cssom::values::computed
78
{
8-
class TextAlign : public client_cssom::values::specified::TextAlign
9+
class TextAlign : public specified::TextAlign
910
{
10-
using client_cssom::values::specified::TextAlign::TextAlign;
11+
using specified::TextAlign::TextAlign;
1112

1213
public:
14+
TextAlign(const specified::TextAlign &other)
15+
: specified::TextAlign(other)
16+
{
17+
}
18+
1319
operator skia::textlayout::TextAlign() const
1420
{
1521
switch (tag_)
@@ -32,6 +38,29 @@ namespace client_cssom::values::computed
3238
return skia::textlayout::TextAlign::kStart;
3339
}
3440
}
41+
42+
// Convert to layout value for layout system
43+
crates::layout2::styles::TextAlign toLayoutValue() const
44+
{
45+
switch (tag_)
46+
{
47+
case Tag::kStart:
48+
return crates::layout2::styles::TextAlign::Start();
49+
case Tag::kEnd:
50+
return crates::layout2::styles::TextAlign::End();
51+
case Tag::kLeft:
52+
return crates::layout2::styles::TextAlign::Left();
53+
case Tag::kRight:
54+
return crates::layout2::styles::TextAlign::Right();
55+
case Tag::kCenter:
56+
return crates::layout2::styles::TextAlign::Center();
57+
case Tag::kJustify:
58+
return crates::layout2::styles::TextAlign::Justify();
59+
default:
60+
// TODO(yorkie): support match-parent.
61+
return crates::layout2::styles::TextAlign::Start();
62+
}
63+
}
3564
};
3665

3766
class Direction : public client_cssom::values::specified::Direction

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ namespace client_cssom::values::specified
5858
{
5959
}
6060

61-
private:
61+
protected:
6262
TextAlign(Tag tag)
6363
: tag_(tag)
6464
{

0 commit comments

Comments
 (0)