Bug 1138288 - Refactor nsWindow/nsScreen for multiple screen/window case. r=mwu
authorHenry Chang <hchang@mozilla.com>
Thu, 30 Apr 2015 14:38:26 +0800
changeset 274167 c3446a630074076d92d324e74669c3ef3f18d27c
parent 274166 772d976eb3e8b985a8fff5f151c088bcae2e2183
child 274168 e9f75be97c2d359072b740f4d3aac22461f783a3
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu
bugs1138288
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1138288 - Refactor nsWindow/nsScreen for multiple screen/window case. r=mwu
widget/gonk/nsScreenManagerGonk.h
widget/gonk/nsWindow.cpp
--- a/widget/gonk/nsScreenManagerGonk.h
+++ b/widget/gonk/nsScreenManagerGonk.h
@@ -26,65 +26,88 @@
 class nsRunnable;
 class nsWindow;
 
 class nsScreenGonk : public nsBaseScreen
 {
     typedef mozilla::hal::ScreenConfiguration ScreenConfiguration;
 
 public:
-    nsScreenGonk();
+    nsScreenGonk(uint32_t aId, ANativeWindow* aNativeWindow);
+
     ~nsScreenGonk();
 
     NS_IMETHOD GetId(uint32_t* aId);
     NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
     NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
     NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth);
     NS_IMETHOD GetColorDepth(int32_t* aColorDepth);
     NS_IMETHOD GetRotation(uint32_t* aRotation);
     NS_IMETHOD SetRotation(uint32_t  aRotation);
 
+    uint32_t GetId();
+    nsIntRect GetRect();
+    float GetDpi();
+    ANativeWindow* GetNativeWindow();
     nsIntRect GetNaturalBounds();
     uint32_t EffectiveScreenRotation();
     ScreenConfiguration GetConfiguration();
+    bool IsPrimaryScreen();
 
     void RegisterWindow(nsWindow* aWindow);
     void UnregisterWindow(nsWindow* aWindow);
     void BringToTop(nsWindow* aWindow);
 
     const nsTArray<nsWindow*>& GetTopWindows() const
     {
         return mTopWindows;
     }
 
 protected:
-    nsIntRect mScreenBounds;
-    nsIntRect mVirtualBounds;
+    uint32_t mId;
+    int32_t mColorDepth;
+    android::sp<ANativeWindow> mNativeWindow;
+    float mDpi;
+    nsIntRect mNaturalBounds; // Screen bounds w/o rotation taken into account.
+    nsIntRect mVirtualBounds; // Screen bounds w/ rotation taken into account.
     uint32_t mScreenRotation;
     uint32_t mPhysicalScreenRotation;
     nsTArray<nsWindow*> mTopWindows;
 };
 
 class nsScreenManagerGonk final : public nsIScreenManager
 {
 public:
+    enum {
+        // TODO: Bug 1138287 will define more screen/display types.
+        PRIMARY_SCREEN_TYPE = 0,
+
+        // TODO: Maintain a mapping from type to id dynamically.
+        PRIMARY_SCREEN_ID = 0,
+    };
+
+public:
     nsScreenManagerGonk();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSISCREENMANAGER
 
     static already_AddRefed<nsScreenManagerGonk> GetInstance();
     static already_AddRefed<nsScreenGonk> GetPrimaryScreen();
 
     void Initialize();
     void DisplayEnabled(bool aEnabled);
 
+    void AddScreen(uint32_t aDisplayType);
+    void RemoveScreen(uint32_t aDisplayType);
+
 protected:
     ~nsScreenManagerGonk();
     void VsyncControl(bool aEnabled);
+    uint32_t GetIdFromType(uint32_t aDisplayType);
 
     bool mInitialized;
-    nsCOMPtr<nsIScreen> mOneScreen;
+    nsTArray<nsRefPtr<nsScreenGonk>> mScreens;
     nsRefPtr<nsRunnable> mScreenOnEvent;
     nsRefPtr<nsRunnable> mScreenOffEvent;
 };
 
 #endif /* nsScreenManagerGonk_h___ */
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -129,33 +129,34 @@ displayEnabledCallback(bool enabled)
 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
 
 nsWindow::nsWindow()
 {
     mFramebuffer = nullptr;
 
     nsRefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance();
     screenManager->Initialize();
-    mScreen = nsScreenManagerGonk::GetPrimaryScreen();
 
     // This is a hack to force initialization of the compositor
     // resources, if we're going to use omtc.
     //
     // NB: GetPlatform() will create the gfxPlatform, which wants
     // to know the color depth, which asks our native window.
     // This has to happen after other init has finished.
     gfxPlatform::GetPlatform();
     if (!ShouldUseOffMainThreadCompositing()) {
         MOZ_CRASH("How can we render apps, then?");
     }
 }
 
 nsWindow::~nsWindow()
 {
-    HwcComposer2D::GetInstance()->SetCompositorParent(nullptr);
+    if (mScreen->IsPrimaryScreen()) {
+        HwcComposer2D::GetInstance()->SetCompositorParent(nullptr);
+    }
 }
 
 void
 nsWindow::DoDraw(void)
 {
     if (!hal::GetScreenEnabled()) {
         gDrawRequest = true;
         return;
@@ -392,38 +393,45 @@ nsWindow::SynthesizeNativeTouchPoint(uin
 }
 
 NS_IMETHODIMP
 nsWindow::Create(nsIWidget *aParent,
                  void *aNativeParent,
                  const nsIntRect &aRect,
                  nsWidgetInitData *aInitData)
 {
-    nsIntRect virtualBounds;
-    mScreen->GetRect(&virtualBounds.x, &virtualBounds.y,
-                     &virtualBounds.width, &virtualBounds.height);
-    BaseCreate(aParent, IS_TOPLEVEL() ? virtualBounds : aRect,
-               aInitData);
+    BaseCreate(aParent, aRect, aInitData);
+
+    nsCOMPtr<nsIScreen> screen;
+
+    uint32_t screenId = aParent ? ((nsWindow*)aParent)->mScreen->GetId() :
+                                  aInitData->mScreenId;
+
+    nsRefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance();
+    screenManager->ScreenForId(screenId, getter_AddRefs(screen));
+
+    mScreen = static_cast<nsScreenGonk*>(screen.get());
 
     mBounds = aRect;
 
     mParent = (nsWindow *)aParent;
     mVisible = false;
 
     if (!aParent) {
-        mBounds = virtualBounds;
+        mBounds = mScreen->GetRect();
     }
 
     if (!IS_TOPLEVEL()) {
         return NS_OK;
     }
 
     mScreen->RegisterWindow(this);
 
-    Resize(0, 0, virtualBounds.width, virtualBounds.height, false);
+    Resize(0, 0, mBounds.width, mBounds.height, false);
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::Destroy(void)
 {
     mOnDestroyCalled = true;
     mScreen->UnregisterWindow(this);
@@ -506,20 +514,17 @@ nsWindow::Resize(double aX,
 {
     mBounds = nsIntRect(NSToIntRound(aX), NSToIntRound(aY),
                         NSToIntRound(aWidth), NSToIntRound(aHeight));
     if (mWidgetListener) {
         mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
     }
 
     if (aRepaint) {
-        nsIntRect virtualBounds;
-        mScreen->GetRect(&virtualBounds.x, &virtualBounds.y,
-                         &virtualBounds.width, &virtualBounds.height);
-        Invalidate(virtualBounds);
+        Invalidate(mBounds);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::Enable(bool aState)
 {
@@ -533,17 +538,22 @@ nsWindow::IsEnabled() const
 }
 
 NS_IMETHODIMP
 nsWindow::SetFocus(bool aRaise)
 {
     if (aRaise) {
         BringToTop();
     }
-    gFocusedWindow = this;
+
+    if (!IS_TOPLEVEL() && mScreen->IsPrimaryScreen()) {
+        // We should only set focused window on non-toplevel primary window.
+        gFocusedWindow = this;
+    }
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>&)
 {
     return NS_OK;
 }
@@ -582,17 +592,17 @@ nsWindow::WidgetToScreenOffset()
 }
 
 void*
 nsWindow::GetNativeData(uint32_t aDataType)
 {
     switch (aDataType) {
     case NS_NATIVE_WINDOW:
         // Called before primary display's EGLSurface creation.
-        return GetGonkDisplay()->GetNativeWindow();
+        return mScreen->GetNativeWindow();
     }
     return nullptr;
 }
 
 void
 nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
 {
     switch (aDataType) {
@@ -743,17 +753,17 @@ nsWindow::EndRemoteDrawing()
     }
     mFramebuffer = nullptr;
     mFramebufferTarget = nullptr;
 }
 
 float
 nsWindow::GetDPI()
 {
-    return GetGonkDisplay()->xdpi;
+    return mScreen->GetDpi();
 }
 
 double
 nsWindow::GetDefaultScaleInternal()
 {
     float dpi = GetDPI();
     // The mean pixel density for mdpi devices is 160dpi, 240dpi for hdpi,
     // and 320dpi for xhdpi, respectively.
@@ -798,17 +808,17 @@ nsWindow::GetLayerManager(PLayerTransact
     nsWindow *topWindow = windows[0];
 
     if (!topWindow) {
         LOGW(" -- no topwindow\n");
         return nullptr;
     }
 
     CreateCompositor();
-    if (mCompositorParent) {
+    if (mCompositorParent && mScreen->IsPrimaryScreen()) {
         HwcComposer2D::GetInstance()->SetCompositorParent(mCompositorParent);
     }
     MOZ_ASSERT(mLayerManager);
     return mLayerManager;
 }
 
 void
 nsWindow::BringToTop()
@@ -821,20 +831,17 @@ nsWindow::BringToTop()
     }
 
     mScreen->BringToTop(this);
 
     if (mWidgetListener) {
         mWidgetListener->WindowActivated();
     }
 
-    nsIntRect virtualBounds;
-    mScreen->GetRect(&virtualBounds.x, &virtualBounds.y,
-                     &virtualBounds.width, &virtualBounds.height);
-    Invalidate(virtualBounds);
+    Invalidate(mBounds);
 }
 
 void
 nsWindow::UserActivity()
 {
     if (!mIdleService) {
         mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
     }
@@ -869,143 +876,183 @@ nsWindow::NeedsPaint()
     return false;
   }
   return nsIWidget::NeedsPaint();
 }
 
 Composer2D*
 nsWindow::GetComposer2D()
 {
+    if (!mScreen->IsPrimaryScreen()) {
+        return nullptr;
+    }
+
     return HwcComposer2D::GetInstance();
 }
 
+static uint32_t
+SurfaceFormatToColorDepth(int32_t aSurfaceFormat)
+{
+    switch (aSurfaceFormat) {
+    case GGL_PIXEL_FORMAT_RGB_565:
+        return 16;
+    case GGL_PIXEL_FORMAT_RGBA_8888:
+        return 32;
+    }
+    return 24; // GGL_PIXEL_FORMAT_RGBX_8888
+}
+
 // nsScreenGonk.cpp
 
-nsScreenGonk::nsScreenGonk()
-    : mScreenRotation(nsIScreen::ROTATION_0_DEG)
+nsScreenGonk::nsScreenGonk(uint32_t aId, ANativeWindow* aNativeWindow)
+    : mId(aId)
+    , mNativeWindow(aNativeWindow)
+    , mScreenRotation(nsIScreen::ROTATION_0_DEG)
     , mPhysicalScreenRotation(nsIScreen::ROTATION_0_DEG)
 {
-    nsIntSize screenSize;
-
-    ANativeWindow *win = GetGonkDisplay()->GetNativeWindow();
-    if (win->query(win, NATIVE_WINDOW_WIDTH, &screenSize.width) ||
-        win->query(win, NATIVE_WINDOW_HEIGHT, &screenSize.height)) {
+    int surfaceFormat;
+    if (mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &mVirtualBounds.width) ||
+        mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &mVirtualBounds.height) ||
+        mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FORMAT, &surfaceFormat)) {
         NS_RUNTIMEABORT("Failed to get native window size, aborting...");
     }
-    mScreenBounds = gfx::IntRect(gfx::IntPoint(0, 0), screenSize);
+
+    mNaturalBounds = mVirtualBounds;
 
-    char propValue[PROPERTY_VALUE_MAX];
-    property_get("ro.sf.hwrotation", propValue, "0");
-    mPhysicalScreenRotation = atoi(propValue) / 90;
+    if (IsPrimaryScreen()) {
+        char propValue[PROPERTY_VALUE_MAX];
+        property_get("ro.sf.hwrotation", propValue, "0");
+        mPhysicalScreenRotation = atoi(propValue) / 90;
+    }
 
-    mVirtualBounds = mScreenBounds;
+    mDpi = GetGonkDisplay()->xdpi;
+    mColorDepth = SurfaceFormatToColorDepth(surfaceFormat);
 }
 
 nsScreenGonk::~nsScreenGonk()
 {
 }
 
+bool
+nsScreenGonk::IsPrimaryScreen()
+{
+    return nsScreenManagerGonk::PRIMARY_SCREEN_ID == mId;
+}
+
 NS_IMETHODIMP
 nsScreenGonk::GetId(uint32_t *outId)
 {
-    *outId = 1;
+    *outId = mId;
     return NS_OK;
 }
 
+uint32_t
+nsScreenGonk::GetId()
+{
+    return mId;
+}
+
 NS_IMETHODIMP
 nsScreenGonk::GetRect(int32_t *outLeft,  int32_t *outTop,
                       int32_t *outWidth, int32_t *outHeight)
 {
     *outLeft = mVirtualBounds.x;
     *outTop = mVirtualBounds.y;
 
     *outWidth = mVirtualBounds.width;
     *outHeight = mVirtualBounds.height;
 
     return NS_OK;
 }
 
+nsIntRect
+nsScreenGonk::GetRect()
+{
+    return mVirtualBounds;
+}
+
 NS_IMETHODIMP
 nsScreenGonk::GetAvailRect(int32_t *outLeft,  int32_t *outTop,
                            int32_t *outWidth, int32_t *outHeight)
 {
     return GetRect(outLeft, outTop, outWidth, outHeight);
 }
 
-static uint32_t
-ColorDepth()
-{
-    switch (GetGonkDisplay()->surfaceformat) {
-    case GGL_PIXEL_FORMAT_RGB_565:
-        return 16;
-    case GGL_PIXEL_FORMAT_RGBA_8888:
-        return 32;
-    }
-    return 24; // GGL_PIXEL_FORMAT_RGBX_8888
-}
-
 NS_IMETHODIMP
 nsScreenGonk::GetPixelDepth(int32_t *aPixelDepth)
 {
     // XXX: this should actually return 32 when we're using 24-bit
     // color, because we use RGBX.
-    *aPixelDepth = ColorDepth();
+    *aPixelDepth = mColorDepth;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreenGonk::GetColorDepth(int32_t *aColorDepth)
 {
-    return GetPixelDepth(aColorDepth);
+    *aColorDepth = mColorDepth;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreenGonk::GetRotation(uint32_t* aRotation)
 {
     *aRotation = mScreenRotation;
     return NS_OK;
 }
 
+float
+nsScreenGonk::GetDpi()
+{
+    return mDpi;
+}
+
+ANativeWindow*
+nsScreenGonk::GetNativeWindow()
+{
+    return mNativeWindow.get();
+}
+
 NS_IMETHODIMP
 nsScreenGonk::SetRotation(uint32_t aRotation)
 {
     if (!(aRotation <= ROTATION_270_DEG)) {
         return NS_ERROR_ILLEGAL_VALUE;
     }
 
     if (mScreenRotation == aRotation) {
         return NS_OK;
     }
 
     mScreenRotation = aRotation;
     uint32_t rotation = EffectiveScreenRotation();
     if (rotation == nsIScreen::ROTATION_90_DEG ||
         rotation == nsIScreen::ROTATION_270_DEG) {
         mVirtualBounds = nsIntRect(0, 0,
-                                   mScreenBounds.height,
-                                   mScreenBounds.width);
+                                   mNaturalBounds.height,
+                                   mNaturalBounds.width);
     } else {
-        mVirtualBounds = mScreenBounds;
+        mVirtualBounds = mNaturalBounds;
     }
 
     nsAppShell::NotifyScreenRotation();
 
     for (unsigned int i = 0; i < mTopWindows.Length(); i++) {
         mTopWindows[i]->Resize(mVirtualBounds.width,
                             mVirtualBounds.height,
                             true);
     }
 
     return NS_OK;
 }
 
 nsIntRect
 nsScreenGonk::GetNaturalBounds()
 {
-    return mScreenBounds;
+    return mNaturalBounds;
 }
 
 uint32_t
 nsScreenGonk::EffectiveScreenRotation()
 {
     return (mScreenRotation + mPhysicalScreenRotation) % (360 / 90);
 }
 
@@ -1034,22 +1081,22 @@ ComputeOrientation(uint32_t aRotation, c
         MOZ_CRASH("Gonk screen must always have a known rotation");
     }
 }
 
 ScreenConfiguration
 nsScreenGonk::GetConfiguration()
 {
     ScreenOrientation orientation = ComputeOrientation(mScreenRotation,
-                                                       mScreenBounds.Size());
-    uint32_t colorDepth = ColorDepth();
+                                                       mNaturalBounds.Size());
+
     // NB: perpetuating colorDepth == pixelDepth illusion here, for
     // consistency.
     return ScreenConfiguration(mVirtualBounds, orientation,
-                               colorDepth, colorDepth);
+                               mColorDepth, mColorDepth);
 }
 
 void
 nsScreenGonk::RegisterWindow(nsWindow* aWindow)
 {
     mTopWindows.AppendElement(aWindow);
 }
 
@@ -1066,17 +1113,16 @@ nsScreenGonk::BringToTop(nsWindow* aWind
     mTopWindows.InsertElementAt(0, aWindow);
 }
 
 NS_IMPL_ISUPPORTS(nsScreenManagerGonk, nsIScreenManager)
 
 nsScreenManagerGonk::nsScreenManagerGonk()
     : mInitialized(false)
 {
-    mOneScreen = new nsScreenGonk();
 }
 
 nsScreenManagerGonk::~nsScreenManagerGonk()
 {
 }
 
 /* static */ already_AddRefed<nsScreenManagerGonk>
 nsScreenManagerGonk::GetInstance()
@@ -1105,16 +1151,18 @@ nsScreenManagerGonk::Initialize()
     if (mInitialized) {
         return;
     }
 
     mScreenOnEvent = new ScreenOnOffEvent(true);
     mScreenOffEvent = new ScreenOnOffEvent(false);
     GetGonkDisplay()->OnEnabled(displayEnabledCallback);
 
+    AddScreen(PRIMARY_SCREEN_TYPE);
+
     nsAppShell::NotifyScreenInitialized();
     mInitialized = true;
 }
 
 void
 nsScreenManagerGonk::DisplayEnabled(bool aEnabled)
 {
     if (gfxPrefs::HardwareVsyncEnabled()) {
@@ -1122,47 +1170,65 @@ nsScreenManagerGonk::DisplayEnabled(bool
     }
 
     NS_DispatchToMainThread(aEnabled ? mScreenOnEvent : mScreenOffEvent);
 }
 
 NS_IMETHODIMP
 nsScreenManagerGonk::GetPrimaryScreen(nsIScreen **outScreen)
 {
-    NS_IF_ADDREF(*outScreen = mOneScreen.get());
+    NS_IF_ADDREF(*outScreen = mScreens[0].get());
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreenManagerGonk::ScreenForId(uint32_t aId,
                                  nsIScreen **outScreen)
 {
-    return GetPrimaryScreen(outScreen);
+    for (size_t i = 0; i < mScreens.Length(); i++) {
+        if (mScreens[i]->GetId() == aId) {
+            NS_IF_ADDREF(*outScreen = mScreens[i].get());
+            return NS_OK;
+        }
+    }
+
+    *outScreen = nullptr;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreenManagerGonk::ScreenForRect(int32_t inLeft,
                                    int32_t inTop,
                                    int32_t inWidth,
                                    int32_t inHeight,
                                    nsIScreen **outScreen)
 {
+    // Since all screens have independent coordinate system, we could
+    // only return the primary screen no matter what rect is given.
     return GetPrimaryScreen(outScreen);
 }
 
 NS_IMETHODIMP
 nsScreenManagerGonk::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen)
 {
-    return GetPrimaryScreen(outScreen);
+    for (size_t i = 0; i < mScreens.Length(); i++) {
+        if (aWidget == mScreens[i]->GetNativeWindow()) {
+            NS_IF_ADDREF(*outScreen = mScreens[i].get());
+            return NS_OK;
+        }
+    }
+
+    *outScreen = nullptr;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreenManagerGonk::GetNumberOfScreens(uint32_t *aNumberOfScreens)
 {
-    *aNumberOfScreens = 1;
+    *aNumberOfScreens = mScreens.Length();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreenManagerGonk::GetSystemDefaultScale(float *aDefaultScale)
 {
     *aDefaultScale = 1.0f;
     return NS_OK;
@@ -1184,8 +1250,44 @@ nsScreenManagerGonk::VsyncControl(bool a
     MOZ_ASSERT(NS_IsMainThread());
     VsyncSource::Display &display = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay();
     if (aEnabled) {
         display.EnableVsync();
     } else {
         display.DisableVsync();
     }
 }
+
+uint32_t
+nsScreenManagerGonk::GetIdFromType(uint32_t aDisplayType)
+{
+    // This is the only place where we make the assumption that
+    // display type is equivalent to screen id.
+
+    // Bug 1138287 will address the conversion from type to id.
+    return aDisplayType;
+}
+
+void
+nsScreenManagerGonk::AddScreen(uint32_t aDisplayType)
+{
+    // We currently only support adding primary screen.
+    MOZ_ASSERT(PRIMARY_SCREEN_TYPE == aDisplayType);
+
+    uint32_t id = GetIdFromType(aDisplayType);
+
+    ANativeWindow* win = GetGonkDisplay()->GetNativeWindow();
+    nsScreenGonk* screen = new nsScreenGonk(id, win);
+
+    mScreens.AppendElement(screen);
+}
+
+void
+nsScreenManagerGonk::RemoveScreen(uint32_t aDisplayType)
+{
+    uint32_t screenId = GetIdFromType(aDisplayType);
+    for (size_t i = 0; i < mScreens.Length(); i++) {
+        if (mScreens[i]->GetId() == screenId) {
+            mScreens.RemoveElementAt(i);
+            break;
+        }
+    }
+}