#1 2016-09-22 14:45:22

MtwStark
Member
From: Italy
Registered: 2016-01-05
Posts: 27

Last SynPdf version corrupts clipping ranges

EDIT: Jump to the end of the page this post is superseeded! smile

Hello,
I recently had this problem, with introduction of enhanced clipping process by Achim Kalwa, I noticed invalid clipping when rendering metafiles.

They are now partially clipped out without reason, with previous version the clipping of same files was correct.

I have digged a bit and found that the problem is the new ExtSelectClipRgn function because of the transformation of clipping regions using WorldTransform in functions I2X and I2Y

I think that clipping regions are absolute (Window relative?) and they do not need to be shifted/rotated/scaled.

in ExtSelectClipRgn there is a call to BoxI function who calls RectI who calls I2X and I2Y where the clip region is shifted and scaled using FWorldOffsetX/Y and GetWorldFactorX/Y

the resulting clipping region is not correct.

I have simply avoided the BoxI call and calculated the CliptRect manually and it works fine.
This is the modified loop in the ExtSelectClipRgn:

    for i := 0 to RGNs^.rdh.nCount - 1 do begin
      Move(Rgns^.Buffer[i * SizeOf(TRect)], RCT, SizeOf(RCT));
      Inc(RCT.Bottom);
{$IFDEF TMW_TEST_NEW_CLIPRGN}

      // MTW WRONG ORIGIN AND SCALING OF CLIP REGIONS
      // seems that clip region is window relative, not world relative

      with Canvas do begin
        ClipRect.Left := FOffsetXDef + ViewOffsetX(RCT.Left) * FDevScaleX ;//*
        ClipRect.Top := FPage.GetPageHeight - FOffsetYDef - ViewOffsetY(RCT.Top) * FDevScaleY;
        ClipRect.Width := (ViewOffsetX(RCT.Right - 1) - ViewOffsetX(RCT.Left)) * FDevScaleX  ;//*
        ClipRect.Height := (ViewOffsetY(RCT.Top) - ViewOffsetY(RCT.Bottom - 1) ) * FDevScaleY;
      end;

{$ELSE}
      ClipRect := Canvas.BoxI(RCT, False);
{$ENDIF}
      Canvas.Rectangle(ClipRect.Left, ClipRect.Top, ClipRect.Width, ClipRect.Height);
    end;

if the problem is spread across other portions of library it could be interesting to add a flag with default to BoxI, RectI, I2X and I2Y, to exclude WorldOffset and WorldFactor from the calc.

I hope this could be of any help for someone.

Has anyone had my same problem and can confirm my intuition?

thanks
regards

Last edited by MtwStark (2016-11-16 11:11:44)

Offline

#2 2016-09-26 13:49:02

MtwStark
Member
From: Italy
Registered: 2016-01-05
Posts: 27

Re: Last SynPdf version corrupts clipping ranges

Hello everyone,
after some other tests I had to revert to the old version before enhanced clipping process by Achim Kalwa

I would like to open some points to discuss with the Forum because a few things are not really clear to me:

1) SetMetaRgn is now implemented to return the intersection of Current Meta Region and Current Clip Region.
reading the  SetMetaRgn function reference I ask myself if it should return their union (combined region) instead of their intersection

EDIT
1.5) IntersectClipRect
EMR_INTERSECTCLIPRECT Reference tells that it would set a new clip region to the intersection between passed region and Current Clip Region.
Now, if the passed region is empty (width or height = 0) the clip region is unaffected (exit), I think it should be set to null.

2) Coordinates are always handled as WorldTransform relative in clipping functions.
In some cases it seems to me they should be in Device Units, other in Logical Units. Something is odd with region coordinates..

3) EMR_EXTSELECTCLIPRGN
The RegionMode parameter is not handled at all, maybe it would be better to test RegionMode = RGN_COPY before clipping.

4) EMR_EXCLUDECLIPRECT is missing
it should be almost the same code of EMR_EXTSELECTCLIPRGN in RGN_DIFF mode, so implementing it will be like to kill two birds with one stone.

5) EMR_SELECTCLIPPATH is missing
maybe not too much important but I think it should be easy to implement, redirecting the call to ExtSelectClipRgn.

6) EMR_OFFSETCLIPRGN is missing
still not found in any document, but it shouldn't be too hard to implement.

Anybody have worked with this stuff?
any comment appreciated

regards

Last edited by MtwStark (2016-09-26 14:00:42)

Offline

#3 2016-10-05 11:14:05

MtwStark
Member
From: Italy
Registered: 2016-01-05
Posts: 27

Re: Last SynPdf version corrupts clipping ranges

Hello everybody

finally I discovered that the problem was that the type of clip applied was not the one to apply.

I try to explain better:

in TPdfEnum.ExtSelectClipRgn we receive a EMRExtSelectClipRgn structure.
this structure contains the iMode field which determines the type of clip to apply to current clip region and received region.

Currently the procedure only handles the RGN_COPY (replace) type of clipping.
Using the region passed, to replace the current clip region with different clip types (RGN_AND, RGN_DIFF, RGN_OR, or RGN_XOR) is not correct and will bring to unespected (wrong) results.

I have added a test for iMode to exit for types different from RGN_COPY.

procedure TPdfEnum.ExtSelectClipRgn(data: PEMRExtSelectClipRgn);
var
  RGNs: PRgnData;
  i: Integer;
  RCT: TRect;
  ClipRect: TPdfBox;
begin // see http://www.codeproject.com/Articles/1944/Guide-to-WIN-Regions

  // we are handling RGN_COPY (5) only..
  if data^.iMode <> RGN_COPY then
    exit;

  if not DC[nDC].ClipRgnNull then begin
    Canvas.GRestore;
    Canvas.NewPath;
    Canvas.fNewPath := False;
    DC[nDC].ClipRgnNull := True;
    fFillColor := -1;
  end;
  if Data^.cbRgnData > 0 then begin
    Canvas.GSave;
    Canvas.NewPath;
    DC[nDC].ClipRgnNull := False;
    RGNs := @Data^.RgnData;
    for i := 0 to RGNs^.rdh.nCount - 1 do begin
      Move(Rgns^.Buffer[i * SizeOf(TRect)], RCT, SizeOf(RCT));
      Inc(RCT.Bottom);
      ClipRect := Canvas.BoxI(RCT, False);
      Canvas.Rectangle(ClipRect.Left, ClipRect.Top, ClipRect.Width, ClipRect.Height);
    end;
    Canvas.Closepath;
    Canvas.Clip;
    Canvas.NewPath;
    Canvas.FNewPath := False;
  end;
end;

this avoids overwrite of clip regions with wrong ones.


P.S.
do not consider the code posted in 1st post

Offline

Board footer

Powered by FluxBB