Skip to content

Commit ee82140

Browse files
authored
Enable native iOS screenshot support (#4114)
* Enable native iOS screenshot support * Fix iOS screenshot thread state handling * Refine iOS screenshot dispatch handling * Ensure iOS fallback screenshot returns an image * Ensure iOS screenshots return mutable images * Remove Java fallback for iOS screenshots * Update MainActivity.png
1 parent ce006aa commit ee82140

File tree

4 files changed

+117
-30
lines changed

4 files changed

+117
-30
lines changed

Ports/iOSPort/nativeSources/IOSNative.m

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#import "CN1AudioUnit.h"
3838
#import <UIKit/UIKit.h>
3939
#import "CodenameOne_GLViewController.h"
40+
#import <QuartzCore/QuartzCore.h>
4041
#import "NetworkConnectionImpl.h"
4142
#include "com_codename1_impl_ios_IOSImplementation.h"
4243
#include "com_codename1_ui_Display.h"
@@ -5193,12 +5194,16 @@ void com_codename1_impl_ios_IOSNative_updatePersonWithRecordID___int_com_codenam
51935194
#endif
51945195
}
51955196

5196-
/*static UIImage* cn1_captureView(UIView *view) {
5197+
static UIImage* cn1_captureView(UIView *view) {
5198+
if (view == nil) {
5199+
return nil;
5200+
}
51975201
CGSize size = view.bounds.size;
5198-
if (size.width <= 0 || size.height <= 0) return nil;
5202+
if (size.width <= 0 || size.height <= 0) {
5203+
return nil;
5204+
}
51995205

5200-
// Prefer drawViewHierarchyInRect (renders with effects), fallback to CALayer
5201-
UIGraphicsBeginImageContextWithOptions(size, view.opaque, 0.0); // scale=0 → device scale
5206+
UIGraphicsBeginImageContextWithOptions(size, view.opaque, 0.0);
52025207
BOOL ok = NO;
52035208
if ([view respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
52045209
ok = [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
@@ -5212,27 +5217,50 @@ void com_codename1_impl_ios_IOSNative_updatePersonWithRecordID___int_com_codenam
52125217
}
52135218

52145219
void com_codename1_impl_ios_IOSNative_screenshot__(CN1_THREAD_STATE_MULTI_ARG JAVA_OBJECT instanceObject) {
5215-
dispatch_async(dispatch_get_main_queue(), ^{
5220+
#ifdef NEW_CODENAME_ONE_VM
5221+
struct ThreadLocalData* capturedThreadStateData = threadStateData;
5222+
#endif
5223+
5224+
void (^performCapture)(void) = ^{
5225+
#ifdef NEW_CODENAME_ONE_VM
5226+
struct ThreadLocalData* threadStateData = capturedThreadStateData;
5227+
#endif
5228+
POOL_BEGIN();
52165229
UIView *view = [CodenameOne_GLViewController instance].view;
52175230
UIImage *img = cn1_captureView(view);
5218-
if (!img) {
5219-
return;
5231+
NSData *png = nil;
5232+
if (img != nil) {
5233+
png = UIImagePNGRepresentation(img);
52205234
}
52215235

5222-
NSData *png = UIImagePNGRepresentation(img);
5223-
if (!png) {
5224-
return;
5236+
JAVA_OBJECT byteArr = JAVA_NULL;
5237+
if (png != nil) {
5238+
int len = (int)[png length];
5239+
if (len > 0) {
5240+
#ifndef NEW_CODENAME_ONE_VM
5241+
org_xmlvm_runtime_XMLVMArray* arr = XMLVMArray_createSingleDimension(__CLASS_byte, len);
5242+
memcpy(arr->fields.org_xmlvm_runtime_XMLVMArray.array_, [png bytes], len);
5243+
byteArr = arr;
5244+
#else
5245+
enteringNativeAllocations();
5246+
JAVA_OBJECT arr = __NEW_ARRAY_JAVA_BYTE(CN1_THREAD_STATE_PASS_ARG len);
5247+
memcpy(((JAVA_ARRAY)arr)->data, [png bytes], len);
5248+
finishedNativeAllocations();
5249+
byteArr = arr;
5250+
#endif
5251+
}
52255252
}
52265253

5227-
// Create Java byte[]
5228-
int len = (int)[png length];
5229-
JAVA_OBJECT byteArr = __NEW_ARRAY_JAVA_BYTE(CN1_THREAD_GET_STATE_PASS_ARG len);
5230-
5231-
memcpy((JAVA_ARRAY_BYTE*)((JAVA_ARRAY)byteArr)->data, (const jbyte*)[png bytes], len);
5254+
com_codename1_impl_ios_IOSImplementation_onScreenshot___byte_1ARRAY(CN1_THREAD_STATE_PASS_ARG byteArr);
5255+
POOL_END();
5256+
};
52325257

5233-
com_codename1_impl_ios_IOSImplementation_onScreenshot___byte_1ARRAY(CN1_THREAD_GET_STATE_PASS_ARG byteArr);
5234-
});
5235-
}*/
5258+
if ([NSThread isMainThread]) {
5259+
performCapture();
5260+
} else {
5261+
dispatch_async(dispatch_get_main_queue(), performCapture);
5262+
}
5263+
}
52365264

52375265

52385266
JAVA_LONG com_codename1_impl_ios_IOSNative_getPersonWithRecordID___int(CN1_THREAD_STATE_MULTI_ARG JAVA_OBJECT instanceObject, JAVA_INT recId) {

Ports/iOSPort/src/com/codename1/impl/ios/IOSImplementation.java

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import com.codename1.location.Location;
3434
import com.codename1.ui.Component;
3535
import com.codename1.ui.Display;
36-
import com.codename1.ui.EncodedImage;
3736
import com.codename1.ui.Font;
3837
import com.codename1.ui.Image;
3938
import com.codename1.ui.PeerComponent;
@@ -113,7 +112,6 @@
113112

114113
import java.io.ByteArrayInputStream;
115114
import java.io.ByteArrayOutputStream;
116-
import java.util.Arrays;
117115
import java.util.Collections;
118116
import com.codename1.ui.plaf.DefaultLookAndFeel;
119117

@@ -301,24 +299,85 @@ public void addCookie(Cookie c) {
301299
}
302300
}
303301

304-
/*private static SuccessCallback<Image> screenshotCallback;
302+
private static SuccessCallback<Image> screenshotCallback;
305303

306304
@Override
307-
public void screenshot(SuccessCallback<Image> callback) {
308-
screenshotCallback = callback;
309-
nativeInstance.screenshot();
310-
}
305+
public void screenshot(final SuccessCallback<Image> callback) {
306+
if (callback == null) {
307+
return;
308+
}
311309

312-
static void onScreenshot(final byte[] imageData) {
313-
if(screenshotCallback != null) {
310+
if (screenshotCallback != null) {
311+
Log.p("Screenshot request ignored: another capture is already in progress.");
314312
Display.getInstance().callSerially(new Runnable() {
315313
@Override
316314
public void run() {
317-
screenshotCallback.onSucess(EncodedImage.createImage(imageData));
315+
callback.onSucess(null);
318316
}
319317
});
318+
return;
320319
}
321-
}*/
320+
321+
screenshotCallback = callback;
322+
try {
323+
nativeInstance.screenshot();
324+
} catch (Throwable t) {
325+
screenshotCallback = null;
326+
Log.e(t);
327+
Display.getInstance().callSerially(new Runnable() {
328+
@Override
329+
public void run() {
330+
callback.onSucess(null);
331+
}
332+
});
333+
}
334+
}
335+
336+
static void onScreenshot(final byte[] imageData) {
337+
final SuccessCallback<Image> callback = screenshotCallback;
338+
screenshotCallback = null;
339+
if (callback == null) {
340+
return;
341+
}
342+
343+
Display.getInstance().callSerially(new Runnable() {
344+
@Override
345+
public void run() {
346+
if (imageData != null && imageData.length > 0) {
347+
try {
348+
Image image = Image.createImage(imageData, 0, imageData.length);
349+
if (image != null) {
350+
if (image.getGraphics() == null) {
351+
int width = Math.max(1, image.getWidth());
352+
int height = Math.max(1, image.getHeight());
353+
try {
354+
int[] rgb = image.getRGB();
355+
if (rgb != null && rgb.length >= width * height) {
356+
Image mutable = Image.createImage(rgb, width, height);
357+
if (mutable != null && mutable.getGraphics() != null) {
358+
image = mutable;
359+
}
360+
}
361+
} catch (OutOfMemoryError oom) {
362+
Log.e(oom);
363+
} catch (Throwable t) {
364+
Log.e(t);
365+
}
366+
}
367+
368+
if (image != null && image.getGraphics() != null) {
369+
callback.onSucess(image);
370+
return;
371+
}
372+
}
373+
} catch (Throwable t) {
374+
Log.e(t);
375+
}
376+
}
377+
callback.onSucess(null);
378+
}
379+
});
380+
}
322381

323382
/**
324383
* Used to enable/disable native cookies from native code.

Ports/iOSPort/src/com/codename1/impl/ios/IOSNative.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ native void nativeSetTransformMutable(
691691
// We go through java in order to use locking concurrency
692692
native void appendData(long peer, long data);
693693

694-
//native void screenshot();
694+
native void screenshot();
695695

696696
native void fillPolygonGlobal(int color, int alpha, int[] xPoints, int[] yPoints, int nPoints);
697697

4.32 KB
Loading

0 commit comments

Comments
 (0)