Przeglądaj źródła

base: text-decoration for span

mattias 1 miesiąc temu
rodzic
commit
0cbe446083
2 zmienionych plików z 178 dodań i 72 usunięć
  1. 72 14
      demo/TextDecoration/MainUnit.pas
  2. 106 58
      src/base/fresnel.renderer.pas

+ 72 - 14
demo/TextDecoration/MainUnit.pas

@@ -16,6 +16,7 @@ type
     procedure MainFormCreate(Sender: TObject);
   private
     procedure OnLineClick(Event: TAbstractEvent);
+    procedure OnRangeClick(Event: TAbstractEvent);
     procedure OnStyleClick(Event: TAbstractEvent);
     procedure OnThicknessClick(Event: TAbstractEvent);
     procedure OnThicknessPxChanged(Sender: TObject);
@@ -43,7 +44,15 @@ type
     ThicknessPxRadioButton: TDemoRadioButton;
     ThicknessPxSlider: TDemoSlider;
 
+    RangeRadiogroup: TDiv;
+    RangeLabel: TLabel;
+    RangeLabelRadioButton: TDemoRadioButton;
+    RangeSpanRadioButton: TDemoRadioButton;
+    RangeDivRadioButton: TDemoRadioButton;
+
+    El: TFresnelElement;
     TextDiv: TDiv;
+    Span1: TSpan;
     Label1, Label2, Label3, Label4, Label5: TLabel;
   end;
 
@@ -58,18 +67,25 @@ implementation
 
 procedure TMainForm.MainFormCreate(Sender: TObject);
 
-  function AddDiv(aName: string; aParent: TFresnelElement): TDiv;
+  function AddLabel(aName, aCaption: string; aParent: TFresnelElement): TLabel;
   begin
-    Result:=TDiv.Create(Self);
+    Result:=TLabel.Create(Self);
     Result.Name:=aName;
+    Result.Caption:=aCaption;
     Result.Parent:=aParent;
   end;
 
-  function AddLabel(aName, aCaption: string; aParent: TFresnelElement): TLabel;
+  function AddSpan(aName: string; aParent: TFresnelElement): TSpan;
   begin
-    Result:=TLabel.Create(Self);
+    Result:=TSpan.Create(Self);
+    Result.Name:=aName;
+    Result.Parent:=aParent;
+  end;
+
+  function AddDiv(aName: string; aParent: TFresnelElement): TDiv;
+  begin
+    Result:=TDiv.Create(Self);
     Result.Name:=aName;
-    Result.Caption:=aCaption;
     Result.Parent:=aParent;
   end;
 
@@ -101,7 +117,7 @@ procedure TMainForm.MainFormCreate(Sender: TObject);
 begin
   StyleSheet.Text:=':root { font-size: 12px; }'+LineEnding
     +'#TextDiv { font-size: 30px; }'+LineEnding
-    +'#TextDiv>label { margin-right: .5em; }';
+    +'#TextDiv label { margin-right: .5em; }';
 
   // line radiogroup
   LineRadiogroup:=AddDiv('LineRadiogroup',Self);
@@ -152,13 +168,29 @@ begin
   ThicknessPxSlider:=AddSlider('ThicknessPxSlider','',ThicknessRadiogroup,
     0,5,1,'%fpx',@OnThicknessPxChanged);
 
+  // range radiogroup
+  RangeRadiogroup:=AddDiv('RangeRadiogroup',Self);
+  RangeRadiogroup.Style:='padding: 1em;';
+
+  RangeLabel:=AddLabel('RangeLabel','Apply to',StyleRadiogroup);
+  RangeLabelRadioButton:=AddRadioButton('RangeLabelRadioButton','label',
+    RangeRadiogroup,@OnRangeClick);
+  RangeLabelRadioButton.Checked:=true;
+  RangeSpanRadioButton:=AddRadioButton('RangeSpanRadioButton','span',
+    RangeRadiogroup,@OnRangeClick);
+  RangeDivRadioButton:=AddRadioButton('RangeDivRadioButton','div',
+    RangeRadiogroup,@OnRangeClick);
+
   // div, span, label
   TextDiv:=AddDiv('TextDiv',Self);
-  TextDiv.Style:='padding: 1em;';
-  Label1:=AddLabel('Label1','Happy',TextDiv);
+  TextDiv.Style:='padding: 1em; border: 1px solid black;';
+  Span1:=AddSpan('Span1',TextDiv);
+  Span1.Style:='border: 1px solid blue;';
+  Label1:=AddLabel('Label1','Happy',Span1);
+  El:=Label1;
   Label1.SetStyleAttr('text-decoration-line','underline');
-  Label2:=AddLabel('Label2','Fresnel',TextDiv);
-  Label3:=AddLabel('Label3','day',TextDiv);
+  Label2:=AddLabel('Label2','Fresnel',Span1);
+  Label3:=AddLabel('Label3','day',Span1);
   Label4:=AddLabel('Label4','to',TextDiv);
   Label5:=AddLabel('Label5','everyone',TextDiv);
 end;
@@ -179,7 +211,33 @@ begin
     s:='spelling-error'
   else
     s:='none';
-  Label1.SetStyleAttr('text-decoration-line',s);
+  El.SetStyleAttr('text-decoration-line',s);
+end;
+
+procedure TMainForm.OnRangeClick(Event: TAbstractEvent);
+var
+  NewEl: TFresnelElement;
+  OldLine, OldStyle, OldThickness: String;
+begin
+  if Event.Sender=RangeDivRadioButton then
+    NewEl:=TextDiv
+  else if Event.Sender=RangeSpanRadioButton then
+    NewEl:=Span1
+  else
+    NewEl:=Label1;
+  if El=NewEl then exit;
+
+  OldLine:=El.GetStyleAttr('text-decoration-line');
+  El.SetStyleAttr('text-decoration-line','');
+  OldStyle:=El.GetStyleAttr('text-decoration-style');
+  El.SetStyleAttr('text-decoration-style','');
+  OldThickness:=El.GetStyleAttr('text-decoration-thickness');
+  El.SetStyleAttr('text-decoration-thickness','');
+
+  El:=NewEl;
+  El.SetStyleAttr('text-decoration-line',OldLine);
+  El.SetStyleAttr('text-decoration-style',OldStyle);
+  El.SetStyleAttr('text-decoration-thickness',OldThickness);
 end;
 
 procedure TMainForm.OnStyleClick(Event: TAbstractEvent);
@@ -196,7 +254,7 @@ begin
     s:='wavy'
   else
     s:='solid';
-  Label1.SetStyleAttr('text-decoration-style',s);
+  El.SetStyleAttr('text-decoration-style',s);
 end;
 
 procedure TMainForm.OnThicknessClick(Event: TAbstractEvent);
@@ -209,13 +267,13 @@ begin
     s:='from-font'
   else if Event.Sender=ThicknessPxRadioButton then
     s:=FloatToCSSPx(ThicknessPxSlider.SliderPosition);
-  Label1.SetStyleAttr('text-decoration-thickness',s);
+  El.SetStyleAttr('text-decoration-thickness',s);
 end;
 
 procedure TMainForm.OnThicknessPxChanged(Sender: TObject);
 begin
   if ThicknessPxRadioButton.Checked then
-    Label1.SetStyleAttr('text-decoration-thickness',FloatToCSSPx(ThicknessPxSlider.SliderPosition));
+    El.SetStyleAttr('text-decoration-thickness',FloatToCSSPx(ThicknessPxSlider.SliderPosition));
 end;
 
 end.

+ 106 - 58
src/base/fresnel.renderer.pas

@@ -993,14 +993,10 @@ var
   s: String;
   aFont: IFresnelFont;
   aComp: TCSSResCompValue;
+  i: Integer;
+  l: SizeInt;
 begin
   LNode:=TUsedLayoutNode(El.LayoutNode);
-  with Params.BoundingBox.Box do
-  begin
-    aLeft:=Left+LNode.BorderLeft+LNode.PaddingLeft;
-    aRight:=Right-LNode.BorderRight-LNode.PaddingRight;
-    aTop:=Top+LNode.BorderTop+LNode.PaddingTop;
-  end;
 
   aFont:=El.Font;
 
@@ -1046,18 +1042,65 @@ begin
         end;
       end;
       if aThickness<0.1 then exit;
-
-      DrawTextDecorationH(aLeft,aTop,aRight,aFont,LineKW,StyleKW,aColorFP,aThickness);
     end;
   CSSRegistry.kwGrammarError:
     begin
-      DrawTextDecorationH(aLeft,aTop,aRight,aFont,CSSRegistry.kwUnderline,CSSRegistry.kwWavy,colDkGreen,1);
+      LineKW:=CSSRegistry.kwUnderline;
+      StyleKW:=CSSRegistry.kwWavy;
+      aColorFP:=colDkGreen;
+      aThickness:=1;
     end;
   CSSRegistry.kwSpellingError:
     begin
-      DrawTextDecorationH(aLeft,aTop,aRight,aFont,CSSRegistry.kwUnderline,CSSRegistry.kwWavy,colRed,1);
+      LineKW:=CSSRegistry.kwUnderline;
+      StyleKW:=CSSRegistry.kwWavy;
+      aColorFP:=colRed;
+      aThickness:=1;
     end;
   end;
+
+  if Params.Fragments<>nil then
+  begin
+    // fragments
+    l:=length(Params.Fragments);
+    with Params.Fragments[0] do
+    begin
+      aLeft:=Left+LNode.BorderLeft+LNode.PaddingLeft;
+      aRight:=Right-LNode.BorderRight-LNode.PaddingRight;
+      aTop:=Top+LNode.BorderTop+LNode.PaddingTop;
+    end;
+    DrawTextDecorationH(aLeft,aTop,aRight,aFont,LineKW,StyleKW,aColorFP,aThickness);
+
+    for i:=1 to l-2 do
+    begin
+      with Params.Fragments[i] do
+      begin
+        aLeft:=Left;
+        aRight:=Right;
+        aTop:=Top+LNode.BorderTop+LNode.PaddingTop;
+      end;
+      DrawTextDecorationH(aLeft,aTop,aRight,aFont,LineKW,StyleKW,aColorFP,aThickness);
+    end;
+
+    with Params.Fragments[l-1] do
+    begin
+      aLeft:=Left;
+      aRight:=Right-LNode.BorderRight-LNode.PaddingRight;
+      aTop:=Top+LNode.BorderTop+LNode.PaddingTop;
+    end;
+    DrawTextDecorationH(aLeft,aTop,aRight,aFont,LineKW,StyleKW,aColorFP,aThickness);
+
+  end else begin
+    // simple box
+    with Params.BoundingBox.Box do
+    begin
+      aLeft:=Left+LNode.BorderLeft+LNode.PaddingLeft;
+      aRight:=Right-LNode.BorderRight-LNode.PaddingRight;
+      aTop:=Top+LNode.BorderTop+LNode.PaddingTop;
+    end;
+
+    DrawTextDecorationH(aLeft,aTop,aRight,aFont,LineKW,StyleKW,aColorFP,aThickness);
+  end;
 end;
 
 function TFresnelRenderer.CreateScrollBar(El: TFresnelElement; Horizontal: boolean
@@ -1225,12 +1268,12 @@ begin
   aBorderBox:=El.UsedBorderBox;
 
   //writeln('TFresnelRenderer.DrawElement ',El.Name,' BorderBox=',El.UsedBorderBox.ToString,' ContentBox=',El.UsedContentBox.ToString,' Origin=',Origin.ToString);
-
-  if El<>El.Viewport then
-  begin
-    // background and border
-    BorderParams:=CreateBorderAndBackground;
-    try
+  BorderParams:=nil;
+  try
+    if El<>El.Viewport then
+    begin
+      // background and border
+      BorderParams:=CreateBorderAndBackground;
       // border-width
       BorderParams.Width[ffsLeft]:=LNode.BorderLeft;
       BorderParams.Width[ffsTop]:=LNode.BorderTop;
@@ -1284,55 +1327,57 @@ begin
         if BorderParams.HasBorder then
           DrawElBorder(El,BorderParams);
         end;
-    finally
-      BorderParams.Free;
     end;
-  end;
 
-  NeedRestore:=false;
-  ClipHorizontal:=flfClipHorizontal in LNode.Flags;
-  ClipVertical:=flfClipVertical in LNode.Flags;
-  if ClipHorizontal or ClipVertical then
-  begin
-    //writeln('TFresnelRenderer.DrawElement ',El.Name,' ',ClipHorizontal,' ',ClipVertical);
-    r:=El.GetUsedPaddingBox;
-    if not ClipHorizontal then
-    begin
-      r.Left:=-Origin.X;
-      r.Right:=El.Viewport.Width-Origin.X;
-    end else if not ClipVertical then
+    NeedRestore:=false;
+    ClipHorizontal:=flfClipHorizontal in LNode.Flags;
+    ClipVertical:=flfClipVertical in LNode.Flags;
+    if ClipHorizontal or ClipVertical then
     begin
-      r.Top:=-Origin.Y;
-      r.Bottom:=El.Viewport.Height-Origin.Y;
-    end;
+      //writeln('TFresnelRenderer.DrawElement ',El.Name,' ',ClipHorizontal,' ',ClipVertical);
+      r:=El.GetUsedPaddingBox;
+      if not ClipHorizontal then
+      begin
+        r.Left:=-Origin.X;
+        r.Right:=El.Viewport.Width-Origin.X;
+      end else if not ClipVertical then
+      begin
+        r.Top:=-Origin.Y;
+        r.Bottom:=El.Viewport.Height-Origin.Y;
+      end;
 
-    Save;
-    NeedRestore:=true;
-    ClipRect(r);
-  end;
-  try
-    // underlying text-decoration
-    TextDecorationLineKW:=El.GetComputedKeyword(fcaTextDecorationLine,CSSRegistry.Chk_TextDecorationLine_KeywordIDs);
-    if TextDecorationLineKW in [CSSRegistry.kwUnderline,CSSRegistry.kwOverline,
-        CSSRegistry.kwGrammarError,CSSRegistry.kwSpellingError] then
-      DrawElTextDecoration(El,TextDecorationLineKW,BorderParams);
+      Save;
+      NeedRestore:=true;
+      ClipRect(r);
+    end;
+    try
+      // underlying text-decoration
+      TextDecorationLineKW:=El.GetComputedKeyword(fcaTextDecorationLine,CSSRegistry.Chk_TextDecorationLine_KeywordIDs);
+      if (TextDecorationLineKW in [CSSRegistry.kwUnderline,CSSRegistry.kwOverline,
+          CSSRegistry.kwGrammarError,CSSRegistry.kwSpellingError])
+          and (BorderParams<>nil) then
+        DrawElTextDecoration(El,TextDecorationLineKW,BorderParams);
 
-    // Give element a chance to draw itself (on top of background and border)
-    aRenderable.Render(FIntfRenderer);
+      // Give element a chance to draw itself (on top of background and border)
+      aRenderable.Render(FIntfRenderer);
 
-    DrawChildren(El);
+      DrawChildren(El);
 
-    // overlying text-decoration
-    if TextDecorationLineKW=CSSRegistry.kwLineThrough then
-      DrawElTextDecoration(El,TextDecorationLineKW,BorderParams);
+      // overlying text-decoration
+      if (TextDecorationLineKW=CSSRegistry.kwLineThrough)
+          and (BorderParams<>nil) then
+        DrawElTextDecoration(El,TextDecorationLineKW,BorderParams);
 
-    // draw scrollbars
-    DrawScrollBars(El);
+      // draw scrollbars
+      DrawScrollBars(El);
+    finally
+      if NeedRestore then
+        Restore;
+    end;
+    aRenderable.AfterRender;
   finally
-    if NeedRestore then
-      Restore;
+    BorderParams.Free;
   end;
-  aRenderable.AfterRender;
 end;
 
 procedure TFresnelRenderer.DrawChildren(El: TFresnelElement);
@@ -1345,9 +1390,12 @@ begin
   LNode:=TUsedLayoutNode(El.LayoutNode);
 
   OldOrigin:=Origin;
-  NewOrigin.X:=OldOrigin.X+El.UsedClientBox.Left-El.ScrollLeft;
-  NewOrigin.Y:=OldOrigin.Y+El.UsedClientBox.Top-El.ScrollTop;
-  Origin:=NewOrigin;
+  if LNode.Layouter<>nil then
+  begin
+    NewOrigin.X:=OldOrigin.X+El.UsedClientBox.Left-El.ScrollLeft;
+    NewOrigin.Y:=OldOrigin.Y+El.UsedClientBox.Top-El.ScrollTop;
+    Origin:=NewOrigin;
+  end;
   //writeln('TFresnelRenderer.DrawChildren ',El.GetPath,' Old=',OldOrigin.ToString,' Origin=',Origin.ToString);
   for i:=0 to LNode.NodeCount-1 do
   begin