changeset 2994:8311be624877

Mac/iOS: Implement DW_FEATURE_RENDER_SAFE. iOS always operates in safe render mode. Mac defaults to disabled, enabling will enforce expose event restrictions on drawing to render widgets.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Wed, 03 May 2023 23:29:17 +0000
parents 392f0b3dd502
children a74b30a9d744
files ios/dw.m mac/dw.m
diffstat 2 files changed, 134 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/ios/dw.m	Tue May 02 11:37:48 2023 +0000
+++ b/ios/dw.m	Wed May 03 23:29:17 2023 +0000
@@ -12262,6 +12262,7 @@
         case DW_FEATURE_MLE_WORD_WRAP:
         case DW_FEATURE_UTF8_UNICODE:
         case DW_FEATURE_TREE:
+        case DW_FEATURE_RENDER_SAFE:
             return DW_FEATURE_ENABLED;
         case DW_FEATURE_CONTAINER_MODE:
             return _dw_container_mode;
@@ -12313,6 +12314,7 @@
         case DW_FEATURE_MLE_WORD_WRAP:
         case DW_FEATURE_UTF8_UNICODE:
         case DW_FEATURE_TREE:
+        case DW_FEATURE_RENDER_SAFE:
             return DW_ERROR_GENERAL;
         case DW_FEATURE_CONTAINER_MODE:
         {
--- a/mac/dw.m	Tue May 02 11:37:48 2023 +0000
+++ b/mac/dw.m	Wed May 03 23:29:17 2023 +0000
@@ -521,6 +521,22 @@
 static int DWOSMajor, DWOSMinor, DWOSBuild;
 static char _dw_bundle_path[PATH_MAX+1] = { 0 };
 static char _dw_app_id[_DW_APP_ID_SIZE+1]= {0};
+static int _dw_render_safe_mode = DW_FEATURE_DISABLED;
+static id _dw_render_expose = nil;
+
+/* Return TRUE if it is safe to draw on the window handle.
+ * Either we are in unsafe mode, or we are in an EXPOSE
+ * event for the requested render window handle.
+ */
+int _dw_render_safe_check(id handle)
+{
+    if(_dw_render_safe_mode == DW_FEATURE_DISABLED || 
+       (handle && _dw_render_expose == handle))
+           return TRUE;
+    return FALSE;
+}
+
+int _dw_is_render(id handle);
 
 /* Create a default colors for a thread */
 void _dw_init_colors(void)
@@ -732,12 +748,17 @@
                 DWExpose exp;
                 int (* API exposefunc)(HWND, DWExpose *, void *) = (int (* API)(HWND, DWExpose *, void *))handler->signalfunction;
                 NSRect rect = [object frame];
+                id oldrender = _dw_render_expose;
 
                 exp.x = rect.origin.x;
                 exp.y = rect.origin.y;
                 exp.width = rect.size.width;
                 exp.height = rect.size.height;
+                /* The render expose is only valid for render class windows */
+                if(_dw_is_render(object))
+                    _dw_render_expose = object;
                 int result = exposefunc(object, &exp, handler->data);
+                _dw_render_expose = oldrender;
 #ifndef BUILDING_FOR_MOJAVE
                 [[object window] flushWindow];
 #endif
@@ -1263,6 +1284,14 @@
 -(BOOL)acceptsFirstResponder { return YES; }
 @end
 
+/* So we can check before DWRender is declared */
+int _dw_is_render(id handle)
+{
+    if([handle isMemberOfClass:[DWRender class]])
+        return TRUE;
+    return FALSE;
+}
+
 @implementation DWObject
 -(void)uselessThread:(id)sender { /* Thread only to initialize threading */ }
 #ifndef BUILDING_FOR_MOJAVE
@@ -7004,17 +7033,22 @@
         bi = (id)pixmap->image;
     else
     {
+        if(_dw_render_safe_check(handle))
+        {
 #ifdef BUILDING_FOR_MOJAVE
-        if([image isMemberOfClass:[DWRender class]])
-        {
-            DWRender *render = image;
-
-            bi = [render cachedDrawingRep];
-        }
+            if([image isMemberOfClass:[DWRender class]])
+            {
+                DWRender *render = image;
+
+                bi = [render cachedDrawingRep];
+            }
 #else
-        if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
-            _DWLastDrawable = handle;
-#endif
+            if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
+                _DWLastDrawable = handle;
+#endif
+        } 
+        else
+            bCanDraw = NO;
     }
     if(bi)
     {
@@ -7068,17 +7102,22 @@
         bi = (id)pixmap->image;
     else
     {
+        if(_dw_render_safe_check(handle))
+        {
 #ifdef BUILDING_FOR_MOJAVE
-        if([image isMemberOfClass:[DWRender class]])
-        {
-            DWRender *render = image;
-
-            bi = [render cachedDrawingRep];
-        }
+            if([image isMemberOfClass:[DWRender class]])
+            {
+                DWRender *render = image;
+
+                bi = [render cachedDrawingRep];
+            }
 #else
-        if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
-            _DWLastDrawable = handle;
-#endif
+            if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
+                _DWLastDrawable = handle;
+#endif
+        }
+        else
+            bCanDraw = NO;
     }
     if(bi)
     {
@@ -7143,14 +7182,19 @@
     }
     else if(image && [image isMemberOfClass:[DWRender class]])
     {
-        render = image;
-        font = [render font];
+        if(_dw_render_safe_check(handle))
+        {
+            render = image;
+            font = [render font];
 #ifdef BUILDING_FOR_MOJAVE
-        bi = [render cachedDrawingRep];
+            bi = [render cachedDrawingRep];
 #else
-        if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
-            _DWLastDrawable = handle;
-#endif
+            if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
+                _DWLastDrawable = handle;
+#endif
+        }
+        else
+            bCanDraw = NO;
     }
     if(bi)
     {
@@ -7275,20 +7319,25 @@
         bi = (id)pixmap->image;
     else
     {
+        if(_dw_render_safe_check(handle))
+        {
 #ifdef BUILDING_FOR_MOJAVE
-        if([image isMemberOfClass:[DWRender class]])
-        {
-            DWRender *render = image;
-
-            bi = [render cachedDrawingRep];
-        }
+            if([image isMemberOfClass:[DWRender class]])
+            {
+                DWRender *render = image;
+
+                bi = [render cachedDrawingRep];
+            }
 #else
-        if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
-        {
-            _DWLastDrawable = handle;
-            [[NSGraphicsContext currentContext] setShouldAntialias:(flags & DW_DRAW_NOAA ? NO : YES)];
-        }
-#endif
+            if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
+            {
+                _DWLastDrawable = handle;
+                [[NSGraphicsContext currentContext] setShouldAntialias:(flags & DW_DRAW_NOAA ? NO : YES)];
+            }
+#endif
+        }
+        else
+            bCanDraw = NO;
     }
     if(bi)
     {
@@ -7354,20 +7403,25 @@
         bi = (id)pixmap->image;
     else
     {
+        if(_dw_render_safe_check(handle))
+        {
 #ifdef BUILDING_FOR_MOJAVE
-        if([image isMemberOfClass:[DWRender class]])
-        {
-            DWRender *render = image;
-
-            bi = [render cachedDrawingRep];
-        }
+            if([image isMemberOfClass:[DWRender class]])
+            {
+                DWRender *render = image;
+
+                bi = [render cachedDrawingRep];
+            }
 #else
-        if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
-        {
-            _DWLastDrawable = handle;
-            [[NSGraphicsContext currentContext] setShouldAntialias:(flags & DW_DRAW_NOAA ? NO : YES)];
-        }
-#endif
+            if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
+            {
+                _DWLastDrawable = handle;
+                [[NSGraphicsContext currentContext] setShouldAntialias:(flags & DW_DRAW_NOAA ? NO : YES)];
+            }
+#endif
+        }
+        else
+            bCanDraw = NO;
     }
     if(bi)
     {
@@ -7428,20 +7482,25 @@
         bi = (id)pixmap->image;
     else
     {
+        if(_dw_render_safe_check(handle))
+        {
 #ifdef BUILDING_FOR_MOJAVE
-        if([image isMemberOfClass:[DWRender class]])
-        {
-            DWRender *render = image;
-
-            bi = [render cachedDrawingRep];
-        }
+            if([image isMemberOfClass:[DWRender class]])
+            {
+                DWRender *render = image;
+
+                bi = [render cachedDrawingRep];
+            }
 #else
-        if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
-        {
-            _DWLastDrawable = handle;
-            [[NSGraphicsContext currentContext] setShouldAntialias:(flags & DW_DRAW_NOAA ? NO : YES)];
-        }
-#endif
+            if((bCanDraw = [image lockFocusIfCanDraw]) == YES)
+            {
+                _DWLastDrawable = handle;
+                [[NSGraphicsContext currentContext] setShouldAntialias:(flags & DW_DRAW_NOAA ? NO : YES)];
+            }
+#endif
+        }
+        else
+            bCanDraw = NO;
     }
     if(bi)
     {
@@ -9284,7 +9343,8 @@
 
     /* Sanity checks */
     if((!dest && !destp) || (!src && !srcp) ||
-       ((srcwidth == -1 || srcheight == -1) && srcwidth != srcheight))
+       ((srcwidth == -1 || srcheight == -1) && srcwidth != srcheight) ||
+           (dest && !_dw_render_safe_check(dest)))
     {
         DW_LOCAL_POOL_OUT;
         return DW_ERROR_GENERAL;
@@ -13477,6 +13537,8 @@
         case DW_FEATURE_TREE:
         case DW_FEATURE_WINDOW_PLACEMENT:
             return DW_FEATURE_ENABLED;
+        case DW_FEATURE_RENDER_SAFE:
+            return _dw_render_safe_mode;
 #ifdef BUILDING_FOR_MOJAVE
         case DW_FEATURE_DARK_MODE:
         {
@@ -13562,6 +13624,15 @@
         case DW_FEATURE_WINDOW_PLACEMENT:
             return DW_ERROR_GENERAL;
         /* These features are supported and configurable */
+        case DW_FEATURE_RENDER_SAFE:
+        {
+            if (state == DW_FEATURE_ENABLED || state == DW_FEATURE_DISABLED)
+            {
+                _dw_render_safe_mode = state;
+                return DW_ERROR_NONE;
+            }
+            return DW_ERROR_GENERAL;
+        }
 #ifdef BUILDING_FOR_MOJAVE
         case DW_FEATURE_DARK_MODE:
         {