editor/txmgr/src/nsTransactionItem.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/mozalloc.h"
     7 #include "nsAutoPtr.h"
     8 #include "nsCOMPtr.h"
     9 #include "nsDebug.h"
    10 #include "nsError.h"
    11 #include "nsISupportsImpl.h"
    12 #include "nsITransaction.h"
    13 #include "nsTransactionItem.h"
    14 #include "nsTransactionManager.h"
    15 #include "nsTransactionStack.h"
    17 nsTransactionItem::nsTransactionItem(nsITransaction *aTransaction)
    18     : mTransaction(aTransaction), mUndoStack(0), mRedoStack(0)
    19 {
    20 }
    22 nsTransactionItem::~nsTransactionItem()
    23 {
    24   delete mRedoStack;
    26   delete mUndoStack;
    27 }
    29 void
    30 nsTransactionItem::CleanUp()
    31 {
    32   mData.Clear();
    33   mTransaction = nullptr;
    34   if (mRedoStack) {
    35     mRedoStack->DoUnlink();
    36   }
    37   if (mUndoStack) {
    38     mUndoStack->DoUnlink();
    39   }
    40 }
    42 NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(nsTransactionItem)
    43 NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(nsTransactionItem,
    44                                                           CleanUp())
    46 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTransactionItem)
    48 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTransactionItem)
    49   tmp->CleanUp();
    50 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    52 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTransactionItem)
    53   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
    54   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
    55   if (tmp->mRedoStack) {
    56     tmp->mRedoStack->DoTraverse(cb);
    57   }
    58   if (tmp->mUndoStack) {
    59     tmp->mUndoStack->DoTraverse(cb);
    60   }
    61 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    63 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTransactionItem, AddRef)
    64 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTransactionItem, Release)
    66 nsresult
    67 nsTransactionItem::AddChild(nsTransactionItem *aTransactionItem)
    68 {
    69   NS_ENSURE_TRUE(aTransactionItem, NS_ERROR_NULL_POINTER);
    71   if (!mUndoStack) {
    72     mUndoStack = new nsTransactionStack(nsTransactionStack::FOR_UNDO);
    73   }
    75   mUndoStack->Push(aTransactionItem);
    77   return NS_OK;
    78 }
    80 already_AddRefed<nsITransaction>
    81 nsTransactionItem::GetTransaction()
    82 {
    83   nsCOMPtr<nsITransaction> txn = mTransaction;
    84   return txn.forget();
    85 }
    87 nsresult
    88 nsTransactionItem::GetIsBatch(bool *aIsBatch)
    89 {
    90   NS_ENSURE_TRUE(aIsBatch, NS_ERROR_NULL_POINTER);
    92   *aIsBatch = !mTransaction;
    94   return NS_OK;
    95 }
    97 nsresult
    98 nsTransactionItem::GetNumberOfChildren(int32_t *aNumChildren)
    99 {
   100   nsresult result;
   102   NS_ENSURE_TRUE(aNumChildren, NS_ERROR_NULL_POINTER);
   104   *aNumChildren = 0;
   106   int32_t ui = 0;
   107   int32_t ri = 0;
   109   result = GetNumberOfUndoItems(&ui);
   111   NS_ENSURE_SUCCESS(result, result);
   113   result = GetNumberOfRedoItems(&ri);
   115   NS_ENSURE_SUCCESS(result, result);
   117   *aNumChildren = ui + ri;
   119   return NS_OK;
   120 }
   122 nsresult
   123 nsTransactionItem::GetChild(int32_t aIndex, nsTransactionItem **aChild)
   124 {
   125   NS_ENSURE_TRUE(aChild, NS_ERROR_NULL_POINTER);
   127   *aChild = 0;
   129   int32_t numItems = 0;
   130   nsresult result = GetNumberOfChildren(&numItems);
   132   NS_ENSURE_SUCCESS(result, result);
   134   if (aIndex < 0 || aIndex >= numItems)
   135     return NS_ERROR_FAILURE;
   137   // Children are expected to be in the order they were added,
   138   // so the child first added would be at the bottom of the undo
   139   // stack, or if there are no items on the undo stack, it would
   140   // be at the top of the redo stack.
   142   result = GetNumberOfUndoItems(&numItems);
   144   NS_ENSURE_SUCCESS(result, result);
   146   if (numItems > 0 && aIndex < numItems) {
   147     NS_ENSURE_TRUE(mUndoStack, NS_ERROR_FAILURE);
   149     nsRefPtr<nsTransactionItem> child = mUndoStack->GetItem(aIndex);
   150     child.forget(aChild);
   151     return *aChild ? NS_OK : NS_ERROR_FAILURE;
   152   }
   154   // Adjust the index for the redo stack:
   156   aIndex -=  numItems;
   158   result = GetNumberOfRedoItems(&numItems);
   160   NS_ENSURE_SUCCESS(result, result);
   162   NS_ENSURE_TRUE(mRedoStack && numItems != 0 && aIndex < numItems, NS_ERROR_FAILURE);
   164   nsRefPtr<nsTransactionItem> child = mRedoStack->GetItem(aIndex);
   165   child.forget(aChild);
   166   return *aChild ? NS_OK : NS_ERROR_FAILURE;
   167 }
   169 nsresult
   170 nsTransactionItem::DoTransaction()
   171 {
   172   if (mTransaction)
   173     return mTransaction->DoTransaction();
   174   return NS_OK;
   175 }
   177 nsresult
   178 nsTransactionItem::UndoTransaction(nsTransactionManager *aTxMgr)
   179 {
   180   nsresult result = UndoChildren(aTxMgr);
   182   if (NS_FAILED(result)) {
   183     RecoverFromUndoError(aTxMgr);
   184     return result;
   185   }
   187   if (!mTransaction)
   188     return NS_OK;
   190   result = mTransaction->UndoTransaction();
   192   if (NS_FAILED(result)) {
   193     RecoverFromUndoError(aTxMgr);
   194     return result;
   195   }
   197   return NS_OK;
   198 }
   200 nsresult
   201 nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
   202 {
   203   nsRefPtr<nsTransactionItem> item;
   204   nsresult result = NS_OK;
   205   int32_t sz = 0;
   207   if (mUndoStack) {
   208     if (!mRedoStack && mUndoStack) {
   209       mRedoStack = new nsTransactionStack(nsTransactionStack::FOR_REDO);
   210     }
   212     /* Undo all of the transaction items children! */
   213     sz = mUndoStack->GetSize();
   215     while (sz-- > 0) {
   216       item = mUndoStack->Peek();
   218       if (!item) {
   219         return NS_ERROR_FAILURE;
   220       }
   222       nsCOMPtr<nsITransaction> t = item->GetTransaction();
   224       bool doInterrupt = false;
   226       result = aTxMgr->WillUndoNotify(t, &doInterrupt);
   228       if (NS_FAILED(result)) {
   229         return result;
   230       }
   232       if (doInterrupt) {
   233         return NS_OK;
   234       }
   236       result = item->UndoTransaction(aTxMgr);
   238       if (NS_SUCCEEDED(result)) {
   239         item = mUndoStack->Pop();
   240         mRedoStack->Push(item);
   241       }
   243       nsresult result2 = aTxMgr->DidUndoNotify(t, result);
   245       if (NS_SUCCEEDED(result)) {
   246         result = result2;
   247       }
   248     }
   249   }
   251   return result;
   252 }
   254 nsresult
   255 nsTransactionItem::RedoTransaction(nsTransactionManager *aTxMgr)
   256 {
   257   nsresult result;
   259   nsCOMPtr<nsITransaction> kungfuDeathGrip(mTransaction);
   260   if (mTransaction) {
   261     result = mTransaction->RedoTransaction();
   263     NS_ENSURE_SUCCESS(result, result);
   264   }
   266   result = RedoChildren(aTxMgr);
   268   if (NS_FAILED(result)) {
   269     RecoverFromRedoError(aTxMgr);
   270     return result;
   271   }
   273   return NS_OK;
   274 }
   276 nsresult
   277 nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
   278 {
   279   nsRefPtr<nsTransactionItem> item;
   280   nsresult result = NS_OK;
   282   if (!mRedoStack)
   283     return NS_OK;
   285   /* Redo all of the transaction items children! */
   286   int32_t sz = mRedoStack->GetSize();
   288   while (sz-- > 0) {
   289     item = mRedoStack->Peek();
   291     if (!item) {
   292       return NS_ERROR_FAILURE;
   293     }
   295     nsCOMPtr<nsITransaction> t = item->GetTransaction();
   297     bool doInterrupt = false;
   299     result = aTxMgr->WillRedoNotify(t, &doInterrupt);
   301     if (NS_FAILED(result)) {
   302       return result;
   303     }
   305     if (doInterrupt) {
   306       return NS_OK;
   307     }
   309     result = item->RedoTransaction(aTxMgr);
   311     if (NS_SUCCEEDED(result)) {
   312       item = mRedoStack->Pop();
   313       mUndoStack->Push(item);
   314     }
   316     nsresult result2 = aTxMgr->DidUndoNotify(t, result);
   318     if (NS_SUCCEEDED(result)) {
   319       result = result2;
   320     }
   321   }
   323   return result;
   324 }
   326 nsresult
   327 nsTransactionItem::GetNumberOfUndoItems(int32_t *aNumItems)
   328 {
   329   NS_ENSURE_TRUE(aNumItems, NS_ERROR_NULL_POINTER);
   331   if (!mUndoStack) {
   332     *aNumItems = 0;
   333     return NS_OK;
   334   }
   336   *aNumItems = mUndoStack->GetSize();
   337   return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
   338 }
   340 nsresult
   341 nsTransactionItem::GetNumberOfRedoItems(int32_t *aNumItems)
   342 {
   343   NS_ENSURE_TRUE(aNumItems, NS_ERROR_NULL_POINTER);
   345   if (!mRedoStack) {
   346     *aNumItems = 0;
   347     return NS_OK;
   348   }
   350   *aNumItems = mRedoStack->GetSize();
   351   return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
   352 }
   354 nsresult
   355 nsTransactionItem::RecoverFromUndoError(nsTransactionManager *aTxMgr)
   356 {
   357   //
   358   // If this method gets called, we never got to the point where we
   359   // successfully called UndoTransaction() for the transaction item itself.
   360   // Just redo any children that successfully called undo!
   361   //
   362   return RedoChildren(aTxMgr);
   363 }
   365 nsresult
   366 nsTransactionItem::RecoverFromRedoError(nsTransactionManager *aTxMgr)
   367 {
   368   //
   369   // If this method gets called, we already successfully called
   370   // RedoTransaction() for the transaction item itself. Undo all
   371   // the children that successfully called RedoTransaction(),
   372   // then undo the transaction item itself.
   373   //
   375   nsresult result;
   377   result = UndoChildren(aTxMgr);
   379   if (NS_FAILED(result)) {
   380     return result;
   381   }
   383   if (!mTransaction)
   384     return NS_OK;
   386   return mTransaction->UndoTransaction();
   387 }

mercurial