TCFresnelCSS.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. {
  2. *****************************************************************************
  3. This file is part of Fresnel.
  4. See the file COPYING.modifiedLGPL.txt, included in this distribution,
  5. for details about the license.
  6. *****************************************************************************
  7. Examples:
  8. ./testfresnelbase --suite=TTestFresnelCSS.TestEmptyViewport
  9. }
  10. unit TCFresnelCSS;
  11. {$mode ObjFPC}{$H+}
  12. interface
  13. uses
  14. Classes, SysUtils, Math, fpcunit, testregistry, FpImage, Fresnel.DOM,
  15. Fresnel.Renderer, Fresnel.Layouter, Fresnel.Classes, Fresnel.Controls,
  16. Avl_Tree, UTF8Utils;
  17. type
  18. { TTestFont }
  19. TTestFont = class(TInterfacedObject,IFresnelFont)
  20. public
  21. Desc: TFresnelFontDesc;
  22. function GetDescription: String;
  23. function GetFamily: string;
  24. function GetKerning: string;
  25. function GetSize: double;
  26. function GetStyle: string;
  27. function GetVariant: string;
  28. function GetWeight: double;
  29. function TextSize(const aText: string): TFresnelPoint;
  30. function TextSizeMaxWidth(const aText: string; MaxWidth: TFresnelLength): TFresnelPoint;
  31. function GetTool: TObject;
  32. end;
  33. { TTestFontEngine }
  34. TTestFontEngine = class(TFresnelFontEngine)
  35. private
  36. FFonts: TAVLTree; // tree of TTestFont sorted with CompareTestFont
  37. protected
  38. public
  39. constructor Create(AOwner: TComponent); override;
  40. destructor Destroy; override;
  41. function FindFont(const Desc: TFresnelFontDesc): TTestFont; virtual;
  42. function Allocate(const Desc: TFresnelFontDesc): IFresnelFont; override;
  43. end;
  44. { TTestRenderer }
  45. TTestRenderer = class(TFresnelRenderer)
  46. public
  47. procedure Arc(const aColor: TFPColor; const aCenter, aRadii: TFresnelPoint;
  48. aStartAngle: TFresnelLength=0; aStopAngle: TFresnelLength=DoublePi); override;
  49. procedure FillRect(const aColor: TFPColor; const aRect: TFresnelRect); override;
  50. procedure Line(const aColor: TFPColor; const x1, y1, x2, y2: TFresnelLength); override;
  51. procedure RoundRect(const aColor: TFPColor; const aRect: TFresnelRoundRect; Fill: Boolean);
  52. override;
  53. procedure TextOut(const aLeft, aTop: TFresnelLength;
  54. const aFont: IFresnelFont; const aColor: TFPColor;
  55. const aText: string); override;
  56. procedure DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength; const aImage: TFPCustomImage); override;
  57. constructor Create(AOwner: TComponent); override;
  58. end;
  59. { TTestViewport }
  60. TTestViewport = class(TFresnelViewport)
  61. private
  62. FLayoutQueued: boolean;
  63. FRenderer: TFresnelRenderer;
  64. protected
  65. procedure SetWidth(AValue: TFresnelLength); override;
  66. procedure SetHeight(AValue: TFresnelLength); override;
  67. public
  68. constructor Create(AOwner: TComponent); override;
  69. destructor Destroy; override;
  70. procedure DomChanged; override;
  71. procedure Draw; virtual;
  72. property LayoutQueued: boolean read FLayoutQueued write FLayoutQueued;
  73. property Renderer: TFresnelRenderer read FRenderer write FRenderer;
  74. end;
  75. { TCustomTestFresnelCSS }
  76. TCustomTestFresnelCSS = Class(TTestCase)
  77. protected
  78. procedure SetUp; override;
  79. procedure TearDown; override;
  80. public
  81. Viewport: TTestViewport;
  82. end;
  83. { TTestFresnelCSS }
  84. TTestFresnelCSS = class(TCustomTestFresnelCSS)
  85. published
  86. procedure TestEmptyViewport;
  87. procedure TestBody;
  88. procedure TestGetStyleAttr_OneValue;
  89. procedure TestGetStyleAttr_TwoValues;
  90. procedure TestGetStyleAttr_OneFunction;
  91. procedure TestGetStyleAttr_TwoFunctions;
  92. procedure TestGetStyleAttr_NestedFunctions;
  93. procedure TestSetStyleAttr_NewValueEmpty;
  94. procedure TestSetStyleAttr_NewValueFirst;
  95. procedure TestSetStyleAttr_NewValueAppend;
  96. procedure TestSetStyleAttr_NewValueAppendSemicolon;
  97. procedure TestSetStyleAttr_DeleteOnlyValue;
  98. procedure TestSetStyleAttr_DeleteFirstValue;
  99. procedure TestSetStyleAttr_DeleteLastValue;
  100. procedure TestSetStyleAttr_DeleteMiddleValue;
  101. procedure TestSetStyleAttr_ReplaceOnlyValue;
  102. procedure TestSetStyleAttr_ReplaceFirstValue;
  103. procedure TestSetStyleAttr_ReplaceLastValue;
  104. procedure TestSetStyleAttr_ReplaceMiddleValue;
  105. procedure TestVar_NoDefault;
  106. end;
  107. function LinesToStr(const Args: array of const): string;
  108. implementation
  109. const
  110. // char sizes for a font size of 100
  111. CharHeight = 115;
  112. CharWidths: array[32..126] of word = (
  113. 278, // space
  114. 278, // !
  115. 355, // "
  116. 556, // #
  117. 556, // $
  118. 889, // %
  119. 667, // &
  120. 191, // '
  121. 333, // (
  122. 333, // )
  123. 389, // *
  124. 584, // +
  125. 278, // ,
  126. 333, // -
  127. 278, // .
  128. 278, // /
  129. 556, // 0
  130. 489, // 1
  131. 556, // 2
  132. 556, // 3
  133. 556, // 4
  134. 556, // 5
  135. 556, // 6
  136. 556, // 7
  137. 556, // 8
  138. 556, // 9
  139. 278, // :
  140. 278, // ;
  141. 584, // <
  142. 584, // =
  143. 584, // >
  144. 556, // ?
  145. 1015, // @
  146. 667, // A
  147. 667, // B
  148. 722, // C
  149. 722, // D
  150. 667, // E
  151. 611, // F
  152. 778, // G
  153. 722, // H
  154. 278, // I
  155. 500, // J
  156. 667, // K
  157. 556, // L
  158. 833, // M
  159. 722, // N
  160. 778, // O
  161. 667, // P
  162. 778, // Q
  163. 722, // R
  164. 667, // S
  165. 611, // T
  166. 722, // U
  167. 667, // V
  168. 944, // W
  169. 667, // X
  170. 667, // Y
  171. 611, // Z
  172. 278, // [
  173. 278, // \
  174. 278, // ]
  175. 469, // ^
  176. 556, // _
  177. 333, // `
  178. 556, // a
  179. 556, // b
  180. 500, // c
  181. 556, // d
  182. 556, // e
  183. 262, // f
  184. 556, // g
  185. 556, // h
  186. 222, // i
  187. 222, // j
  188. 500, // k
  189. 222, // l
  190. 833, // m
  191. 556, // n
  192. 556, // o
  193. 556, // p
  194. 556, // q
  195. 333, // r
  196. 500, // s
  197. 278, // t
  198. 556, // u
  199. 500, // v
  200. 722, // w
  201. 500, // x
  202. 500, // y
  203. 500, // z
  204. 334, // {
  205. 260, // |
  206. 334, // }
  207. 584 // ~
  208. );
  209. function CompareTestFont(Desc1, Desc2: Pointer): integer;
  210. var
  211. A: PFresnelFontDesc absolute Desc1;
  212. B: PFresnelFontDesc absolute Desc2;
  213. begin
  214. Result:=A^.Compare(B^);
  215. end;
  216. function CompareFontDescTestFont(aDesc, aFont: Pointer): integer;
  217. var
  218. Desc: PFresnelFontDesc absolute aDesc;
  219. Font: TTestFont absolute aFont;
  220. begin
  221. Result:=Desc^.Compare(Font.Desc);
  222. end;
  223. function LinesToStr(const Args: array of const): string;
  224. var
  225. s: String;
  226. i: Integer;
  227. begin
  228. s:='';
  229. for i:=Low(Args) to High(Args) do
  230. begin
  231. case Args[i].VType of
  232. vtChar: s += Args[i].VChar+LineEnding;
  233. vtString: s += Args[i].VString^+LineEnding;
  234. vtPChar: s += Args[i].VPChar+LineEnding;
  235. vtWideChar: s += String(Args[i].VWideChar)+LineEnding;
  236. vtPWideChar: s += String(Args[i].VPWideChar)+LineEnding;
  237. vtAnsiString: s += AnsiString(Args[i].VAnsiString)+LineEnding; // FPC uses encoding CP_UTF8 for TVarRec.VAnsiString
  238. vtWidestring: s += String(WideString(Args[i].VWideString))+LineEnding;
  239. vtUnicodeString:s += String(UnicodeString(Args[i].VUnicodeString))+LineEnding;
  240. end;
  241. end;
  242. Result:=s;
  243. end;
  244. { TTestFont }
  245. function TTestFont.GetFamily: string;
  246. begin
  247. Result:=Desc.Family;
  248. end;
  249. function TTestFont.GetDescription: String;
  250. begin
  251. Result:=Desc.Family;
  252. end;
  253. function TTestFont.GetKerning: string;
  254. begin
  255. Result:=Desc.Kerning;
  256. end;
  257. function TTestFont.GetSize: Double;
  258. begin
  259. Result:=Desc.Size;
  260. end;
  261. function TTestFont.GetStyle: string;
  262. begin
  263. Result:=Desc.Style;
  264. end;
  265. function TTestFont.GetVariant: string;
  266. begin
  267. Result:=Desc.Variant_;
  268. end;
  269. function TTestFont.GetWeight: double;
  270. begin
  271. Result:=Desc.Weight;
  272. end;
  273. function TTestFont.TextSize(const aText: string): TFresnelPoint;
  274. begin
  275. Result:=TextSizeMaxWidth(aText,1000000);
  276. end;
  277. function TTestFont.TextSizeMaxWidth(const aText: string;
  278. MaxWidth: TFresnelLength): TFresnelPoint;
  279. var
  280. aSize, CurLineWidth, CurLineHeight: TFresnelLength;
  281. CodepointLen: Integer;
  282. p: PChar;
  283. CodePoint: Cardinal;
  284. procedure AddLineBreak;
  285. begin
  286. if CurLineWidth>Result.X then
  287. Result.X:=CurLineWidth;
  288. CurLineWidth:=0;
  289. Result.Y:=Result.Y+CurLineHeight;
  290. end;
  291. procedure AddChar(CharWidth: TFresnelLength);
  292. begin
  293. if (CurLineWidth>0) and (CurLineWidth+CharWidth>MaxWidth) then
  294. AddLineBreak;
  295. CurLineWidth:=CurLineWidth+CharWidth;
  296. end;
  297. begin
  298. aSize:=Desc.Size;
  299. if aSize<0 then
  300. raise EFresnelFont.CreateFmt('font size negative "%g"',[Desc.Size]);
  301. Result.X:=0;
  302. Result.Y:=0;
  303. if (aText='') or (SameValue(aSize,0)) then
  304. exit;
  305. CurLineHeight:=aSize*CharHeight/100;
  306. Result.Y:=CurLineHeight;
  307. p:=PChar(aText);
  308. CurLineWidth:=0;
  309. CodepointLen:=0;
  310. while p^<>#0 do
  311. begin
  312. CodePoint:=ord(p^);
  313. case CodePoint of
  314. 0: break;
  315. 10,13:
  316. begin
  317. AddLineBreak;
  318. if (p[1] in [#10,#13]) and (CodePoint<>ord(p[1])) then
  319. inc(p,2)
  320. else
  321. inc(p);
  322. end;
  323. 32..126:
  324. begin
  325. AddChar(aSize*CharWidths[CodePoint]/100);
  326. inc(p);
  327. end
  328. else
  329. {$IFNDEF CPUWASM}
  330. CodePoint:=UTF8CodepointToUnicode(p,CodepointLen);
  331. {$ELSE}
  332. CodePoint:=0;
  333. {$ENDIF}
  334. AddChar(aSize*CharWidths[65]/100);
  335. inc(p,CodepointLen);
  336. end;
  337. end;
  338. if CurLineWidth>Result.X then
  339. Result.X:=CurLineWidth;
  340. end;
  341. function TTestFont.GetTool: TObject;
  342. begin
  343. Result:=Self;
  344. end;
  345. { TTestFontEngine }
  346. constructor TTestFontEngine.Create(AOwner: TComponent);
  347. begin
  348. inherited Create(AOwner);
  349. FFonts:=TAVLTree.Create(@CompareTestFont);
  350. end;
  351. destructor TTestFontEngine.Destroy;
  352. begin
  353. FFonts.FreeAndClear;
  354. FreeAndNil(FFonts);
  355. inherited Destroy;
  356. end;
  357. function TTestFontEngine.FindFont(const Desc: TFresnelFontDesc): TTestFont;
  358. var
  359. Node: TAVLTreeNode;
  360. begin
  361. Node:=FFonts.FindKey(@Desc,@CompareFontDescTestFont);
  362. if Node=nil then
  363. Result:=nil
  364. else
  365. Result:=TTestFont(Node.Data);
  366. end;
  367. function TTestFontEngine.Allocate(const Desc: TFresnelFontDesc): IFresnelFont;
  368. var
  369. aFont: TTestFont;
  370. begin
  371. aFont:=FindFont(Desc);
  372. if aFont=nil then
  373. begin
  374. aFont:=TTestFont.Create;
  375. aFont.Desc:=Desc;
  376. FFonts.Add(aFont);
  377. end;
  378. Result:=aFont;
  379. end;
  380. { TTestRenderer }
  381. procedure TTestRenderer.Arc(const aColor: TFPColor; const aCenter, aRadii: TFresnelPoint;
  382. aStartAngle: TFresnelLength; aStopAngle: TFresnelLength);
  383. begin
  384. if aColor=colBlack then;
  385. if aCenter.X=0 then ;
  386. if aRadii.X=0 then;
  387. if aStartAngle=0 then;
  388. if aStopAngle=0 then;
  389. end;
  390. procedure TTestRenderer.FillRect(const aColor: TFPColor;
  391. const aRect: TFresnelRect);
  392. begin
  393. if aColor=colBlack then ;
  394. if aRect.IsEmpty then ;
  395. end;
  396. procedure TTestRenderer.Line(const aColor: TFPColor; const x1, y1, x2,
  397. y2: TFresnelLength);
  398. begin
  399. if aColor=colBlack then ;
  400. if x1+y1+x2+y2=0 then ;
  401. end;
  402. procedure TTestRenderer.RoundRect(const aColor: TFPColor; const aRect: TFresnelRoundRect;
  403. Fill: Boolean);
  404. begin
  405. if aColor=colBlack then;
  406. if aRect.Box.Left=0 then;
  407. if Fill then;
  408. end;
  409. procedure TTestRenderer.TextOut(const aLeft, aTop: TFresnelLength;
  410. const aFont: IFresnelFont; const aColor: TFPColor; const aText: string);
  411. begin
  412. if aLeft=aTop then ;
  413. if aFont=nil then ;
  414. if aColor=colBlack then ;
  415. if aText='' then ;
  416. end;
  417. procedure TTestRenderer.DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength; const aImage: TFPCustomImage);
  418. begin
  419. if (aLeft=aTop) then ;
  420. if (aWidth=aHeight) then ;
  421. if (aImage=nil) then ;
  422. end;
  423. constructor TTestRenderer.Create(AOwner: TComponent);
  424. begin
  425. inherited Create(AOwner);
  426. end;
  427. { TTestViewport }
  428. procedure TTestViewport.SetWidth(AValue: TFresnelLength);
  429. begin
  430. inherited SetWidth(AValue);
  431. LayoutQueued:=true;
  432. end;
  433. procedure TTestViewport.SetHeight(AValue: TFresnelLength);
  434. begin
  435. inherited SetHeight(AValue);
  436. LayoutQueued:=true;
  437. end;
  438. constructor TTestViewport.Create(AOwner: TComponent);
  439. begin
  440. inherited Create(AOwner);
  441. Layouter:=TViewportLayouter.Create(nil);
  442. TViewportLayouter(Layouter).Viewport:=Self;
  443. Renderer:=TTestRenderer.Create(Self);
  444. end;
  445. destructor TTestViewport.Destroy;
  446. begin
  447. FreeAndNil(FRenderer);
  448. Layouter.Free;
  449. Layouter:=nil;
  450. inherited Destroy;
  451. end;
  452. procedure TTestViewport.DomChanged;
  453. begin
  454. LayoutQueued:=true;
  455. inherited DomChanged;
  456. end;
  457. procedure TTestViewport.Draw;
  458. begin
  459. //debugln(['TTestViewport.WSDraw ',DbgSName(Self),' ',DbgSName(Renderer)]);
  460. if LayoutQueued then
  461. begin
  462. LayoutQueued:=false;
  463. ApplyCSS;
  464. //Layouter.WriteLayoutTree;
  465. Layouter.Apply(Self);
  466. end;
  467. Renderer.Draw(Self);
  468. end;
  469. { TCustomTestFresnelCSS }
  470. procedure TCustomTestFresnelCSS.SetUp;
  471. begin
  472. inherited SetUp;
  473. Viewport:=TTestViewport.Create(nil);
  474. end;
  475. procedure TCustomTestFresnelCSS.TearDown;
  476. begin
  477. FreeAndNil(Viewport);
  478. inherited TearDown;
  479. end;
  480. { TTestFresnelCSS }
  481. procedure TTestFresnelCSS.TestEmptyViewport;
  482. begin
  483. Viewport.Draw;
  484. end;
  485. procedure TTestFresnelCSS.TestBody;
  486. var
  487. Body: TBody;
  488. begin
  489. Body:=TBody.Create(Viewport);
  490. Body.Name:='Body';
  491. Body.Parent:=Viewport;
  492. Viewport.Draw;
  493. Body.WriteComputedAttributes('Body');
  494. end;
  495. procedure TTestFresnelCSS.TestGetStyleAttr_OneValue;
  496. begin
  497. if Viewport.Style<>'' then
  498. Fail('20240820190117');
  499. Viewport.Style:='padding:3px';
  500. AssertEquals('padding:3px',Viewport.Style);
  501. AssertEquals('3px',Viewport.GetStyleAttr('padding'));
  502. end;
  503. procedure TTestFresnelCSS.TestGetStyleAttr_TwoValues;
  504. begin
  505. Viewport.Style:='padding-left:3px; padding-top: 4px';
  506. AssertEquals('3px',Viewport.GetStyleAttr('padding-left'));
  507. AssertEquals('4px',Viewport.GetStyleAttr('padding-top'));
  508. end;
  509. procedure TTestFresnelCSS.TestGetStyleAttr_OneFunction;
  510. begin
  511. Viewport.Style:='padding-left:var(--bird)';
  512. AssertEquals('var(--bird)',Viewport.GetStyleAttr('padding-left'));
  513. end;
  514. procedure TTestFresnelCSS.TestGetStyleAttr_TwoFunctions;
  515. begin
  516. Viewport.Style:='padding-left:var(--bird); padding-right: min(10px, 20%) ';
  517. AssertEquals('var(--bird)',Viewport.GetStyleAttr('padding-left'));
  518. AssertEquals('min(10px, 20%)',Viewport.GetStyleAttr('padding-right'));
  519. end;
  520. procedure TTestFresnelCSS.TestGetStyleAttr_NestedFunctions;
  521. begin
  522. Viewport.Style:='padding-left: calc(var(--bird)*10%) ; padding-right: min(max(10%,3em), 20%) min(3px,5ch)';
  523. AssertEquals('calc(var(--bird)*10%)',Viewport.GetStyleAttr('padding-left'));
  524. AssertEquals('min(max(10%,3em), 20%) min(3px,5ch)',Viewport.GetStyleAttr('padding-right'));
  525. end;
  526. procedure TTestFresnelCSS.TestSetStyleAttr_NewValueEmpty;
  527. begin
  528. if not Viewport.SetStyleAttr('padding-left','') then
  529. Fail('20240820193346');
  530. AssertEquals('',Viewport.Style);
  531. end;
  532. procedure TTestFresnelCSS.TestSetStyleAttr_NewValueFirst;
  533. begin
  534. if not Viewport.SetStyleAttr('padding-left','3px') then
  535. Fail('20240820193354');
  536. AssertEquals('padding-left:3px',Viewport.Style);
  537. end;
  538. procedure TTestFresnelCSS.TestSetStyleAttr_NewValueAppend;
  539. begin
  540. Viewport.Style:='padding-left:4px';
  541. if not Viewport.SetStyleAttr('padding-right','7px') then
  542. Fail('20240820193401');
  543. AssertEquals('padding-left:4px; padding-right:7px',Viewport.Style);
  544. end;
  545. procedure TTestFresnelCSS.TestSetStyleAttr_NewValueAppendSemicolon;
  546. begin
  547. Viewport.Style:='padding-left:4px ;';
  548. if not Viewport.SetStyleAttr('padding-right','7px') then
  549. Fail('20240820194710');
  550. AssertEquals('padding-left:4px ; padding-right:7px',Viewport.Style);
  551. end;
  552. procedure TTestFresnelCSS.TestSetStyleAttr_DeleteOnlyValue;
  553. begin
  554. Viewport.Style:='padding-left:4px';
  555. if not Viewport.SetStyleAttr('padding-left','') then
  556. Fail('20240820193844');
  557. AssertEquals('',Viewport.Style);
  558. end;
  559. procedure TTestFresnelCSS.TestSetStyleAttr_DeleteFirstValue;
  560. begin
  561. Viewport.Style:='padding-left:4px; padding-top:3px';
  562. if not Viewport.SetStyleAttr('padding-left','') then
  563. Fail('20240820193847');
  564. AssertEquals('padding-top:3px',Viewport.Style);
  565. end;
  566. procedure TTestFresnelCSS.TestSetStyleAttr_DeleteLastValue;
  567. begin
  568. Viewport.Style:='padding-left:4px ; padding-top:3px';
  569. if not Viewport.SetStyleAttr('padding-top','') then
  570. Fail('20240820194509');
  571. AssertEquals('padding-left:4px ;',Viewport.Style);
  572. end;
  573. procedure TTestFresnelCSS.TestSetStyleAttr_DeleteMiddleValue;
  574. begin
  575. Viewport.Style:='padding-left:4px ; padding-top:3px; padding-right: 2px';
  576. if not Viewport.SetStyleAttr('padding-top','') then
  577. Fail('20240820195100');
  578. AssertEquals('padding-left:4px ;padding-right: 2px',Viewport.Style);
  579. end;
  580. procedure TTestFresnelCSS.TestSetStyleAttr_ReplaceOnlyValue;
  581. begin
  582. Viewport.Style:='padding-left: 4px;';
  583. if not Viewport.SetStyleAttr('padding-left','5em') then
  584. Fail('20240820195245');
  585. AssertEquals('padding-left:5em;',Viewport.Style);
  586. end;
  587. procedure TTestFresnelCSS.TestSetStyleAttr_ReplaceFirstValue;
  588. begin
  589. Viewport.Style:='padding-left: 4px ; padding-top:3px';
  590. if not Viewport.SetStyleAttr('padding-left','7em') then
  591. Fail('20240820195924');
  592. AssertEquals('padding-left:7em; padding-top:3px',Viewport.Style);
  593. end;
  594. procedure TTestFresnelCSS.TestSetStyleAttr_ReplaceLastValue;
  595. begin
  596. Viewport.Style:='padding-left: 4px ; padding-top: 3px ';
  597. if not Viewport.SetStyleAttr('padding-top','7em') then
  598. Fail('20240820200021');
  599. AssertEquals('padding-left: 4px ; padding-top:7em',Viewport.Style);
  600. end;
  601. procedure TTestFresnelCSS.TestSetStyleAttr_ReplaceMiddleValue;
  602. begin
  603. Viewport.Style:='padding-left:4px ; padding-top: 3px ; padding-right: 2px';
  604. if not Viewport.SetStyleAttr('padding-top','7em') then
  605. Fail('20240820200135');
  606. AssertEquals('padding-left:4px ; padding-top:7em; padding-right: 2px',Viewport.Style);
  607. end;
  608. procedure TTestFresnelCSS.TestVar_NoDefault;
  609. var
  610. Body: TBody;
  611. begin
  612. Viewport.Stylesheet.Text:=LinesToStr([
  613. ':root {',
  614. '--bird-color:red;',
  615. '}',
  616. 'body {',
  617. 'color:var(--bird-color);',
  618. '}']);
  619. Body:=TBody.Create(Viewport);
  620. Body.Name:='Body';
  621. Body.Parent:=Viewport;
  622. Viewport.ApplyCSS;
  623. AssertEquals('red',Viewport.GetComputedCSSString('--bird-color'));
  624. AssertEquals('red',Body.GetComputedCSSString('--bird-color'));
  625. AssertEquals('red',Body.GetComputedCSSString('color'));
  626. end;
  627. Initialization
  628. RegisterTests([TTestFresnelCSS]);
  629. end.