* On iOS, fix support for the case where [UIScreen scale] is not 1.0 (retina)
authorTim Angus <tim@blackcompanystudios.co.uk>
Wed, 25 Jan 2012 14:29:56 +0000
changeset 6267 ed2cf4669e55
parent 6266 a4be1e781020
child 6268 3aa24ec6bc39
* On iOS, fix support for the case where [UIScreen scale] is not 1.0 (retina) * Allow selection of non-retina modes on retina devices
src/video/uikit/SDL_uikitopengles.m
src/video/uikit/SDL_uikitopenglview.h
src/video/uikit/SDL_uikitopenglview.m
src/video/uikit/SDL_uikitvideo.h
src/video/uikit/SDL_uikitvideo.m
src/video/uikit/SDL_uikitviewcontroller.m
src/video/uikit/SDL_uikitwindow.h
src/video/uikit/SDL_uikitwindow.m
--- a/src/video/uikit/SDL_uikitopengles.m	Sun Jan 22 23:51:46 2012 -0500
+++ b/src/video/uikit/SDL_uikitopengles.m	Wed Jan 25 14:29:56 2012 +0000
@@ -103,10 +103,14 @@
 {
     SDL_uikitopenglview *view;
     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+    SDL_DisplayData *displaydata = display->driverdata;
+    SDL_DisplayModeData *displaymodedata = display->current_mode.driverdata;
     UIWindow *uiwindow = data->uiwindow;
 
     /* construct our view, passing in SDL's OpenGL configuration data */
     view = [[SDL_uikitopenglview alloc] initWithFrame: [uiwindow bounds]
+                                    scale: displaymodedata->scale
                                     retainBacking: _this->gl_config.retained_backing
                                     rBits: _this->gl_config.red_size
                                     gBits: _this->gl_config.green_size
@@ -135,9 +139,10 @@
     }
 
     /* Make this window the current mouse focus for touch input */
-    /* !!! FIXME: only do this if this is the primary screen. */
-    SDL_SetMouseFocus(window);
-    SDL_SetKeyboardFocus(window);
+    if (displaydata->uiscreen == [UIScreen mainScreen]) {
+        SDL_SetMouseFocus(window);
+        SDL_SetKeyboardFocus(window);
+    }
 
     return view;
 }
--- a/src/video/uikit/SDL_uikitopenglview.h	Sun Jan 22 23:51:46 2012 -0500
+++ b/src/video/uikit/SDL_uikitopenglview.h	Wed Jan 25 14:29:56 2012 +0000
@@ -54,6 +54,7 @@
 - (void)setCurrentContext;
 
 - (id)initWithFrame:(CGRect)frame
+    scale:(CGFloat)scale
     retainBacking:(BOOL)retained
     rBits:(int)rBits
     gBits:(int)gBits
--- a/src/video/uikit/SDL_uikitopenglview.m	Sun Jan 22 23:51:46 2012 -0500
+++ b/src/video/uikit/SDL_uikitopenglview.m	Wed Jan 25 14:29:56 2012 +0000
@@ -37,6 +37,7 @@
 }
 
 - (id)initWithFrame:(CGRect)frame
+      scale:(CGFloat)scale
       retainBacking:(BOOL)retained
       rBits:(int)rBits
       gBits:(int)gBits
@@ -79,10 +80,9 @@
             return nil;
         }
 
-        // !!! FIXME: use the screen this is on!
-        /* Use the main screen scale (for retina display support) */
+        /* Set the appropriate scale (for retina display support) */
         if ([self respondsToSelector:@selector(contentScaleFactor)])
-            self.contentScaleFactor = [UIScreen mainScreen].scale;
+            self.contentScaleFactor = scale;
 
         /* create the buffers */
         glGenFramebuffersOES(1, &viewFramebuffer);
--- a/src/video/uikit/SDL_uikitvideo.h	Sun Jan 22 23:51:46 2012 -0500
+++ b/src/video/uikit/SDL_uikitvideo.h	Wed Jan 25 14:29:56 2012 +0000
@@ -25,6 +25,22 @@
 
 extern BOOL SDL_UIKit_supports_multiple_displays;
 
+typedef struct SDL_DisplayData SDL_DisplayData;
+
+struct SDL_DisplayData
+{
+    UIScreen *uiscreen;
+    CGFloat scale;
+};
+
+typedef struct SDL_DisplayModeData SDL_DisplayModeData;
+
+struct SDL_DisplayModeData
+{
+    UIScreenMode *uiscreenmode;
+    CGFloat scale;
+};
+
 #endif /* _SDL_uikitvideo_h */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/uikit/SDL_uikitvideo.m	Sun Jan 22 23:51:46 2012 -0500
+++ b/src/video/uikit/SDL_uikitvideo.m	Wed Jan 25 14:29:56 2012 +0000
@@ -120,79 +120,167 @@
 
 */
 
+static int
+UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
+    UIScreenMode * uiscreenmode, CGFloat scale)
+{
+    SDL_DisplayMode mode;
+    SDL_zero(mode);
+    
+    SDL_DisplayModeData *data = NULL;
+
+    if (uiscreenmode != nil) {
+        /* Allocate the display mode data */
+        data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
+        if (!data) {
+            SDL_OutOfMemory();
+            return -1;
+        }
+        
+        data->uiscreenmode = uiscreenmode;
+        data->scale = scale;
+    }
+    
+    mode.format = SDL_PIXELFORMAT_ABGR8888;
+    mode.refresh_rate = 0;
+    mode.driverdata = data;
+    
+    mode.w = w;
+    mode.h = h;
+    if (SDL_AddDisplayMode(display, &mode)) {
+        if (uiscreenmode != nil) {
+            [uiscreenmode retain];
+        }
+        
+        return 0;
+    }
+    
+    SDL_free(data);
+
+    return -1;
+}
+
+static int
+UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale,
+                     UIScreenMode * uiscreenmode, BOOL rotated)
+{
+    if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode, scale) < 0) {
+        return -1;
+    }
+    
+    if (rotated) {
+        // Add the rotated version
+        if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode, scale) < 0) {
+            return -1;
+        }
+    }
+    
+    return 0;
+}
+
 static void
 UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
 {
-    UIScreen *uiscreen = (UIScreen *) display->driverdata;
-    SDL_DisplayMode mode;
-    SDL_zero(mode);
-
-    // availableModes showed up in 3.2 (the iPad and later). We should only
-    //  land here for at least that version of the OS.
-    if (!SDL_UIKit_supports_multiple_displays) {
-        const CGRect rect = [uiscreen bounds];
-        mode.format = SDL_PIXELFORMAT_ABGR8888;
-        mode.refresh_rate = 0;
-        mode.driverdata = NULL;
-
-        mode.w = (int) rect.size.width;
-        mode.h = (int) rect.size.height;
-        SDL_AddDisplayMode(display, &mode);
+    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
 
-        mode.w = (int) rect.size.height;  // swap the orientation, add again.
-        mode.h = (int) rect.size.width;
-        SDL_AddDisplayMode(display, &mode);
-        return;
-    }
-
-    for (UIScreenMode *uimode in [uiscreen availableModes]) {
-        CGSize size = [uimode size];
-        mode.format = SDL_PIXELFORMAT_ABGR8888;
-        mode.refresh_rate = 0;
-        mode.driverdata = uimode;
-        mode.w = (int) size.width;
-        mode.h = (int) size.height;
-        if (SDL_AddDisplayMode(display, &mode))
-            [uimode retain];        // retain is needed because of mode.driverdata
-
-        if (uiscreen == [UIScreen mainScreen]) {
-            // Add the mode with swapped width/height
-            mode.w = (int) size.height;
-            mode.h = (int) size.width;
-            if (SDL_AddDisplayMode(display, &mode))
-                [uimode retain];
+    if (SDL_UIKit_supports_multiple_displays) {
+        // availableModes showed up in 3.2 (the iPad and later). We should only
+        //  land here for at least that version of the OS.
+        for (UIScreenMode *uimode in [data->uiscreen availableModes]) {
+            BOOL mainscreen = (data->uiscreen == [UIScreen mainScreen]);
+            CGSize size = [uimode size];
+            int w = (int)size.width;
+            int h = (int)size.height;
+            
+            // Add the native screen resolution.
+            UIKit_AddDisplayMode(display, w, h, data->scale, uimode, mainscreen);
+            
+            if (data->scale != 1.0f) {
+                // Add the native screen resolution divided by its scale.
+                // This is so devices capable of e.g. 640x960 also advertise
+                // 320x480.
+                UIKit_AddDisplayMode(display,
+                    (int)(w / data->scale), (int)(h / data->scale),
+                    1.0f, uimode, mainscreen);
+            }
         }
-    }
+    } else {
+        const CGRect rect = [data->uiscreen bounds];
+        UIKit_AddDisplayMode(display,
+            (int)rect.size.width, (int)rect.size.height,
+            1.0f, nil, YES);
+    } 
 }
 
 
-static void
-UIKit_AddDisplay(UIScreen *uiscreen, int w, int h)
+static int
+UIKit_AddDisplay(UIScreen *uiscreen, CGSize size)
 {
+    // When dealing with UIKit all coordinates are specified in terms of
+    // what Apple refers to as points. On earlier devices without the
+    // so called "Retina" display, there is a one to one mapping between
+    // points and pixels. In other cases [UIScreen scale] indicates the
+    // relationship between points and pixels. Since SDL has no notion
+    // of points, we must compensate in all cases where dealing with such
+    // units.
+    CGFloat scale;
+    if ([UIScreen instancesRespondToSelector:@selector(scale)]) {
+        scale = [uiscreen scale]; // iOS >= 4.0
+    } else {
+        scale = 1.0f; // iOS < 4.0
+    }
+	
     SDL_VideoDisplay display;
     SDL_DisplayMode mode;
     SDL_zero(mode);
     mode.format = SDL_PIXELFORMAT_ABGR8888;
-    mode.w = w;
-    mode.h = h;
+    mode.w = (int)(size.width * scale);
+    mode.h = (int)(size.height * scale);
     mode.refresh_rate = 0;
 
     // UIScreenMode showed up in 3.2 (the iPad and later). We're
     //  misusing this supports_multiple_displays flag here for that.
     if (SDL_UIKit_supports_multiple_displays) {
-        UIScreenMode *uimode = [uiscreen currentMode];
-        [uimode retain];  // once for the desktop_mode
-        [uimode retain];  // once for the current_mode
-        mode.driverdata = uimode;
+        SDL_DisplayModeData *data;
+        
+        /* Allocate the mode data */
+        data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
+        if (!data) {
+            SDL_OutOfMemory();
+            return -1;
+        }
+        
+        data->uiscreenmode = [uiscreen currentMode];
+        [data->uiscreenmode retain];  // once for the desktop_mode
+        [data->uiscreenmode retain];  // once for the current_mode
+        
+        data->scale = scale;
+
+        mode.driverdata = data;
     }
 
     SDL_zero(display);
     display.desktop_mode = mode;
     display.current_mode = mode;
+	
+    SDL_DisplayData *data;
 
+    /* Allocate the display data */
+    data = (SDL_DisplayData *) SDL_malloc(sizeof(*data));
+    if (!data) {
+        SDL_free(mode.driverdata);
+        SDL_OutOfMemory();
+        return -1;
+    }
+	
     [uiscreen retain];
-    display.driverdata = uiscreen;
+    data->uiscreen = uiscreen;
+    data->scale = scale;
+	
+    display.driverdata = data;
     SDL_AddVideoDisplay(&display);
+    
+    return 0;
 }
 
 
@@ -207,7 +295,10 @@
     // Add the main screen.
     UIScreen *uiscreen = [UIScreen mainScreen];
     const CGSize size = [uiscreen bounds].size;
-    UIKit_AddDisplay(uiscreen, (int)size.width, (int)size.height);
+
+    if (UIKit_AddDisplay(uiscreen, size) < 0) {
+        return -1;
+    }
 
     // If this is iPhoneOS < 3.2, all devices are one screen, 320x480 pixels.
     //  The iPad added both a larger main screen and the ability to use
@@ -217,7 +308,9 @@
             // Only add the other screens
             if (uiscreen != [UIScreen mainScreen]) {
                 const CGSize size = [uiscreen bounds].size;
-                UIKit_AddDisplay(uiscreen, (int)size.width, (int)size.height);
+                if (UIKit_AddDisplay(uiscreen, size) < 0) {
+                    return -1;
+                }
             }
         }
     }
@@ -229,15 +322,15 @@
 static int
 UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
 {
-    UIScreen *uiscreen = (UIScreen *) display->driverdata;
+    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
     if (!SDL_UIKit_supports_multiple_displays) {
         // Not on at least iPhoneOS 3.2 (versions prior to iPad).
         SDL_assert(mode->driverdata == NULL);
     } else {
-        UIScreenMode *uimode = (UIScreenMode *) mode->driverdata;
-        [uiscreen setCurrentMode:uimode];
+        SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
+        [data->uiscreen setCurrentMode:modedata->uiscreenmode];
 
-        CGSize size = [uimode size];
+        CGSize size = [modedata->uiscreenmode size];
         if (size.width >= size.height) {
             [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
         } else {
@@ -255,8 +348,9 @@
         // Not on at least iPhoneOS 3.2 (versions prior to iPad).
         SDL_assert(mode->driverdata == NULL);
     } else {
-        UIScreenMode *uimode = (UIScreenMode *) mode->driverdata;
-        [uimode release];
+        SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
+        [data->uiscreenmode release];
+        SDL_free(data);
         mode->driverdata = NULL;
     }
 }
@@ -268,8 +362,9 @@
     int i, j;
     for (i = 0; i < _this->num_displays; i++) {
         SDL_VideoDisplay *display = &_this->displays[i];
-        UIScreen *uiscreen = (UIScreen *) display->driverdata;
-        [uiscreen release];
+        SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
+        [data->uiscreen release];
+        SDL_free(data);
         display->driverdata = NULL;
         UIKit_ReleaseUIScreenMode(&display->desktop_mode);
         UIKit_ReleaseUIScreenMode(&display->current_mode);
--- a/src/video/uikit/SDL_uikitviewcontroller.m	Sun Jan 22 23:51:46 2012 -0500
+++ b/src/video/uikit/SDL_uikitviewcontroller.m	Wed Jan 25 14:29:56 2012 +0000
@@ -113,11 +113,10 @@
     const UIInterfaceOrientation toInterfaceOrientation = [self interfaceOrientation];
     SDL_WindowData *data = self->window->driverdata;
     UIWindow *uiwindow = data->uiwindow;
-    UIScreen *uiscreen;
-    if (SDL_UIKit_supports_multiple_displays)
-        uiscreen = [uiwindow screen];
-    else
-        uiscreen = [UIScreen mainScreen];
+    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(self->window);
+    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
+    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
+    UIScreen *uiscreen = displaydata->uiscreen;
     const int noborder = (self->window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS));
     CGRect frame = noborder ? [uiscreen bounds] : [uiscreen applicationFrame];
     const CGSize size = frame.size;
@@ -141,6 +140,9 @@
             return;
     }
 
+    w = (int)(w * displaymodedata->scale);
+    h = (int)(h * displaymodedata->scale);
+
     [uiwindow setFrame:frame];
     [data->view setFrame:frame];
     [data->view updateFrame];
--- a/src/video/uikit/SDL_uikitwindow.h	Sun Jan 22 23:51:46 2012 -0500
+++ b/src/video/uikit/SDL_uikitwindow.h	Wed Jan 25 14:29:56 2012 +0000
@@ -22,6 +22,7 @@
 #define _SDL_uikitwindow_h
 
 #include "../SDL_sysvideo.h"
+#import "SDL_uikitvideo.h"
 #import "SDL_uikitopenglview.h"
 #import "SDL_uikitviewcontroller.h"
 
--- a/src/video/uikit/SDL_uikitwindow.m	Sun Jan 22 23:51:46 2012 -0500
+++ b/src/video/uikit/SDL_uikitwindow.m	Wed Jan 25 14:29:56 2012 +0000
@@ -46,7 +46,8 @@
 static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
 {
     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
-    UIScreen *uiscreen = (UIScreen *) display->driverdata;
+    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
+    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
     SDL_WindowData *data;
 
     /* Allocate the window data */
@@ -64,24 +65,28 @@
         window->x = 0;
         window->y = 0;
 
+        /* Get frame dimensions in pixels */
+        int width = (int)(uiwindow.frame.size.width * displaymodedata->scale);
+        int height = (int)(uiwindow.frame.size.height * displaymodedata->scale);
+
         /* We can pick either width or height here and we'll rotate the
            screen to match, so we pick the closest to what we wanted.
          */
         if (window->w >= window->h) {
             if (uiwindow.frame.size.width > uiwindow.frame.size.height) {
-                window->w = (int)uiwindow.frame.size.width;
-                window->h = (int)uiwindow.frame.size.height;
+                window->w = width;
+                window->h = height;
             } else {
-                window->w = (int)uiwindow.frame.size.height;
-                window->h = (int)uiwindow.frame.size.width;
+                window->w = height;
+                window->h = width;
             }
         } else {
             if (uiwindow.frame.size.width > uiwindow.frame.size.height) {
-                window->w = (int)uiwindow.frame.size.height;
-                window->h = (int)uiwindow.frame.size.width;
+                window->w = height;
+                window->h = width;
             } else {
-                window->w = (int)uiwindow.frame.size.width;
-                window->h = (int)uiwindow.frame.size.height;
+                window->w = width;
+                window->h = height;
             }
         }
     }
@@ -95,7 +100,7 @@
     // SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
     // This is only set if the window is on the main screen. Other screens
     //  just force the window to have the borderless flag.
-    if ([UIScreen mainScreen] != uiscreen) {
+    if ([UIScreen mainScreen] != displaydata->uiscreen) {
         window->flags &= ~SDL_WINDOW_RESIZABLE;  // window is NEVER resizeable
         window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  // never has input focus
         window->flags |= SDL_WINDOW_BORDERLESS;  // never has a status bar.
@@ -131,8 +136,8 @@
 UIKit_CreateWindow(_THIS, SDL_Window *window)
 {
     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
-    UIScreen *uiscreen = (UIScreen *) display->driverdata;
-    const BOOL external = ([UIScreen mainScreen] != uiscreen);
+    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
+    const BOOL external = ([UIScreen mainScreen] != data->uiscreen);
 
     // SDL currently puts this window at the start of display's linked list. We rely on this.
     SDL_assert(_this->windows == window);
@@ -154,7 +159,7 @@
     //  user, so it's in standby), try to force the display to a resolution
     //  that most closely matches the desired window size.
     if (SDL_UIKit_supports_multiple_displays) {
-        const CGSize origsize = [[uiscreen currentMode] size];
+        const CGSize origsize = [[data->uiscreen currentMode] size];
         if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
             if (display->num_display_modes == 0) {
                 _this->GetDisplayModes(_this, display);
@@ -169,8 +174,8 @@
             }
 
             if (bestmode) {
-                UIScreenMode *uimode = (UIScreenMode *) bestmode->driverdata;
-                [uiscreen setCurrentMode:uimode];
+                SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata;
+                [data->uiscreen setCurrentMode:modedata->uiscreenmode];
 
                 // desktop_mode doesn't change here (the higher level will
                 //  use it to set all the screens back to their defaults
@@ -186,16 +191,16 @@
     // !!! FIXME: can we have a smaller view?
     UIWindow *uiwindow = [UIWindow alloc];
     if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS))
-        uiwindow = [uiwindow initWithFrame:[uiscreen bounds]];
+        uiwindow = [uiwindow initWithFrame:[data->uiscreen bounds]];
     else
-        uiwindow = [uiwindow initWithFrame:[uiscreen applicationFrame]];
+        uiwindow = [uiwindow initWithFrame:[data->uiscreen applicationFrame]];
 
     // put the window on an external display if appropriate. This implicitly
     //  does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
     //  main display, where we land by default, as that would eat the
     //  status bar real estate.
     if (external) {
-        [uiwindow setScreen:uiscreen];
+        [uiwindow setScreen:data->uiscreen];
     }
 
     if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
@@ -210,35 +215,40 @@
 void
 UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
 {
-    UIScreen *uiscreen = (UIScreen *) display->driverdata;
+    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
+    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
     UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
 
     if (fullscreen) {
         [UIApplication sharedApplication].statusBarHidden = YES;
-        uiwindow.frame = [uiscreen bounds];
+        uiwindow.frame = [displaydata->uiscreen bounds];
     } else {
         [UIApplication sharedApplication].statusBarHidden = NO;
-        uiwindow.frame = [uiscreen applicationFrame];
+        uiwindow.frame = [displaydata->uiscreen applicationFrame];
     }
 
+    /* Get frame dimensions in pixels */
+    int width = (int)(uiwindow.frame.size.width * displaymodedata->scale);
+    int height = (int)(uiwindow.frame.size.height * displaymodedata->scale);
+
     /* We can pick either width or height here and we'll rotate the
        screen to match, so we pick the closest to what we wanted.
      */
     if (window->w >= window->h) {
         if (uiwindow.frame.size.width > uiwindow.frame.size.height) {
-            window->w = (int)uiwindow.frame.size.width;
-            window->h = (int)uiwindow.frame.size.height;
+            window->w = width;
+            window->h = height;
         } else {
-            window->w = (int)uiwindow.frame.size.height;
-            window->h = (int)uiwindow.frame.size.width;
+            window->w = height;
+            window->h = width;
         }
     } else {
         if (uiwindow.frame.size.width > uiwindow.frame.size.height) {
-            window->w = (int)uiwindow.frame.size.height;
-            window->h = (int)uiwindow.frame.size.width;
+            window->w = height;
+            window->h = width;
         } else {
-            window->w = (int)uiwindow.frame.size.width;
-            window->h = (int)uiwindow.frame.size.height;
+            window->w = width;
+            window->h = height;
         }
     }
 }