From f1c6358aeb62cac7a58258c0e5b2a0b89e1d9ec0 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Mon, 20 Oct 2014 06:01:39 +0000 Subject: [PATCH] lcl-cocoa: Fixes TBitBtn.Glyph, the image data was being freed together with the glyph TBitmap git-svn-id: trunk@46620 - --- lcl/interfaces/cocoa/cocoagdiobjects.pas | 37 +++++++++++++++++++++--- lcl/interfaces/cocoa/cocoaobject.inc | 9 ++++-- lcl/interfaces/cocoa/cocoaprivate.pp | 17 +++++++++-- lcl/interfaces/cocoa/cocoawinapi.inc | 4 ++- lcl/interfaces/cocoa/cocoawsbuttons.pp | 4 ++- lcl/interfaces/cocoa/cocoawscommon.pas | 1 + lcl/interfaces/cocoa/cocoawsforms.pp | 6 ++-- 7 files changed, 64 insertions(+), 14 deletions(-) diff --git a/lcl/interfaces/cocoa/cocoagdiobjects.pas b/lcl/interfaces/cocoa/cocoagdiobjects.pas index 2aed689493..6bb50798bf 100644 --- a/lcl/interfaces/cocoa/cocoagdiobjects.pas +++ b/lcl/interfaces/cocoa/cocoagdiobjects.pas @@ -203,6 +203,7 @@ type TCocoaBitmap = class(TCocoaGDIObject) strict private FData: Pointer; + FOriginalData: PByte; // Exists and is set in case the data needed pre-multiplication FAlignment: TCocoaBitmapAlignment; FFreeData: Boolean; FDataSize: Integer; @@ -218,7 +219,6 @@ type FImage: NSImage; FImagerep: NSBitmapImageRep; function GetColorSpace: NSString; - procedure PreMultiplyAlpha(); function DebugShowData(): string; public constructor Create(ABitmap: TCocoaBitmap); @@ -232,6 +232,8 @@ type function CreateSubImage(const ARect: TRect): CGImageRef; function CreateMaskImage(const ARect: TRect): CGImageRef; + procedure PreMultiplyAlpha(); + function GetNonPreMultipliedData(): PByte; public property BitmapType: TCocoaBitmapType read FType; property BitsPerPixel: Byte read FBitsPerPixel; @@ -749,8 +751,10 @@ begin HasAlpha := AType in [cbtARGB, cbtRGBA]; // Non premultiplied bitmaps can't be used for bitmap context - // So we need to pre-multiply ourselves - PreMultiplyAlpha(); + // So we need to pre-multiply ourselves, but only if we were allowed + // to copy the data, otherwise we might corrupt the original + if ACopyData then + PreMultiplyAlpha(); BitmapFormat := 0; if AType in [cbtARGB, cbtRGB] then BitmapFormat := BitmapFormat or NSAlphaFirstBitmapFormat; @@ -789,6 +793,8 @@ destructor TCocoaBitmap.Destroy; begin image.release; if FFreeData then System.FreeMem(FData); + if FOriginalData <> nil then + System.FreeMem(FOriginalData); inherited Destroy; end; @@ -890,6 +896,7 @@ begin Result := NSCalibratedRGBColorSpace; end; +// Cocoa cannot create a context unless the image has alpha pre-multiplied procedure TCocoaBitmap.PreMultiplyAlpha; var lByteData: PByte; @@ -897,6 +904,16 @@ var lAlpha, lRed, lGreen, lBlue: Byte; begin if not (FType in [cbtARGB, cbtRGBA]) then Exit; + if FData = nil then Exit; + + // Keep the original data in a copy, otherwise we cant get access to it + // because pre-multiplying destroys the original value if we had alpha=0 + if FOriginalData <> nil then + System.FreeMem(FOriginalData); + System.GetMem(FOriginalData, FDataSize); + System.Move(FData^, FOriginalData^, FDataSize); // copy data + + // Pre-Multiply lByteData := PByte(FData); i := 0; while i < FDataSize -1 do @@ -928,10 +945,22 @@ begin end; end; +// The Alpha pre-multiplication will prevent us from obtaining the original image +// raw data for the function RawImage_FromCocoaBitmap, +// so we need to store it +function TCocoaBitmap.GetNonPreMultipliedData(): PByte; +begin + if FOriginalData <> nil then + Result := FOriginalData + else + Result := PByte(FData); +end; + function TCocoaBitmap.DebugShowData: string; var i: Integer; begin + Result := ''; for i := 0 to FDataSize -1 do begin Result := Result + IntToHex(PByte(FData)[i], 2); @@ -1823,7 +1852,7 @@ var begin if Style = bvRaised then begin - GetHiThemeMetric(kThemeMetricPrimaryGroupBoxContentInset, D); + D := GetHiThemeMetric(kThemeMetricPrimaryGroupBoxContentInset); // draw frame as group box DrawInfo.version := 0; diff --git a/lcl/interfaces/cocoa/cocoaobject.inc b/lcl/interfaces/cocoa/cocoaobject.inc index ed75db1d80..bb51a3bc66 100644 --- a/lcl/interfaces/cocoa/cocoaobject.inc +++ b/lcl/interfaces/cocoa/cocoaobject.inc @@ -585,19 +585,22 @@ begin end; {------------------------------------------------------------------------------ - Method: TCarbonWidgetSet.RawImage_FromCarbonBitmap + Method: TCocoaWidgetSet.RawImage_FromCocoaBitmap - Creates a rawimage description for a carbonbitmap + Creates a rawimage description for a cocoabitmap ------------------------------------------------------------------------------} function TCocoaWidgetSet.RawImage_FromCocoaBitmap(out ARawImage: TRawImage; ABitmap, AMask: TCocoaBitmap; ARect: PRect = nil): Boolean; +var + lBitmapData: PByte; begin FillChar(ARawImage, SizeOf(ARawImage), 0); RawImage_DescriptionFromCocoaBitmap(ARawImage.Description, ABitmap); ARawImage.DataSize := ABitmap.DataSize; ReAllocMem(ARawImage.Data, ARawImage.DataSize); + lBitmapData := ABitmap.GetNonPreMultipliedData(); if ARawImage.DataSize > 0 then - System.Move(ABitmap.Data^, ARawImage.Data^, ARawImage.DataSize); + System.Move(lBitmapData^, ARawImage.Data^, ARawImage.DataSize); Result := True; diff --git a/lcl/interfaces/cocoa/cocoaprivate.pp b/lcl/interfaces/cocoa/cocoaprivate.pp index 6e87667d8b..4d439feb37 100644 --- a/lcl/interfaces/cocoa/cocoaprivate.pp +++ b/lcl/interfaces/cocoa/cocoaprivate.pp @@ -29,7 +29,7 @@ uses // Libs MacOSAll, CocoaAll, CocoaUtils, CocoaGDIObjects, // LCL - LMessages, LCLMessageGlue, ExtCtrls, + LMessages, LCLMessageGlue, ExtCtrls, Graphics, LCLType, LCLProc, Controls, ComCtrls; type @@ -216,6 +216,8 @@ type procedure frameDidChange(sender: NSNotification); message 'frameDidChange:'; public callback: IButtonCallback; + Glyph: TBitmap; + procedure dealloc; override; function initWithFrame(frameRect: NSRect): id; override; function acceptsFirstResponder: Boolean; override; function becomeFirstResponder: Boolean; override; @@ -236,7 +238,6 @@ type procedure mouseMoved(event: NSEvent); override; procedure resetCursorRects; override; function lclIsHandle: Boolean; override; - end; TCocoaFieldEditor = objcclass; @@ -1425,6 +1426,14 @@ begin callback.frameDidChange; end; +procedure TCocoaButton.dealloc; +begin + if Assigned(Glyph) then + FreeAndNil(Glyph); + + inherited dealloc; +end; + function TCocoaButton.initWithFrame(frameRect: NSRect): id; begin Result := inherited initWithFrame(frameRect); @@ -1581,6 +1590,7 @@ end; function TCocoaTextField.RealResignFirstResponder: Boolean; begin callback.ResignFirstResponder; + Result := True; end; // Do not propagate this event to the LCL, @@ -1709,6 +1719,7 @@ end; function TCocoaSecureTextField.RealResignFirstResponder: Boolean; begin callback.ResignFirstResponder; + Result := True; end; function TCocoaSecureTextField.resignFirstResponder: Boolean; @@ -2504,7 +2515,7 @@ end; function TCocoaTabControl.tabView_shouldSelectTabViewItem(tabView: NSTabView; tabViewItem: NSTabViewItem): Boolean; begin - + Result := True; end; procedure TCocoaTabControl.tabView_willSelectTabViewItem(tabView: NSTabView; diff --git a/lcl/interfaces/cocoa/cocoawinapi.inc b/lcl/interfaces/cocoa/cocoawinapi.inc index 5d687cc636..4c956b1436 100644 --- a/lcl/interfaces/cocoa/cocoawinapi.inc +++ b/lcl/interfaces/cocoa/cocoawinapi.inc @@ -1710,7 +1710,8 @@ end; function TCocoaWidgetSet.SetCapture(AHandle: HWND): HWND; begin - FCaptureControl:= AHandle; + Result := FCaptureControl; + FCaptureControl := AHandle; end; function TCocoaWidgetSet.SetCaretPos(X, Y: Integer): Boolean; @@ -1750,6 +1751,7 @@ end; function TCocoaWidgetSet.ReleaseCapture : Boolean; begin FCaptureControl:=0; + Result := True; end; function TCocoaWidgetSet.ReleaseDC(hWnd: HWND; DC: HDC): Integer; diff --git a/lcl/interfaces/cocoa/cocoawsbuttons.pp b/lcl/interfaces/cocoa/cocoawsbuttons.pp index d88f449af5..6cdaf4af75 100644 --- a/lcl/interfaces/cocoa/cocoawsbuttons.pp +++ b/lcl/interfaces/cocoa/cocoawsbuttons.pp @@ -111,7 +111,9 @@ begin lButtonHandle := TCocoaButton(ABitBtn.Handle); lButtonHandle.setImage(Img); lButtonHandle.setImagePosition(LCLGlyphPosToCocoa(ABitBtn.Layout)); - AGlyph.Free; + if Assigned(lButtonHandle.Glyph) then + FreeAndNil(lButtonHandle.Glyph); + lButtonHandle.Glyph := AGlyph; end; end; diff --git a/lcl/interfaces/cocoa/cocoawscommon.pas b/lcl/interfaces/cocoa/cocoawscommon.pas index a138e348a4..f737669f57 100644 --- a/lcl/interfaces/cocoa/cocoawscommon.pas +++ b/lcl/interfaces/cocoa/cocoawscommon.pas @@ -459,6 +459,7 @@ var function LCLCharToMacEvent(const AUTF8Char: AnsiString): Boolean; begin + Result := False; if AUTF8Char = '' then Exit; // TODO diff --git a/lcl/interfaces/cocoa/cocoawsforms.pp b/lcl/interfaces/cocoa/cocoawsforms.pp index bc6399d5d2..62e235efe5 100644 --- a/lcl/interfaces/cocoa/cocoawsforms.pp +++ b/lcl/interfaces/cocoa/cocoawsforms.pp @@ -590,8 +590,10 @@ end; class function TCocoaWSCustomForm.GetClientBounds(const AWinControl: TWinControl; var ARect: TRect): Boolean; begin - if AWinControl.HandleAllocated then - ARect := NSObject(AWinControl.Handle).lclClientFrame; + Result := False; + if not AWinControl.HandleAllocated then Exit; + ARect := NSObject(AWinControl.Handle).lclClientFrame; + Result := True; end; class function TCocoaWSCustomForm.GetClientRect(const AWinControl: TWinControl; var ARect: TRect): Boolean;