Browse Source

global transform variable

Unknown 6 years ago
parent
commit
6db60202e6
1 changed files with 86 additions and 57 deletions
  1. 86 57
      lazpaintcontrols/lcvectortextshapes.pas

+ 86 - 57
lazpaintcontrols/lcvectortextshapes.pas

@@ -33,13 +33,15 @@ type
   protected
   protected
     FTextLayout: TBidiTextLayout;
     FTextLayout: TBidiTextLayout;
     FFontRenderer: TBGRACustomFontRenderer;
     FFontRenderer: TBGRACustomFontRenderer;
+    FGlobalMatrix: TAffineMatrix;
+    procedure SetGlobalMatrix(AMatrix: TAffineMatrix);
     function PenVisible(AAssumePenFill: boolean = false): boolean;
     function PenVisible(AAssumePenFill: boolean = false): boolean;
     function AllowShearTransform: boolean; override;
     function AllowShearTransform: boolean; override;
     function ShowArrows: boolean; override;
     function ShowArrows: boolean; override;
-    function GetTextLayout(AMatrix: TAffineMatrix): TBidiTextLayout;
-    function GetTextLayoutIgnoreMatrix: TBidiTextLayout;
-    function GetFontRenderer(AMatrix: TAffineMatrix): TBGRACustomFontRenderer;
-    function GetTextRenderZoom(AMatrix: TAffineMatrix): single;
+    function GetTextLayout: TBidiTextLayout;
+    function GetFontRenderer: TBGRACustomFontRenderer;
+    function UpdateFontRenderer: boolean;
+    function GetTextRenderZoom: single;
     function GetUntransformedMatrix: TAffineMatrix; //matrix before render transform
     function GetUntransformedMatrix: TAffineMatrix; //matrix before render transform
     function IsTextMirrored(ABox: TAffineBox): boolean;
     function IsTextMirrored(ABox: TAffineBox): boolean;
     procedure SetDefaultFont;
     procedure SetDefaultFont;
@@ -190,6 +192,12 @@ begin
   EndUpdate;
   EndUpdate;
 end;
 end;
 
 
+procedure TTextShape.SetGlobalMatrix(AMatrix: TAffineMatrix);
+begin
+  if AMatrix = FGlobalMatrix then exit;
+  FGlobalMatrix := AMatrix;
+end;
+
 function TTextShape.PenVisible(AAssumePenFill: boolean): boolean;
 function TTextShape.PenVisible(AAssumePenFill: boolean): boolean;
 begin
 begin
   result := not PenFill.IsFullyTransparent or AAssumePenFill;
   result := not PenFill.IsFullyTransparent or AAssumePenFill;
@@ -205,18 +213,21 @@ begin
   Result:= false;
   Result:= false;
 end;
 end;
 
 
-function TTextShape.GetTextLayout(AMatrix: TAffineMatrix): TBidiTextLayout;
+function TTextShape.GetTextLayout: TBidiTextLayout;
 var
 var
   box: TAffineBox;
   box: TAffineBox;
   i: Integer;
   i: Integer;
   zoom: Single;
   zoom: Single;
 begin
 begin
   if FTextLayout = nil then
   if FTextLayout = nil then
-    FTextLayout := TBidiTextLayout.Create(GetFontRenderer(AMatrix), FText);
-  box := GetAffineBox(AMatrix,false);
+    FTextLayout := TBidiTextLayout.Create(GetFontRenderer, FText)
+  else
+    if UpdateFontRenderer then FTextLayout.InvalidateLayout;
+
+  box := GetAffineBox(FGlobalMatrix,false);
   FTextLayout.FontBidiMode:= FontBidiMode;
   FTextLayout.FontBidiMode:= FontBidiMode;
   FTextLayout.TopLeft := PointF(0,0);
   FTextLayout.TopLeft := PointF(0,0);
-  zoom := GetTextRenderZoom(AMatrix);
+  zoom := GetTextRenderZoom;
   FTextLayout.AvailableWidth:= box.Width*zoom;
   FTextLayout.AvailableWidth:= box.Width*zoom;
   FTextLayout.AvailableHeight:= box.Height*zoom;
   FTextLayout.AvailableHeight:= box.Height*zoom;
   for i := 0 to FTextLayout.ParagraphCount-1 do
   for i := 0 to FTextLayout.ParagraphCount-1 do
@@ -225,31 +236,38 @@ begin
   result:= FTextLayout;
   result:= FTextLayout;
 end;
 end;
 
 
-function TTextShape.GetTextLayoutIgnoreMatrix: TBidiTextLayout;
-begin
-  if FTextLayout = nil then
-    result := GetTextLayout(AffineMatrixIdentity)
-  else
-    result := FTextLayout;
-end;
-
-function TTextShape.GetFontRenderer(AMatrix: TAffineMatrix): TBGRACustomFontRenderer;
+function TTextShape.GetFontRenderer: TBGRACustomFontRenderer;
 begin
 begin
   if FFontRenderer = nil then
   if FFontRenderer = nil then
     FFontRenderer := TLCLFontRenderer.Create;
     FFontRenderer := TLCLFontRenderer.Create;
-
-  FFontRenderer.FontEmHeight := Round(FontEmHeight*GetTextRenderZoom(AMatrix));
-  FFontRenderer.FontName:= FontName;
-  FFontRenderer.FontStyle:= FontStyle;
-  FFontRenderer.FontQuality:= fqFineAntialiasing;
+  UpdateFontRenderer;
   result := FFontRenderer;
   result := FFontRenderer;
 end;
 end;
 
 
-function TTextShape.GetTextRenderZoom(AMatrix: TAffineMatrix): single;
+function TTextShape.UpdateFontRenderer: boolean;
+var
+  newEmHeight: integer;
+begin
+  newEmHeight := Round(FontEmHeight*GetTextRenderZoom);
+  if (newEmHeight <> FFontRenderer.FontEmHeight) or
+     (FFontRenderer.FontName <> FontName) or
+     (FFontRenderer.FontStyle <> FontStyle) or
+     (FFontRenderer.FontQuality <> fqFineAntialiasing) then
+  begin
+    FFontRenderer.FontEmHeight := newEmHeight;
+    FFontRenderer.FontName:= FontName;
+    FFontRenderer.FontStyle:= FontStyle;
+    FFontRenderer.FontQuality:= fqFineAntialiasing;
+    exit(true);
+  end
+  else exit(false);
+end;
+
+function TTextShape.GetTextRenderZoom: single;
 begin
 begin
   //font to be rendered at a sufficient size to avoid stretching
   //font to be rendered at a sufficient size to avoid stretching
-  result := max(VectLen(AMatrix[1,1],AMatrix[2,1]),
-                VectLen(AMatrix[1,2],AMatrix[2,2]));
+  result := max(VectLen(FGlobalMatrix[1,1],FGlobalMatrix[2,1]),
+                VectLen(FGlobalMatrix[1,2],FGlobalMatrix[2,2]));
 end;
 end;
 
 
 function TTextShape.GetUntransformedMatrix: TAffineMatrix;
 function TTextShape.GetUntransformedMatrix: TAffineMatrix;
@@ -298,8 +316,8 @@ begin
   selLeft := Min(FSelStart,FSelEnd);
   selLeft := Min(FSelStart,FSelEnd);
   if selLeft > 0 then
   if selLeft > 0 then
   begin
   begin
-    delCount := GetTextLayoutIgnoreMatrix.DeleteTextBefore(selLeft, ACount);
-    FText := GetTextLayoutIgnoreMatrix.TextUTF8;
+    delCount := GetTextLayout.DeleteTextBefore(selLeft, ACount);
+    FText := GetTextLayout.TextUTF8;
     dec(selLeft,delCount);
     dec(selLeft,delCount);
   end;
   end;
   FSelStart := selLeft;
   FSelStart := selLeft;
@@ -314,11 +332,11 @@ var
 begin
 begin
   BeginUpdate;
   BeginUpdate;
   selRight := Max(FSelStart,FSelEnd);
   selRight := Max(FSelStart,FSelEnd);
-  tl := GetTextLayoutIgnoreMatrix;
+  tl := GetTextLayout;
   if selRight+ACount <= tl.CharCount then
   if selRight+ACount <= tl.CharCount then
   begin
   begin
-    delCount := GetTextLayoutIgnoreMatrix.DeleteText(selRight, ACount);
-    FText := GetTextLayoutIgnoreMatrix.TextUTF8;
+    delCount := tl.DeleteText(selRight, ACount);
+    FText := tl.TextUTF8;
   end;
   end;
   FSelStart := selRight;
   FSelStart := selRight;
   FSelEnd := selRight;
   FSelEnd := selRight;
@@ -333,8 +351,8 @@ begin
   begin
   begin
     BeginUpdate;
     BeginUpdate;
     selLeft := Min(FSelStart,FSelEnd);
     selLeft := Min(FSelStart,FSelEnd);
-    GetTextLayoutIgnoreMatrix.DeleteText(selLeft, Abs(FSelEnd-FSelStart));
-    FText := GetTextLayoutIgnoreMatrix.TextUTF8;
+    GetTextLayout.DeleteText(selLeft, Abs(FSelEnd-FSelStart));
+    FText := GetTextLayout.TextUTF8;
     FSelStart := selLeft;
     FSelStart := selLeft;
     FSelEnd := selLeft;
     FSelEnd := selLeft;
     EndUpdate;
     EndUpdate;
@@ -347,8 +365,8 @@ var
 begin
 begin
   BeginUpdate;
   BeginUpdate;
   DeleteSelectedText;
   DeleteSelectedText;
-  insertCount := GetTextLayoutIgnoreMatrix.InsertText(ATextUTF8, FSelStart);
-  FText := GetTextLayoutIgnoreMatrix.TextUTF8;
+  insertCount := GetTextLayout.InsertText(ATextUTF8, FSelStart);
+  FText := GetTextLayout.TextUTF8;
   Inc(FSelStart, insertCount);
   Inc(FSelStart, insertCount);
   FSelEnd := FSelStart;
   FSelEnd := FSelStart;
   EndUpdate;
   EndUpdate;
@@ -358,9 +376,11 @@ procedure TTextShape.SelectWithMouse(X, Y: single; AExtend: boolean);
 var
 var
   newPos: Integer;
   newPos: Integer;
   tl: TBidiTextLayout;
   tl: TBidiTextLayout;
+  zoom: Single;
 begin
 begin
-  tl := GetTextLayoutIgnoreMatrix;
-  newPos := tl.GetCharIndexAt(tl.Matrix*AffineMatrixInverse(GetUntransformedMatrix)*PointF(X,Y));
+  tl := GetTextLayout;
+  zoom := GetTextRenderZoom;
+  newPos := tl.GetCharIndexAt(AffineMatrixScale(zoom,zoom)*AffineMatrixInverse(GetUntransformedMatrix)*PointF(X,Y));
   if newPos<>-1 then
   if newPos<>-1 then
   begin
   begin
     if (newPos <> FSelEnd) or (not AExtend and (FSelStart <> FSelEnd)) then
     if (newPos <> FSelEnd) or (not AExtend and (FSelStart <> FSelEnd)) then
@@ -382,13 +402,14 @@ begin
   FText := '';
   FText := '';
   FSelStart := 0;
   FSelStart := 0;
   FSelEnd := 0;
   FSelEnd := 0;
+  FGlobalMatrix := AffineMatrixIdentity;
 end;
 end;
 
 
 procedure TTextShape.QuickDefine(const APoint1, APoint2: TPointF);
 procedure TTextShape.QuickDefine(const APoint1, APoint2: TPointF);
 var minSize: single;
 var minSize: single;
   p2: TPointF;
   p2: TPointF;
 begin
 begin
-  minSize := GetFontRenderer(AffineMatrixIdentity).TextSize('Hg').cy;
+  minSize := GetFontRenderer.TextSize('Hg').cy/GetTextRenderZoom;
   p2 := APoint2;
   p2 := APoint2;
   if abs(APoint1.x-p2.x) < minSize then
   if abs(APoint1.x-p2.x) < minSize then
   begin
   begin
@@ -479,12 +500,14 @@ var
   pts: Array Of TPointF;
   pts: Array Of TPointF;
   i: Integer;
   i: Integer;
   c: TBGRAPixel;
   c: TBGRAPixel;
+  zoom: Single;
 begin
 begin
   inherited ConfigureEditor(AEditor);
   inherited ConfigureEditor(AEditor);
   AEditor.AddPolyline(GetAffineBox(AffineMatrixIdentity,true).AsPolygon, true, opsDashWithShadow);
   AEditor.AddPolyline(GetAffineBox(AffineMatrixIdentity,true).AsPolygon, true, opsDashWithShadow);
-  tl := GetTextLayout(AffineMatrixIdentity);
+  tl := GetTextLayout;
   caret:= tl.GetCaret(FSelEnd);
   caret:= tl.GetCaret(FSelEnd);
-  m := GetUntransformedMatrix;
+  zoom := GetTextRenderZoom;
+  m := GetUntransformedMatrix*AffineMatrixScale(1/zoom,1/zoom);
   if not isEmptyPointF(caret.PreviousTop) and (caret.PreviousRightToLeft<>caret.RightToLeft) then
   if not isEmptyPointF(caret.PreviousTop) and (caret.PreviousRightToLeft<>caret.RightToLeft) then
   begin
   begin
     orientation := (caret.Bottom-caret.Top)*(1/10);
     orientation := (caret.Bottom-caret.Top)*(1/10);
@@ -517,17 +540,18 @@ var
   tmpSource, tmpTransf: TBGRABitmap;
   tmpSource, tmpTransf: TBGRABitmap;
   scan: TBGRACustomScanner;
   scan: TBGRACustomScanner;
 begin
 begin
-  zoom := GetTextRenderZoom(AMatrix);
+  SetGlobalMatrix(AMatrix);
+  zoom := GetTextRenderZoom;
   if zoom = 0 then exit;
   if zoom = 0 then exit;
-  fr := GetFontRenderer(AMatrix);
+  fr := GetFontRenderer;
   if fr.FontEmHeight = 0 then exit;
   if fr.FontEmHeight = 0 then exit;
   pad := fr.FontEmHeight div 2;
   pad := fr.FontEmHeight div 2;
 
 
-  m := AMatrix*                             //global transform
+  m := FGlobalMatrix*                       //global transform
        GetUntransformedMatrix*              //transform according to shape rectangle
        GetUntransformedMatrix*              //transform according to shape rectangle
        AffineMatrixScale(1/zoom,1/zoom);    //shrink zoomed text if necessary
        AffineMatrixScale(1/zoom,1/zoom);    //shrink zoomed text if necessary
 
 
-  tl := GetTextLayout(AMatrix);
+  tl := GetTextLayout;
   sourceRect := RectF(-pad,-pad,tl.AvailableWidth+pad,tl.TotalTextHeight+pad);
   sourceRect := RectF(-pad,-pad,tl.AvailableWidth+pad,tl.TotalTextHeight+pad);
 
 
   destF := RectF(ADest.ClipRect.Left,ADest.ClipRect.Top,ADest.ClipRect.Right,ADest.ClipRect.Bottom);
   destF := RectF(ADest.ClipRect.Left,ADest.ClipRect.Top,ADest.ClipRect.Right,ADest.ClipRect.Bottom);
@@ -571,7 +595,7 @@ begin
                              tmpSource, rfHalfCosine, dmDrawWithTransparency);
                              tmpSource, rfHalfCosine, dmDrawWithTransparency);
     tmpSource.Free;
     tmpSource.Free;
 
 
-    scan := PenFill.CreateScanner(AMatrix, ADraft);
+    scan := PenFill.CreateScanner(FGlobalMatrix, ADraft);
     ADest.FillMask(transfRect.Left, transfRect.Top, tmpTransf, scan, dmDrawWithTransparency);
     ADest.FillMask(transfRect.Left, transfRect.Top, tmpTransf, scan, dmDrawWithTransparency);
     scan.Free;
     scan.Free;
     tmpTransf.Free;
     tmpTransf.Free;
@@ -668,6 +692,7 @@ procedure TTextShape.KeyDown(Shift: TShiftState; Key: TSpecialKey;
 var
 var
   idxPara, newPos: Integer;
   idxPara, newPos: Integer;
   stream: TStringStream;
   stream: TStringStream;
+  tl: TBidiTextLayout;
 begin
 begin
   if FTextLayout = nil then exit;
   if FTextLayout = nil then exit;
 
 
@@ -679,18 +704,19 @@ begin
   end else
   end else
   if Key in [skLeft,skRight] then
   if Key in [skLeft,skRight] then
   begin
   begin
-    if (Key = skLeft) xor GetTextLayoutIgnoreMatrix.ParagraphRightToLeft[GetTextLayoutIgnoreMatrix.GetParagraphAt(FSelEnd)] then
+    tl := GetTextLayout;
+    if (Key = skLeft) xor tl.ParagraphRightToLeft[tl.GetParagraphAt(FSelEnd)] then
     begin
     begin
       BeginUpdate;
       BeginUpdate;
       if FSelEnd > 0 then
       if FSelEnd > 0 then
-        Dec(FSelEnd, GetTextLayoutIgnoreMatrix.IncludeNonSpacingCharsBefore(FSelEnd,1) );
+        Dec(FSelEnd, tl.IncludeNonSpacingCharsBefore(FSelEnd,1) );
       if not (ssShift in Shift) then FSelStart := FSelEnd;
       if not (ssShift in Shift) then FSelStart := FSelEnd;
       EndUpdate;
       EndUpdate;
     end else
     end else
     begin
     begin
       BeginUpdate;
       BeginUpdate;
-      if FSelEnd < GetTextLayoutIgnoreMatrix.CharCount then
-        Inc(FSelEnd, GetTextLayoutIgnoreMatrix.IncludeNonSpacingChars(FSelEnd,1) );
+      if FSelEnd < tl.CharCount then
+        Inc(FSelEnd, tl.IncludeNonSpacingChars(FSelEnd,1) );
       if not (ssShift in Shift) then FSelStart := FSelEnd;
       if not (ssShift in Shift) then FSelStart := FSelEnd;
       EndUpdate;
       EndUpdate;
     end;
     end;
@@ -698,10 +724,11 @@ begin
   end else
   end else
   if Key in [skUp,skDown] then
   if Key in [skUp,skDown] then
   begin
   begin
+    tl := GetTextLayout;
     if Key = skUp then
     if Key = skUp then
-      newPos := GetTextLayoutIgnoreMatrix.FindTextAbove(FSelEnd)
+      newPos := tl.FindTextAbove(FSelEnd)
     else
     else
-      newPos := GetTextLayoutIgnoreMatrix.FindTextBelow(FSelEnd);
+      newPos := tl.FindTextBelow(FSelEnd);
     if (newPos <> -1) or (not (ssShift in Shift) and (FSelStart <> FSelEnd)) then
     if (newPos <> -1) or (not (ssShift in Shift) and (FSelStart <> FSelEnd)) then
     begin
     begin
       BeginUpdate;
       BeginUpdate;
@@ -713,13 +740,14 @@ begin
   end else
   end else
   if Key = skHome then
   if Key = skHome then
   begin
   begin
+    tl := GetTextLayout;
     BeginUpdate;
     BeginUpdate;
     if ssCtrl in Shift then
     if ssCtrl in Shift then
       FSelEnd := 0
       FSelEnd := 0
     else
     else
     begin
     begin
-      idxPara := GetTextLayoutIgnoreMatrix.GetParagraphAt(FSelEnd);
-      FSelEnd := GetTextLayoutIgnoreMatrix.ParagraphStartIndex[idxPara];
+      idxPara := tl.GetParagraphAt(FSelEnd);
+      FSelEnd := tl.ParagraphStartIndex[idxPara];
     end;
     end;
     if not (ssShift in Shift) then FSelStart := FSelEnd;
     if not (ssShift in Shift) then FSelStart := FSelEnd;
     EndUpdate;
     EndUpdate;
@@ -727,13 +755,14 @@ begin
   end else
   end else
   if Key = skEnd then
   if Key = skEnd then
   begin
   begin
+    tl := GetTextLayout;
     BeginUpdate;
     BeginUpdate;
     if ssCtrl in Shift then
     if ssCtrl in Shift then
-      FSelEnd := GetTextLayoutIgnoreMatrix.CharCount
+      FSelEnd := tl.CharCount
     else
     else
     begin
     begin
-      idxPara := GetTextLayoutIgnoreMatrix.GetParagraphAt(FSelEnd);
-      FSelEnd := GetTextLayoutIgnoreMatrix.ParagraphEndIndexBeforeParagraphSeparator[idxPara];
+      idxPara := tl.GetParagraphAt(FSelEnd);
+      FSelEnd := tl.ParagraphEndIndexBeforeParagraphSeparator[idxPara];
     end;
     end;
     if not (ssShift in Shift) then FSelStart := FSelEnd;
     if not (ssShift in Shift) then FSelStart := FSelEnd;
     EndUpdate;
     EndUpdate;
@@ -759,7 +788,7 @@ begin
       stream := nil;
       stream := nil;
       try
       try
         Clipboard.Clear;
         Clipboard.Clear;
-        stream := TStringStream.Create(GetTextLayoutIgnoreMatrix.CopyText(min(FSelStart,FSelEnd),abs(FSelEnd-FSelStart)));
+        stream := TStringStream.Create(GetTextLayout.CopyText(min(FSelStart,FSelEnd),abs(FSelEnd-FSelStart)));
         Clipboard.SetFormat(PredefinedClipboardFormat(pcfText), stream);
         Clipboard.SetFormat(PredefinedClipboardFormat(pcfText), stream);
       finally
       finally
         stream.Free;
         stream.Free;
@@ -780,7 +809,7 @@ begin
   begin
   begin
     BeginUpdate;
     BeginUpdate;
     FSelStart:= 0;
     FSelStart:= 0;
-    FSelEnd:= GetTextLayoutIgnoreMatrix.CharCount;
+    FSelEnd:= GetTextLayout.CharCount;
     EndUpdate;
     EndUpdate;
   end;
   end;
 end;
 end;