TGPGraphics.GetVisibleClipBounds

Issue #163 resolved
Yeray Alonso created an issue

We use the TGPGraphics.GetVisibleClipBounds function to get the current clipping zone, store it and restore later. But this function seems to give a wrong result in Linux and MacOS:

procedure TForm1.FormPaint(Sender: TObject);
var GPGraphics: TGPGraphics;
    tmpR: TGPRectF;
begin
  GPGraphics:=TGPGraphics.Create(Canvas.Handle);
  GPGraphics.GetVisibleClipBounds(tmpR);
  Caption:='Width: ' + FormatFloat('#,##0.00#', tmpR.Width) + ', Height: ' + FormatFloat('#,##0.00#', tmpR.Height);
end;

Comments (7)

  1. Eugene Kryukov repo owner

    Actually this function uses native API to get clipping box. Why you think it is wrong ?

  2. Yeray Alonso reporter

    Our TChart component fails to draw the Legend under some circumstances and I suspect there's something wrong with the clipping. However, at this moment I'm not sure the problem is at TGPGraphics.GetVisibleClipBounds function. Sorry for the confusion.
    Here is the result in Linux:

    VirtualBox_2019-01-24_12-02-43.png

    And in MacOS:

    TeamViewer_2019-01-24_11-57-16.png

    However, in 3D the Legend is drawn both for Linux and MacOS.
    In Linux:

    VirtualBox_2019-01-24_12-02-23.png

    And in MacOS:

    TeamViewer_2019-01-24_11-58-23.png

    Of course in Windows the Legend is drawn both in 2D and 3D.
    At this moment I believe the problem is at how we call TGPGraphics.IntersectClip function.
    For 2D Charts we use this ClipRectangle function:

    procedure TGDIPlusCanvas.ClipRectangle(Const Rect:TRect);
    var tmpR : TRect;
    begin
      tmpR:=TeeRect(Rect.Left,Rect.Top-1,Rect.Right,Rect.Bottom+1);
      FGraphics.IntersectClip(MakeRect(tmpR));
    end;
    

    For 3D Charts we use this ClipPolygon function:

    Procedure TGDIPlusCanvas.ClipPolygon(const Points:Array of TPoint; NumPoints:Integer;
                                         DiffRegion:Boolean=False);
    var Region : HRgn;
        r : TGPRegion;
    begin
      Region:=CreatePolygonRgn(Points,NumPoints,ALTERNATE);
    
      r:=TGPRegion.Create(Region);
      try
        PushClipRect;
    
        if DiffRegion then
           FGraphics.SetClip(r,CombineModeExclude)
        else
           FGraphics.IntersectClip(r);
    
      finally
        DeleteObject(Region);
        r.Free;
      end;
    
    //DONT:  inherited;
    end;
    

    Now I'm testing this new ClipRectangle function, which seems to work fine everywhere:

    procedure TGDIPlusCanvas.ClipRectangle(Const Rect:TRect);
    var tmpR : TRect;
    {$IFNDEF MSWINDOWS}
        tmpP   : TFourPoints;
        Region : HRgn;
        r      : TGPRegion;
    {$ENDIF}
    begin
      PushClipRect;
    
      tmpR:=TeeRect(Rect.Left,Rect.Top-1,Rect.Right,Rect.Bottom+1);
    
      {$IFDEF MSWINDOWS}
      FGraphics.IntersectClip(MakeRect(tmpR));
      {$ELSE}
      try
        RectToFourPoints(tmpR, 0, tmpP);
        Region:=CreatePolygonRgn(tmpP,4,ALTERNATE);
        r:=TGPRegion.Create(Region);
    
        FGraphics.IntersectClip(r);
      finally
        DeleteObject(Region);
        r.Free;
      end;
      {$ENDIF}
    end;
    
  3. Yeray Alonso reporter

    Hmmm, this function works in respect to the Legend drawing, but it doesn't do the clipping correctly in Linux&MacOS:

    Linux:
    VirtualBox_2019-01-24_12-25-03.png

    MacOS:
    TeamViewer_2019-01-24_12-26-49.png

    Windows:
    2019-01-24_12-27-11.png

    I've also tested with this function to do the same in all the platforms, with the same results above:

    procedure TGDIPlusCanvas.ClipRectangle(Const Rect:TRect);
    var tmpR : TRect;
        tmpP   : TFourPoints;
        Region : HRgn;
        r      : TGPRegion;
    begin
      PushClipRect;
    
      tmpR:=TeeRect(Rect.Left,Rect.Top-1,Rect.Right,Rect.Bottom+1);
    
      try
        RectToFourPoints(tmpR, 0, tmpP);
        Region:=CreatePolygonRgn(tmpP,4,ALTERNATE);
        r:=TGPRegion.Create(Region);
    
        FGraphics.IntersectClip(r);
      finally
        DeleteObject(Region);
        r.Free;
      end;
    end;
    
  4. Yeray Alonso reporter

    I've simplified the issue removing any reference to TeeChart. Here you have the code to reproduce the clipping problem in Linux&MacOS:

    uses GDIPOBJ, GDIPAPI;
    
    procedure TForm1.FormPaint(Sender: TObject);
    var G: TGPGraphics;
        chartRect: TRect;
        oldClipRect,
        seriesRect,
        legendRect: TGPRect;
        tmpP   : Array[0..3] of TPoint;
        Region : HRgn;
        r      : TGPRegion;
    begin
      G:=TGPGraphics.Create(Canvas.Handle);
    
      legendRect.Width:=100;
      legendRect.Height:=200;
      legendRect.X:=ClientRect.Width-legendRect.Width-50;
      legendRect.Y:=50;
    
      chartRect:=Rect(50,50,legendRect.X-200+50,clientRect.Height-100);
    
      seriesRect.X:=chartRect.Left+chartRect.Width-50;
      seriesRect.Width:=100;
      seriesRect.Y:=chartRect.Top+50;
      seriesRect.Height:=chartRect.Height;
    
      //draw Chart rectangle
      G.FillRectangle(TGPSolidBrush.Create(MakeColor(255,255,255)), MakeRect(chartRect));
      G.DrawRectangle(TGPPen.Create(MakeColor(0,0,0)), MakeRect(chartRect));
    
      //save clipping rect
      G.GetVisibleClipBounds(oldClipRect);
    
      //clip rectangle
      try
        tmpP[0]:=Point(chartRect.Left,chartRect.Top);
        tmpP[1]:=Point(chartRect.Left,chartRect.Bottom);
        tmpP[2]:=Point(chartRect.Right,chartRect.Bottom);
        tmpP[3]:=Point(chartRect.Right,chartRect.Top);
        Region:=CreatePolygonRgn(tmpP,4,ALTERNATE);
        r:=TGPRegion.Create(Region);
        G.IntersectClip(r);
      finally
        DeleteObject(Region);
        r.Free;
      end;
    
      //drawSeries
      G.FillRectangle(TGPSolidBrush.Create(MakeColor(125,200,255)), seriesRect);
      G.DrawRectangle(TGPPen.Create(MakeColor(0,0,0)), seriesRect);
    
      //restore saved clipping
      G.SetClip(oldClipRect);
    
      //drawLegend
      G.FillRectangle(TGPSolidBrush.Create(MakeColor(255,125,125)), legendRect);
      G.DrawRectangle(TGPPen.Create(MakeColor(0,0,0)), legendRect);
    end;
    
  5. Eugene Kryukov repo owner

    Thank you for detailed report. We start working on it.

    One question, why don't you just use TGPGraphics.IntersectClip(const rect: TGPRectF) in ClipRectangle, but use such complicated code with Region ?

  6. Yeray Alonso reporter

    One question, why don't you just use TGPGraphics.IntersectClip(const rect: TGPRectF) in ClipRectangle, but use such complicated code with Region ?

    Precisely the TGPRectF version of TGPGraphics.IntersectClip wasn't working as expected in Linux&MacOS and I found the TGPRegion version was working well everywhere.

    Now, with v1.06, it seems to work perfectly.
    Thanks!

  7. Log in to comment