mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-12 10:20:49 +01:00
cocoa: fix various bitmap drawing problems
git-svn-id: trunk@38856 -
This commit is contained in:
parent
c66a6f83f6
commit
d8d59de96c
@ -353,11 +353,10 @@ type
|
|||||||
protected
|
protected
|
||||||
function SaveDCData: TCocoaDCData; virtual;
|
function SaveDCData: TCocoaDCData; virtual;
|
||||||
procedure RestoreDCData(const AData: TCocoaDCData); virtual;
|
procedure RestoreDCData(const AData: TCocoaDCData); virtual;
|
||||||
procedure SetCGFillping(Ctx: CGContextRef; Width, Height: Integer);
|
procedure SetCGFillping(Ctx: CGContextRef; Width, Height: CGFloat);
|
||||||
procedure RestoreCGFillping(Ctx: CGContextRef; Width, Height: Integer);
|
procedure RestoreCGFillping(Ctx: CGContextRef; Width, Height: CGFloat);
|
||||||
procedure ApplyTransform(Trans: CGAffineTransform);
|
procedure ApplyTransform(Trans: CGAffineTransform);
|
||||||
procedure ClearClipping;
|
procedure ClearClipping;
|
||||||
function GetSize: TSize; virtual;
|
|
||||||
public
|
public
|
||||||
ctx: NSGraphicsContext;
|
ctx: NSGraphicsContext;
|
||||||
constructor Create; virtual;
|
constructor Create; virtual;
|
||||||
@ -369,7 +368,6 @@ type
|
|||||||
function InitDraw(width, height: Integer): Boolean;
|
function InitDraw(width, height: Integer): Boolean;
|
||||||
|
|
||||||
// drawing functions
|
// drawing functions
|
||||||
procedure DrawBitmap(X, Y: Integer; ABitmap: TCocoaBitmap);
|
|
||||||
procedure DrawFocusRect(ARect: TRect);
|
procedure DrawFocusRect(ARect: TRect);
|
||||||
procedure InvertRectangle(X1, Y1, X2, Y2: Integer);
|
procedure InvertRectangle(X1, Y1, X2, Y2: Integer);
|
||||||
procedure MoveTo(X, Y: Integer);
|
procedure MoveTo(X, Y: Integer);
|
||||||
@ -382,7 +380,8 @@ type
|
|||||||
procedure Frame(const R: TRect);
|
procedure Frame(const R: TRect);
|
||||||
procedure Frame3d(var ARect: TRect; const FrameWidth: integer; const Style: TBevelCut);
|
procedure Frame3d(var ARect: TRect; const FrameWidth: integer; const Style: TBevelCut);
|
||||||
procedure FrameRect(const ARect: TRect; const ABrush: TCocoaBrush);
|
procedure FrameRect(const ARect: TRect; const ABrush: TCocoaBrush);
|
||||||
function DrawCGImage(X, Y, Width, Height: Integer; CGImage: CGImageRef): Boolean;
|
procedure DrawBitmap(X, Y: Integer; ABitmap: TCocoaBitmap);
|
||||||
|
function DrawImageRep(dstRect: NSRect; const srcRect: NSRect; ImageRep: NSBitmapImageRep): Boolean;
|
||||||
function StretchDraw(X, Y, Width, Height: Integer; SrcDC: TCocoaBitmapContext;
|
function StretchDraw(X, Y, Width, Height: Integer; SrcDC: TCocoaBitmapContext;
|
||||||
XSrc, YSrc, SrcWidth, SrcHeight: Integer; Msk: TCocoaBitmap; XMsk,
|
XSrc, YSrc, SrcWidth, SrcHeight: Integer; Msk: TCocoaBitmap; XMsk,
|
||||||
YMsk: Integer; Rop: DWORD): Boolean;
|
YMsk: Integer; Rop: DWORD): Boolean;
|
||||||
@ -401,7 +400,7 @@ type
|
|||||||
property Clipped: Boolean read FClipped;
|
property Clipped: Boolean read FClipped;
|
||||||
property PenPos: TPoint read FPenPos write FPenPos;
|
property PenPos: TPoint read FPenPos write FPenPos;
|
||||||
property ROP2: Integer read FROP2 write SetROP2;
|
property ROP2: Integer read FROP2 write SetROP2;
|
||||||
property Size: TSize read GetSize;
|
property Size: TSize read FSize;
|
||||||
property WindowOfs: TPoint read FWindowOfs write SetWindowOfs;
|
property WindowOfs: TPoint read FWindowOfs write SetWindowOfs;
|
||||||
property ViewPortOfs: TPoint read FViewPortOfs write SetViewPortOfs;
|
property ViewPortOfs: TPoint read FViewPortOfs write SetViewPortOfs;
|
||||||
|
|
||||||
@ -424,8 +423,6 @@ type
|
|||||||
private
|
private
|
||||||
FBitmap : TCocoaBitmap;
|
FBitmap : TCocoaBitmap;
|
||||||
procedure SetBitmap(const AValue: TCocoaBitmap);
|
procedure SetBitmap(const AValue: TCocoaBitmap);
|
||||||
protected
|
|
||||||
function GetSize: TSize; override;
|
|
||||||
public
|
public
|
||||||
constructor Create; override;
|
constructor Create; override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -1035,6 +1032,7 @@ begin
|
|||||||
else
|
else
|
||||||
Context := ctx;
|
Context := ctx;
|
||||||
|
|
||||||
|
ctx.saveGraphicsState;
|
||||||
ctx.setCurrentContext(Context);
|
ctx.setCurrentContext(Context);
|
||||||
ctx.setShouldAntialias(FFont.Antialiased);
|
ctx.setShouldAntialias(FFont.Antialiased);
|
||||||
Range := FLayout.glyphRangeForTextContainer(FTextContainer);
|
Range := FLayout.glyphRangeForTextContainer(FTextContainer);
|
||||||
@ -1058,6 +1056,7 @@ begin
|
|||||||
if FillBackground then
|
if FillBackground then
|
||||||
FLayout.drawBackgroundForGlyphRange_atPoint(Range, Pt);
|
FLayout.drawBackgroundForGlyphRange_atPoint(Range, Pt);
|
||||||
FLayout.drawGlyphsForGlyphRange_atPoint(Range, Pt);
|
FLayout.drawGlyphsForGlyphRange_atPoint(Range, Pt);
|
||||||
|
ctx.restoreGraphicsState;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TCocoaContext }
|
{ TCocoaContext }
|
||||||
@ -1112,6 +1111,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCocoaBitmapContext.SetBitmap(const AValue: TCocoaBitmap);
|
procedure TCocoaBitmapContext.SetBitmap(const AValue: TCocoaBitmap);
|
||||||
|
var
|
||||||
|
I: Boolean;
|
||||||
begin
|
begin
|
||||||
if FBitmap <> AValue then
|
if FBitmap <> AValue then
|
||||||
begin
|
begin
|
||||||
@ -1123,20 +1124,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
ctx := NSGraphicsContext.graphicsContextWithBitmapImageRep(AValue.ImageRep);
|
ctx := NSGraphicsContext.graphicsContextWithBitmapImageRep(AValue.ImageRep);
|
||||||
|
InitDraw(Bitmap.Width, Bitmap.Height);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCocoaBitmapContext.GetSize: TSize;
|
|
||||||
begin
|
|
||||||
if Assigned(Bitmap) then
|
|
||||||
begin
|
|
||||||
Result.cx := Bitmap.Width;
|
|
||||||
Result.cy := Bitmap.Height;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result := inherited GetSize;
|
|
||||||
end;
|
|
||||||
|
|
||||||
constructor TCocoaBitmapContext.Create;
|
constructor TCocoaBitmapContext.Create;
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
@ -1667,7 +1658,7 @@ begin
|
|||||||
Brush.Apply(Self);
|
Brush.Apply(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCocoaContext.SetCGFillping(Ctx: CGContextRef; Width, Height: Integer);
|
procedure TCocoaContext.SetCGFillping(Ctx: CGContextRef; Width, Height: CGFloat);
|
||||||
begin
|
begin
|
||||||
if Width < 0 then
|
if Width < 0 then
|
||||||
begin
|
begin
|
||||||
@ -1682,7 +1673,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCocoaContext.RestoreCGFillping(Ctx: CGContextRef; Width, Height: Integer);
|
procedure TCocoaContext.RestoreCGFillping(Ctx: CGContextRef; Width, Height: CGFloat);
|
||||||
begin
|
begin
|
||||||
if Height < 0 then
|
if Height < 0 then
|
||||||
begin
|
begin
|
||||||
@ -1720,134 +1711,50 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCocoaContext.GetSize: TSize;
|
function TCocoaContext.DrawImageRep(dstRect: NSRect; const srcRect: NSRect;
|
||||||
|
ImageRep: NSBitmapImageRep): Boolean;
|
||||||
|
var
|
||||||
|
Context: NSGraphicsContext;
|
||||||
begin
|
begin
|
||||||
Result := FSize;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TCocoaContext.DrawCGImage(X, Y, Width, Height: Integer;
|
|
||||||
CGImage: CGImageRef): Boolean;
|
|
||||||
begin
|
|
||||||
Result := False;
|
|
||||||
|
|
||||||
// save dest context
|
|
||||||
ctx.saveGraphicsState;
|
ctx.saveGraphicsState;
|
||||||
|
|
||||||
|
// we flip the context on it initialization (see InitDraw) so to draw
|
||||||
|
// a bitmap correctly we need to create a flipped context and to draw onto it
|
||||||
|
|
||||||
|
if not ctx.isFlipped then
|
||||||
|
Context := NSGraphicsContext.graphicsContextWithGraphicsPort_flipped(ctx.graphicsPort, True)
|
||||||
|
else
|
||||||
|
Context := ctx;
|
||||||
|
ctx.setCurrentContext(Context);
|
||||||
CGContextSetBlendMode(CGContext, kCGBlendModeNormal);
|
CGContextSetBlendMode(CGContext, kCGBlendModeNormal);
|
||||||
try
|
try
|
||||||
SetCGFillping(CGContext, Width, Height);
|
Result := ImageRep.drawInRect_fromRect_operation_fraction_respectFlipped_hints(
|
||||||
CGContextDrawImage(CGContext, GetCGRectSorted(X, Y, X + Width, Y + Height), CGImage);
|
dstRect, srcRect, NSCompositeSourceOver, 1.0, True, nil
|
||||||
RestoreCGFillping(CGContext, Width, Height);
|
);
|
||||||
finally
|
finally
|
||||||
ctx.restoreGraphicsState;
|
ctx.restoreGraphicsState;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Result := True;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCocoaContext.StretchDraw(X, Y, Width, Height: Integer;
|
function TCocoaContext.StretchDraw(X, Y, Width, Height: Integer;
|
||||||
SrcDC: TCocoaBitmapContext; XSrc, YSrc, SrcWidth, SrcHeight: Integer;
|
SrcDC: TCocoaBitmapContext; XSrc, YSrc, SrcWidth, SrcHeight: Integer;
|
||||||
Msk: TCocoaBitmap; XMsk, YMsk: Integer; Rop: DWORD): Boolean;
|
Msk: TCocoaBitmap; XMsk, YMsk: Integer; Rop: DWORD): Boolean;
|
||||||
var
|
var
|
||||||
Image, MskImage: CGImageRef;
|
|
||||||
SubImage, SubMask: Boolean;
|
|
||||||
Bmp: TCocoaBitmap;
|
Bmp: TCocoaBitmap;
|
||||||
LayRect, DstRect: CGRect;
|
|
||||||
ImgRect: CGRect;
|
|
||||||
LayerContext: CGContextRef;
|
|
||||||
Layer: CGLayerRef;
|
|
||||||
UseLayer: Boolean;
|
|
||||||
begin
|
begin
|
||||||
Result := False;
|
Result := False;
|
||||||
|
|
||||||
Bmp := SrcDC.Bitmap;
|
Bmp := SrcDC.Bitmap;
|
||||||
if Assigned(Bmp) then
|
if not Assigned(Bmp) then
|
||||||
Image := Bmp.ImageRep.CGImage
|
Exit;
|
||||||
else
|
|
||||||
Image := nil;
|
|
||||||
|
|
||||||
if Image = nil then Exit;
|
// TODO: mask clipping
|
||||||
|
// if Assigned(MskImage) then
|
||||||
|
// CGContextClipToMask(LayerContext, ImgRect, MskImage);
|
||||||
|
|
||||||
DstRect := CGRectMake(X, Y, Abs(Width), Abs(Height));
|
Result := DrawImageRep(
|
||||||
|
GetNSRect(X, Y, Width, Height),
|
||||||
SubMask := (Msk <> nil)
|
GetNSRect(XSrc, YSrc, SrcWidth, SrcHeight), Bmp.ImageRep);
|
||||||
and (Msk.Image <> nil)
|
|
||||||
and ( (XMsk <> 0)
|
|
||||||
or (YMsk <> 0)
|
|
||||||
or (Msk.Width <> SrcWidth)
|
|
||||||
or (Msk.Height <> SrcHeight));
|
|
||||||
|
|
||||||
SubImage := ((Msk <> nil) and (Msk.Image <> nil))
|
|
||||||
or (XSrc <> 0)
|
|
||||||
or (YSrc <> 0)
|
|
||||||
or (SrcWidth <> Bmp.Width)
|
|
||||||
or (SrcHeight <> Bmp.Height);
|
|
||||||
|
|
||||||
|
|
||||||
if SubMask then
|
|
||||||
MskImage := Msk.CreateSubImage(Bounds(XMsk, YMsk, SrcWidth, SrcHeight))
|
|
||||||
else
|
|
||||||
if Assigned(Msk) then
|
|
||||||
MskImage := Msk.ImageRep.CGImage
|
|
||||||
else
|
|
||||||
MskImage := nil;
|
|
||||||
|
|
||||||
if SubImage then
|
|
||||||
Image := Bmp.CreateSubImage(Bounds(XSrc, YSrc, SrcWidth, SrcHeight));
|
|
||||||
|
|
||||||
|
|
||||||
UseLayer:=Assigned(MskImage)
|
|
||||||
or (CGImageGetWidth(Image)<>SrcWidth)
|
|
||||||
or (CGImageGetHeight(Image)<>SrcHeight);
|
|
||||||
|
|
||||||
try
|
|
||||||
if not UseLayer then
|
|
||||||
begin
|
|
||||||
// Normal drawing
|
|
||||||
Result := DrawCGImage(X, Y, Width, Height, Image);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
// use temp layer to mask source image
|
|
||||||
// todo find a way to mask "hard" when stretching, now some soft remains are visible
|
|
||||||
LayRect := CGRectMake(0, 0, SrcWidth, SrcHeight);
|
|
||||||
Layer := CGLayerCreateWithContext(SrcDC.CGContext, LayRect.size, nil);
|
|
||||||
|
|
||||||
// the sub-image is out of edges
|
|
||||||
if (CGImageGetWidth(Image)<>SrcWidth) or (CGImageGetHeight(Image)<>SrcHeight) then
|
|
||||||
begin
|
|
||||||
with ImgRect do
|
|
||||||
if XSrc<0 then origin.x:=SrcWidth-CGImageGetWidth(Image) else origin.x:=0;
|
|
||||||
with ImgRect do
|
|
||||||
if YSrc<0 then origin.y:=0 else origin.y:=SrcHeight-CGImageGetHeight(Image);
|
|
||||||
|
|
||||||
ImgRect.size.width:=CGImageGetWidth(Image);
|
|
||||||
ImgRect.size.height:=CGImageGetHeight(Image);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
ImgRect:=LayRect;
|
|
||||||
|
|
||||||
try
|
|
||||||
LayerContext := CGLayerGetContext(Layer);
|
|
||||||
CGContextScaleCTM(LayerContext, 1, -1);
|
|
||||||
CGContextTranslateCTM(LayerContext, 0, -SrcHeight);
|
|
||||||
|
|
||||||
SetCGFillping(LayerContext, Width, Height);
|
|
||||||
if Assigned(MskImage) then
|
|
||||||
CGContextClipToMask(LayerContext, ImgRect, MskImage);
|
|
||||||
CGContextDrawImage(LayerContext, ImgRect, Image);
|
|
||||||
|
|
||||||
CGContextDrawLayerInRect(CGContext, DstRect, Layer);
|
|
||||||
|
|
||||||
Result := True;
|
|
||||||
finally
|
|
||||||
CGLayerRelease(Layer);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
finally
|
|
||||||
if SubImage then CGImageRelease(Image);
|
|
||||||
if SubMask then CGImageRelease(MskImage);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{------------------------------------------------------------------------------
|
{------------------------------------------------------------------------------
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user