Skip to content

Commit c730f46

Browse files
CSS Grid 7/9: Test generation infrastructure
Summary: Update gentest scripts to support CSS Grid properties. Adds grid style extraction, grid property setup, display:grid handling, and grid-aware LTR/RTL fixture support to the C++, Java, and JavaScript test emitters. Differential Revision: D93946258
1 parent e802349 commit c730f46

29 files changed

Lines changed: 958 additions & 41 deletions

gentest/gentest-cpp.js

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ CPPEmitter.prototype = Object.create(Emitter.prototype, {
125125
YGAlignSpaceAround: {value: 'YGAlignSpaceAround'},
126126
YGAlignSpaceEvenly: {value: 'YGAlignSpaceEvenly'},
127127
YGAlignBaseline: {value: 'YGAlignBaseline'},
128+
YGAlignStart: {value: 'YGAlignStart'},
129+
YGAlignEnd: {value: 'YGAlignEnd'},
128130

129131
YGDirectionInherit: {value: 'YGDirectionInherit'},
130132
YGDirectionLTR: {value: 'YGDirectionLTR'},
@@ -152,6 +154,10 @@ CPPEmitter.prototype = Object.create(Emitter.prototype, {
152154
YGJustifySpaceAround: {value: 'YGJustifySpaceAround'},
153155
YGJustifySpaceBetween: {value: 'YGJustifySpaceBetween'},
154156
YGJustifySpaceEvenly: {value: 'YGJustifySpaceEvenly'},
157+
YGJustifyStretch: {value: 'YGJustifyStretch'},
158+
YGJustifyStart: {value: 'YGJustifyStart'},
159+
YGJustifyEnd: {value: 'YGJustifyEnd'},
160+
YGJustifyAuto: {value: 'YGJustifyAuto'},
155161

156162
YGOverflowHidden: {value: 'YGOverflowHidden'},
157163
YGOverflowVisible: {value: 'YGOverflowVisible'},
@@ -179,6 +185,8 @@ CPPEmitter.prototype = Object.create(Emitter.prototype, {
179185
YGFitContent: {value: 'FitContent'},
180186
YGStretch: {value: 'Stretch'},
181187

188+
YGDisplayGrid: {value: 'YGDisplayGrid'},
189+
182190
YGNodeCalculateLayout: {
183191
value: function (node, dir, _experiments) {
184192
this.push(
@@ -363,6 +371,30 @@ CPPEmitter.prototype = Object.create(Emitter.prototype, {
363371
},
364372
},
365373

374+
YGNodeStyleSetJustifyItems: {
375+
value: function (nodeName, value) {
376+
this.push(
377+
'YGNodeStyleSetJustifyItems(' +
378+
nodeName +
379+
', ' +
380+
toValueCpp(value) +
381+
');',
382+
);
383+
},
384+
},
385+
386+
YGNodeStyleSetJustifySelf: {
387+
value: function (nodeName, value) {
388+
this.push(
389+
'YGNodeStyleSetJustifySelf(' +
390+
nodeName +
391+
', ' +
392+
toValueCpp(value) +
393+
');',
394+
);
395+
},
396+
},
397+
366398
YGNodeStyleSetMargin: {
367399
value: function (nodeName, edge, value) {
368400
let valueStr = toValueCpp(value);
@@ -509,4 +541,267 @@ CPPEmitter.prototype = Object.create(Emitter.prototype, {
509541
);
510542
},
511543
},
544+
545+
YGNodeStyleSetGridTemplateRows: {
546+
value: function (nodeName, value) {
547+
if (!value) {
548+
return;
549+
}
550+
551+
const tracks = parseGridTrackList(this, value);
552+
if (!tracks || tracks.length === 0) {
553+
return;
554+
}
555+
556+
this.push(`auto ${nodeName}_gridTemplateRows = YGGridTrackListCreate();`);
557+
558+
for (const track of tracks) {
559+
if (track.type === 'minmax') {
560+
const minVal = this.formatGridTrackValue(track.min);
561+
const maxVal = this.formatGridTrackValue(track.max);
562+
this.push(
563+
`YGGridTrackListAddTrack(${nodeName}_gridTemplateRows, YGMinMax(${minVal}, ${maxVal}));`,
564+
);
565+
} else {
566+
const val = this.formatGridTrackValue(track);
567+
this.push(
568+
`YGGridTrackListAddTrack(${nodeName}_gridTemplateRows, ${val});`,
569+
);
570+
}
571+
}
572+
573+
this.push(
574+
`YGNodeStyleSetGridTemplateRows(${nodeName}, ${nodeName}_gridTemplateRows);`,
575+
);
576+
this.push(`YGGridTrackListFree(${nodeName}_gridTemplateRows);`);
577+
},
578+
},
579+
580+
YGNodeStyleSetGridTemplateColumns: {
581+
value: function (nodeName, value) {
582+
if (!value) {
583+
return;
584+
}
585+
586+
const tracks = parseGridTrackList(this, value);
587+
if (!tracks || tracks.length === 0) {
588+
return;
589+
}
590+
591+
this.push(
592+
`auto ${nodeName}_gridTemplateColumns = YGGridTrackListCreate();`,
593+
);
594+
595+
for (const track of tracks) {
596+
if (track.type === 'minmax') {
597+
const minVal = this.formatGridTrackValue(track.min);
598+
const maxVal = this.formatGridTrackValue(track.max);
599+
this.push(
600+
`YGGridTrackListAddTrack(${nodeName}_gridTemplateColumns, YGMinMax(${minVal}, ${maxVal}));`,
601+
);
602+
} else {
603+
const val = this.formatGridTrackValue(track);
604+
this.push(
605+
`YGGridTrackListAddTrack(${nodeName}_gridTemplateColumns, ${val});`,
606+
);
607+
}
608+
}
609+
610+
this.push(
611+
`YGNodeStyleSetGridTemplateColumns(${nodeName}, ${nodeName}_gridTemplateColumns);`,
612+
);
613+
this.push(`YGGridTrackListFree(${nodeName}_gridTemplateColumns);`);
614+
},
615+
},
616+
617+
YGNodeStyleSetGridColumnStart: {
618+
value: function (nodeName, value) {
619+
this.push(`YGNodeStyleSetGridColumnStart(${nodeName}, ${value});`);
620+
},
621+
},
622+
623+
YGNodeStyleSetGridColumnStartSpan: {
624+
value: function (nodeName, value) {
625+
this.push(`YGNodeStyleSetGridColumnStartSpan(${nodeName}, ${value});`);
626+
},
627+
},
628+
629+
YGNodeStyleSetGridColumnEnd: {
630+
value: function (nodeName, value) {
631+
this.push(`YGNodeStyleSetGridColumnEnd(${nodeName}, ${value});`);
632+
},
633+
},
634+
635+
YGNodeStyleSetGridColumnEndSpan: {
636+
value: function (nodeName, value) {
637+
this.push(`YGNodeStyleSetGridColumnEndSpan(${nodeName}, ${value});`);
638+
},
639+
},
640+
641+
YGNodeStyleSetGridRowStart: {
642+
value: function (nodeName, value) {
643+
this.push(`YGNodeStyleSetGridRowStart(${nodeName}, ${value});`);
644+
},
645+
},
646+
647+
YGNodeStyleSetGridRowStartSpan: {
648+
value: function (nodeName, value) {
649+
this.push(`YGNodeStyleSetGridRowStartSpan(${nodeName}, ${value});`);
650+
},
651+
},
652+
653+
YGNodeStyleSetGridRowEnd: {
654+
value: function (nodeName, value) {
655+
this.push(`YGNodeStyleSetGridRowEnd(${nodeName}, ${value});`);
656+
},
657+
},
658+
659+
YGNodeStyleSetGridRowEndSpan: {
660+
value: function (nodeName, value) {
661+
this.push(`YGNodeStyleSetGridRowEndSpan(${nodeName}, ${value});`);
662+
},
663+
},
664+
665+
YGNodeStyleSetGridAutoColumns: {
666+
value: function (nodeName, value) {
667+
if (!value) {
668+
return;
669+
}
670+
671+
const tracks = parseGridTrackList(this, value);
672+
if (!tracks || tracks.length === 0) {
673+
return;
674+
}
675+
676+
this.push(`auto ${nodeName}_gridAutoColumns = YGGridTrackListCreate();`);
677+
678+
for (const track of tracks) {
679+
if (track.type === 'minmax') {
680+
const minVal = this.formatGridTrackValue(track.min);
681+
const maxVal = this.formatGridTrackValue(track.max);
682+
this.push(
683+
`YGGridTrackListAddTrack(${nodeName}_gridAutoColumns, YGMinMax(${minVal}, ${maxVal}));`,
684+
);
685+
} else {
686+
const val = this.formatGridTrackValue(track);
687+
this.push(
688+
`YGGridTrackListAddTrack(${nodeName}_gridAutoColumns, ${val});`,
689+
);
690+
}
691+
}
692+
693+
this.push(
694+
`YGNodeStyleSetGridAutoColumns(${nodeName}, ${nodeName}_gridAutoColumns);`,
695+
);
696+
this.push(`YGGridTrackListFree(${nodeName}_gridAutoColumns);`);
697+
},
698+
},
699+
700+
YGNodeStyleSetGridAutoRows: {
701+
value: function (nodeName, value) {
702+
if (!value) {
703+
return;
704+
}
705+
706+
const tracks = parseGridTrackList(this, value);
707+
if (!tracks || tracks.length === 0) {
708+
return;
709+
}
710+
711+
this.push(`auto ${nodeName}_gridAutoRows = YGGridTrackListCreate();`);
712+
713+
for (const track of tracks) {
714+
if (track.type === 'minmax') {
715+
const minVal = this.formatGridTrackValue(track.min);
716+
const maxVal = this.formatGridTrackValue(track.max);
717+
this.push(
718+
`YGGridTrackListAddTrack(${nodeName}_gridAutoRows, YGMinMax(${minVal}, ${maxVal}));`,
719+
);
720+
} else {
721+
const val = this.formatGridTrackValue(track);
722+
this.push(
723+
`YGGridTrackListAddTrack(${nodeName}_gridAutoRows, ${val});`,
724+
);
725+
}
726+
}
727+
728+
this.push(
729+
`YGNodeStyleSetGridAutoRows(${nodeName}, ${nodeName}_gridAutoRows);`,
730+
);
731+
this.push(`YGGridTrackListFree(${nodeName}_gridAutoRows);`);
732+
},
733+
},
734+
735+
formatGridTrackValue: {
736+
value: function (track) {
737+
switch (track.type) {
738+
case 'auto':
739+
return 'YGAuto()';
740+
case 'points':
741+
return `YGPoints(${toValueCpp(track.value)})`;
742+
case 'percent':
743+
return `YGPercent(${toValueCpp(track.value)})`;
744+
case 'fr':
745+
return `YGFr(${toValueCpp(track.value)})`;
746+
default:
747+
return 'YGAuto()';
748+
}
749+
},
750+
},
512751
});
752+
753+
function parseGridTrackList(e, value) {
754+
if (!value || value === 'none') {
755+
return null;
756+
}
757+
758+
// Parse space-separated track values
759+
// Examples: "100px 100px 100px", "100px 100% minmax(100px, 200px) auto"
760+
const tracks = [];
761+
const parts = value.trim().split(/\s+/);
762+
763+
let i = 0;
764+
while (i < parts.length) {
765+
const part = parts[i];
766+
767+
if (part.startsWith('minmax(')) {
768+
// Handle minmax function - may span multiple parts if there are spaces
769+
let minmaxStr = part;
770+
while (!minmaxStr.includes(')') && i < parts.length - 1) {
771+
i++;
772+
minmaxStr += ' ' + parts[i];
773+
}
774+
775+
// Extract min and max values from minmax(min, max)
776+
const match = minmaxStr.match(/minmax\(([^,]+),\s*([^)]+)\)/);
777+
if (match) {
778+
const min = match[1].trim();
779+
const max = match[2].trim();
780+
tracks.push({
781+
type: 'minmax',
782+
min: parseGridTrackValue(e, min),
783+
max: parseGridTrackValue(e, max),
784+
});
785+
}
786+
} else {
787+
// Simple track value
788+
tracks.push(parseGridTrackValue(e, part));
789+
}
790+
i++;
791+
}
792+
793+
return tracks;
794+
}
795+
796+
function parseGridTrackValue(e, value) {
797+
if (value === 'auto') {
798+
return {type: 'auto'};
799+
} else if (value.endsWith('px')) {
800+
return {type: 'points', value: parseFloat(value)};
801+
} else if (value.endsWith('%')) {
802+
return {type: 'percent', value: parseFloat(value)};
803+
} else if (value.endsWith('fr')) {
804+
return {type: 'fr', value: parseFloat(value)};
805+
}
806+
return {type: 'auto'};
807+
}

0 commit comments

Comments
 (0)