diff --git a/lcl/interfaces/customdrawn/customdrawnint.pas b/lcl/interfaces/customdrawn/customdrawnint.pas index 228e695314..6336831ac6 100644 --- a/lcl/interfaces/customdrawn/customdrawnint.pas +++ b/lcl/interfaces/customdrawn/customdrawnint.pas @@ -149,6 +149,13 @@ type function FindWindowByXID(XWindowID: X.TWindow; out AWindowInfo: TX11WindowInfo): TWinControl; {$endif} + {$ifdef CD_Android} + procedure AndroidDebugLn(AStr: string); + {$endif} + // For unusual implementations of DebugLn/DebugOut + public + AccumulatedStr: string; + procedure AccumulatingDebugOut(AStr: string); protected {function CreateThemeServices: TThemeServices; override;} {function GetAppHandle: THandle; override; @@ -203,9 +210,9 @@ function WindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam; {$endif} {$ifndef CD_Android_NATIVEAPP} -function Java_com_pascal_jnitest_AndroidJNITest_stringFromJNI(env:PJNIEnv;this:jobject):jstring; cdecl; -function Java_com_pascal_jnitest_AndroidJNITest_intFromJNI(env:PJNIEnv;this:jobject): jint; cdecl; -function Java_com_pascal_jnitest_AndroidJNITest_LCLDrawToBitmap( +function Java_com_pascal_lclproject_LCLActivity_stringFromJNI(env:PJNIEnv;this:jobject):jstring; cdecl; +function Java_com_pascal_lclproject_LCLActivity_intFromJNI(env:PJNIEnv;this:jobject): jint; cdecl; +function Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap( env:PJNIEnv;this:jobject; width, height: jint; abitmap: jobject): jint; cdecl; function JNI_OnLoad(vm:PJavaVM;reserved:pointer):jint; cdecl; procedure JNI_OnUnload(vm:PJavaVM;reserved:pointer); cdecl; diff --git a/lcl/interfaces/customdrawn/customdrawnobject.inc b/lcl/interfaces/customdrawn/customdrawnobject.inc index d32c9d4e6b..018ce3666c 100644 --- a/lcl/interfaces/customdrawn/customdrawnobject.inc +++ b/lcl/interfaces/customdrawn/customdrawnobject.inc @@ -29,6 +29,10 @@ begin CDWidgetSet := Self; FTerminating := False; + // Setup DebugLn + DebugLnProc := @AndroidDebugLn; + DebugOutProc := @AccumulatingDebugOut; + BackendCreate; end; diff --git a/lcl/interfaces/customdrawn/customdrawnobject_android.inc b/lcl/interfaces/customdrawn/customdrawnobject_android.inc index 3f1ff4c887..67454c7884 100644 --- a/lcl/interfaces/customdrawn/customdrawnobject_android.inc +++ b/lcl/interfaces/customdrawn/customdrawnobject_android.inc @@ -395,7 +395,7 @@ end; const curClass:JClass=nil; nativeCodeLoaded:JfieldID=nil; -function Java_com_pascal_jnitest_AndroidJNITest_stringFromJNI(env:PJNIEnv;this:jobject):jstring; cdecl; +function Java_com_pascal_lclproject_LCLActivity_stringFromJNI(env:PJNIEnv;this:jobject):jstring; cdecl; var x:single; begin { __android_log_write(ANDROID_LOG_INFO,'nativetest','Java_com_bero_nativetest_Main_stringFromJNI entered'); @@ -405,37 +405,85 @@ begin __android_log_write(ANDROID_LOG_INFO,'nativetest','Java_com_bero_nativetest_Main_stringFromJNI exited');} end; -function Java_com_pascal_jnitest_AndroidJNITest_intFromJNI(env:PJNIEnv;this:jobject): jint; cdecl; +function Java_com_pascal_lclproject_LCLActivity_intFromJNI(env:PJNIEnv;this:jobject): jint; cdecl; begin Result := 8; end; -function Java_com_pascal_jnitest_AndroidJNITest_LCLDrawToBitmap( +function Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap( env:PJNIEnv;this:jobject; width, height: jint; abitmap: jobject): jint; cdecl; var pixels: PCardinal; + lCurForm: TCDNonNativeForm; + + struct : TPaintStruct; + lWidth, lHeight: Integer; + lBitmap, lMask: HBITMAP; + lRawImage: TRawImage; + {$IFDEF VerboseCDPaintProfiler} + lTimeStart: TDateTime; + {$ENDIF} begin Result := 0; AndroidBitmap_lockPixels(env, abitmap, @pixels); + + // debug info to check if we are painting pixels[30*width+30] := $FFFFFFFF; pixels[30*width+31] := $FFFFFFFF; pixels[30*width+32] := $FFFFFFFF; pixels[30*width+33] := $FFFFFFFF; pixels[30*width+34] := $FFFFFFFF; pixels[30*width+35] := $FFFFFFFF; + + lCurForm := GetCurrentForm(); + if lCurForm <> nil then + begin + {$IFDEF VerboseCDPaintProfiler} + //lTimeStart := NowUTC(); + {$ENDIF} + {$IFDEF VerboseCDWindow} + //DebugLn(Format('[TCDWSCustomForm.EvPaint] AWindowInfo: %x', [PtrInt(AWindowInfo)])); + {$ENDIF} + //if (AWinControl = nil) or (AWindowInfo = nil) then Exit; + + lWidth := 200;//Round(AWinControl.width); + lHeight := 200;//Round(AWinControl.height); + + FillChar(struct, SizeOf(TPaintStruct), 0); + + // Prepare the non-native image and canvas + UpdateControlLazImageAndCanvas(lCurForm.Image, lCurForm.Canvas, lWidth, lHeight, clfBGRA32, pixels); + + struct.hdc := HDC(lCurForm.Canvas); + + // Send the paint message to the LCL + {$IFDEF VerboseCDWindow} + //DebugLn(Format('[TCDWSCustomForm.EvPaint] OnPaint event started context: %x', [struct.hdc])); + {$ENDIF} + LCLSendPaintMsg(lCurForm.LCLForm, struct.hdc, @struct); + {$IFDEF VerboseCDWindow} + //DebugLn('[TCDWSCustomForm.EvPaint] OnPaint event ended'); + {$ENDIF} + + // Now paint all child win controls + //RenderChildWinControls(AWindowInfo.Image, AWindowInfo.Canvas, + //BackendGetCDWinControlList(TCustomForm(AWinControl))); + end; + + // Now returns the bitmap buffer to LCLActivity so that it can render it AndroidBitmap_unlockPixels(env, abitmap); end; const NativeMethods: array[0..2] of JNINativeMethod= ((name:'stringFromJNI'; signature:'()Ljava/lang/String;'; - fnPtr:@Java_com_pascal_jnitest_AndroidJNITest_stringFromJNI;), + fnPtr:@Java_com_pascal_lclproject_LCLActivity_stringFromJNI;), (name:'intFromJNI'; signature:'()I'; - fnPtr:@Java_com_pascal_jnitest_AndroidJNITest_intFromJNI;), + fnPtr:@Java_com_pascal_lclproject_LCLActivity_intFromJNI;), (name:'LCLDrawToBitmap'; signature:'(IILandroid/graphics/Bitmap;)I'; - fnPtr:@Java_com_pascal_jnitest_AndroidJNITest_LCLDrawToBitmap;) + fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap;) ); function JNI_OnLoad(vm:PJavaVM;reserved:pointer):jint; cdecl; @@ -449,7 +497,7 @@ begin __android_log_write(ANDROID_LOG_INFO,'nativetest',PChar(Format('CurVM^=%x', [PtrInt(CurVM^)]))); __android_log_write(ANDROID_LOG_INFO,'nativetest',PChar(Format('CurVM^^.reserved0=%x', [PtrInt(CurVM^^.reserved0)]))); __android_log_write(ANDROID_LOG_INFO,'nativetest',PChar(Format('CurVM^^.GetEnv=%x', [PtrInt(Pointer(@CurVM^^.GetEnv))]))); - if curVM^^.GetEnv(curVM,@curEnv,JNI_VERSION_1_4)<>JNI_OK then begin //<<<--- THIS CRASHES +{ if curVM^^.GetEnv(curVM,@curEnv,JNI_VERSION_1_4)<>JNI_OK then begin //<<<--- THIS CRASHES __android_log_write(ANDROID_LOG_INFO{FATAL},'nativetest','curVM^.GetEnv failed'); // result:=JNI_ERR; // exit; @@ -473,7 +521,7 @@ begin __android_log_write(ANDROID_LOG_FATAL,'nativetest','curEnv^.GetFieldID failed'); result:=JNI_ERR; exit; - end; + end; } result:=JNI_VERSION_1_4;// 1_6? end; @@ -484,6 +532,17 @@ end; {$endif} +procedure TCDWidgetSet.AndroidDebugLn(AStr: string); +begin + __android_log_write(ANDROID_LOG_INFO, 'lclproject', PChar(AccumulatedStr+AStr)); + AccumulatedStr := ''; +end; + +procedure TCDWidgetSet.AccumulatingDebugOut(AStr: string); +begin + AccumulatedStr := AccumulatedStr + AStr; +end; + {------------------------------------------------------------------------------ Method: TCDWidgetSet.Create Params: None @@ -517,9 +576,9 @@ end; ------------------------------------------------------------------------------} procedure TCDWidgetSet.AppInit(var ScreenInfo: TScreenInfo); begin - {$ifdef VerboseCDApplication} - //DebugLn('TCDWidgetSet.AppInit'); - {$endif} + {$ifdef VerboseCDApplication} + DebugLn('TCDWidgetSet.AppInit'); + {$endif} end; procedure TCDWidgetSet.AppRun(const ALoop: TApplicationMainLoop); diff --git a/lcl/interfaces/customdrawn/customdrawnproc.pas b/lcl/interfaces/customdrawn/customdrawnproc.pas index f0d9505c4c..c6a7f9ad59 100644 --- a/lcl/interfaces/customdrawn/customdrawnproc.pas +++ b/lcl/interfaces/customdrawn/customdrawnproc.pas @@ -26,24 +26,109 @@ type //CDControl: TCDControl; end; + TCDNonNativeForm = class + public + LCLForm: TCustomForm; + Children: TFPList; // of TCDWinControl; + // painting objects + Image: TLazIntfImage; + Canvas: TLazCanvas; + end; + +// Routines for non-native form + +procedure InitNonNativeForms(); +function GetCurrentForm(): TCDNonNativeForm; +function AddNewForm(AForm: TCustomForm): TCDNonNativeForm; +procedure ShowForm(ACDForm: TCDNonNativeForm); +procedure HideForm(ACDForm: TCDNonNativeForm); + +// Routines for non-native wincontrol + procedure UpdateControlLazImageAndCanvas(var AImage: TLazIntfImage; - var ACanvas: TLazCanvas; AWidth, AHeight: Integer; AFormat: TUpdateLazImageFormat); + var ACanvas: TLazCanvas; AWidth, AHeight: Integer; AFormat: TUpdateLazImageFormat; + AData: Pointer = nil); procedure RenderChildWinControls(var AImage: TLazIntfImage; var ACanvas: TLazCanvas; ACDControlsList: TFPList); //procedure RenderWinControl(var AImage: TLazIntfImage; // var ACanvas: TLazCanvas; ACDControlsList: TFPList); function FindControlWhichReceivedEvent(AForm: TCustomForm; AControlsList: TFPList; AX, AY: Integer): TWinControl; + +// Other routines + function DateTimeToMilliseconds(aDateTime: TDateTime): Int64; function IsValidDC(ADC: HDC): Boolean; function IsValidGDIObject(AGDIObj: HGDIOBJ): Boolean; implementation +// List with the Z-order of non-native forms, index=0 is the bottom-most form +var + NonNativeForms: TFPList = nil; + +procedure InitNonNativeForms(); +begin + if NonNativeForms <> nil then Exit; + NonNativeForms := TFPList.Create; +end; + +function GetCurrentForm(): TCDNonNativeForm; +var + lCount: Integer; +begin + {$IFDEF VerboseWinAPI} + DebugLn('GetCurrentForm'); + {$ENDIF} + InitNonNativeForms(); + lCount := NonNativeForms.Count; + if lCount = 0 then Result := nil + else Result := TCDNonNativeForm(NonNativeForms.Items[lCount-1]); +end; + +function AddNewForm(AForm: TCustomForm): TCDNonNativeForm; +var + lFormInfo: TCDNonNativeForm; +begin + {$IFDEF VerboseWinAPI} + DebugLn('AddNewForm'); + {$ENDIF} + InitNonNativeForms(); + lFormInfo := TCDNonNativeForm.Create; + lFormInfo.LCLForm := AForm; + lFormInfo.Children := TFPList.Create; + NonNativeForms.Insert(0, lFormInfo); +end; + +procedure ShowForm(ACDForm: TCDNonNativeForm); +var + lCount, lCurIndex: Integer; +begin + {$IFDEF VerboseWinAPI} + DebugLn('ShowForm'); + {$ENDIF} + InitNonNativeForms(); + lCount := NonNativeForms.Count; + lCurIndex := NonNativeForms.IndexOf(ACDForm); + NonNativeForms.Move(lCurIndex, lCount-1); +end; + +procedure HideForm(ACDForm: TCDNonNativeForm); +var + lCount, lCurIndex: Integer; +begin + InitNonNativeForms(); + lCount := NonNativeForms.Count; + lCurIndex := NonNativeForms.IndexOf(ACDForm); + NonNativeForms.Move(lCurIndex, 0); +end; + procedure UpdateControlLazImageAndCanvas(var AImage: TLazIntfImage; - var ACanvas: TLazCanvas; AWidth, AHeight: Integer; AFormat: TUpdateLazImageFormat); + var ACanvas: TLazCanvas; AWidth, AHeight: Integer; AFormat: TUpdateLazImageFormat; + AData: Pointer = nil); var lRawImage: TRawImage; + lPixelSize: Byte; begin {$IFDEF VerboseWinAPI} DebugLn(Format(':>[UpdateControlLazImageAndCanvas] Input Image: %x Canvas: %x', @@ -62,7 +147,22 @@ begin clfBGR24: lRawImage.Description.Init_BPP24_B8G8R8_BIO_TTB(AWidth, AHeight); clfBGRA32: lRawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(AWidth, AHeight); end; - lRawImage.CreateData(True); + + // Now connect the pixel buffer or create one + if AData = nil then lRawImage.CreateData(True) + else + begin + case AFormat of + clfRGB16_R5G6B5: lPixelSize := 2; + clfRGB24: lPixelSize := 3; + clfRGB24UpsideDown: lPixelSize := 3; + clfBGR24: lPixelSize := 3; + clfBGRA32: lPixelSize := 4; + end; + + lRawImage.Data := AData; + lRawImage.DataSize := AWidth * lPixelSize * AHeight; + end; AImage := TLazIntfImage.Create(AWidth, AHeight); AImage.SetRawImage(lRawImage); diff --git a/lcl/interfaces/customdrawn/customdrawnwsforms_android.inc b/lcl/interfaces/customdrawn/customdrawnwsforms_android.inc index 3d8fbd1100..d02b03270d 100644 --- a/lcl/interfaces/customdrawn/customdrawnwsforms_android.inc +++ b/lcl/interfaces/customdrawn/customdrawnwsforms_android.inc @@ -33,16 +33,17 @@ var lWindowInfo: TAndroidWindowInfo; AForm: TCustomForm absolute AWinControl; begin - {$ifdef VerboseCDWindow} +(* {$ifdef VerboseCDWindow} DebugLn(Format(':>[TCDWSCustomForm.CreateHandle] AWinControl=%x Name=%s: %s', [PtrInt(AWinControl), AWinControl.Name, AWinControl.ClassName])); - {$endif} + {$endif}*) + Result := TLCLIntfhandle(AddNewForm(TCustomForm(AWinControl))); - {$ifdef VerboseCDWindow} +(* {$ifdef VerboseCDWindow} DebugLn(Format(':<[TCDWSCustomForm.CreateHandle] Result=%x', [Result])); - {$endif} + {$endif}*) end; class procedure TCDWSCustomForm.DestroyHandle(const AWinControl: TWinControl); @@ -90,16 +91,18 @@ begin if AWinControl.Visible then begin - {$ifdef VerboseCDWindow} + ShowForm(TCDNonNativeForm(AWinControl.Handle)); +(* {$ifdef VerboseCDWindow} DebugLn(Format('[TCDWSCustomForm.ShowHide] Visible=True AWinControl=%x Handle=%x', [PtrInt(AWinControl), PtrInt(AWinControl.Handle)])); - {$endif} + {$endif}*) end else begin - {$ifdef VerboseCDWindow} + HideForm(TCDNonNativeForm(AWinControl.Handle)); +(* {$ifdef VerboseCDWindow} DebugLn(Format('[TCDWSCustomForm.ShowHide] Visible=False AWinControl=%x', [PtrInt(AWinControl)])); - {$endif} + {$endif}*) end; end;