Home | History | Annotate | Download | only in editing
      1 /*
      2  * Copyright (C) 2006, 2007 Apple, Inc.  All rights reserved.
      3  * Copyright (C) 2012 Google, Inc.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "core/editing/UndoStack.h"
     29 
     30 #include "core/dom/ContainerNode.h"
     31 #include "core/editing/UndoStep.h"
     32 #include "platform/EventDispatchForbiddenScope.h"
     33 #include "wtf/TemporaryChange.h"
     34 
     35 namespace blink {
     36 
     37 // Arbitrary depth limit for the undo stack, to keep it from using
     38 // unbounded memory. This is the maximum number of distinct undoable
     39 // actions -- unbroken stretches of typed characters are coalesced
     40 // into a single action.
     41 static const size_t maximumUndoStackDepth = 1000;
     42 
     43 UndoStack::UndoStack()
     44     : m_inRedo(false)
     45 {
     46 }
     47 
     48 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(UndoStack)
     49 
     50 PassOwnPtrWillBeRawPtr<UndoStack> UndoStack::create()
     51 {
     52     return adoptPtrWillBeNoop(new UndoStack());
     53 }
     54 
     55 void UndoStack::registerUndoStep(PassRefPtrWillBeRawPtr<UndoStep> step)
     56 {
     57     if (m_undoStack.size() == maximumUndoStackDepth)
     58         m_undoStack.removeFirst(); // drop oldest item off the far end
     59     if (!m_inRedo)
     60         m_redoStack.clear();
     61     m_undoStack.append(step);
     62 }
     63 
     64 void UndoStack::registerRedoStep(PassRefPtrWillBeRawPtr<UndoStep> step)
     65 {
     66     m_redoStack.append(step);
     67 }
     68 
     69 void UndoStack::didUnloadFrame(const LocalFrame& frame)
     70 {
     71     EventDispatchForbiddenScope assertNoEventDispatch;
     72     filterOutUndoSteps(m_undoStack, frame);
     73     filterOutUndoSteps(m_redoStack, frame);
     74 }
     75 
     76 void UndoStack::filterOutUndoSteps(UndoStepStack& stack, const LocalFrame& frame)
     77 {
     78     UndoStepStack newStack;
     79     while (!stack.isEmpty()) {
     80         UndoStep* step = stack.first().get();
     81         if (!step->belongsTo(frame))
     82             newStack.append(step);
     83         stack.removeFirst();
     84     }
     85     stack.swap(newStack);
     86 }
     87 
     88 bool UndoStack::canUndo() const
     89 {
     90     return !m_undoStack.isEmpty();
     91 }
     92 
     93 bool UndoStack::canRedo() const
     94 {
     95     return !m_redoStack.isEmpty();
     96 }
     97 
     98 void UndoStack::undo()
     99 {
    100     if (canUndo()) {
    101         UndoStepStack::iterator back = --m_undoStack.end();
    102         RefPtrWillBeRawPtr<UndoStep> step(back->get());
    103         m_undoStack.remove(back);
    104         step->unapply();
    105         // unapply will call us back to push this command onto the redo stack.
    106     }
    107 }
    108 
    109 void UndoStack::redo()
    110 {
    111     if (canRedo()) {
    112         UndoStepStack::iterator back = --m_redoStack.end();
    113         RefPtrWillBeRawPtr<UndoStep> step(back->get());
    114         m_redoStack.remove(back);
    115 
    116         ASSERT(!m_inRedo);
    117         TemporaryChange<bool> redoScope(m_inRedo, true);
    118         step->reapply();
    119         // reapply will call us back to push this command onto the undo stack.
    120     }
    121 }
    122 
    123 void UndoStack::trace(Visitor* visitor)
    124 {
    125     visitor->trace(m_undoStack);
    126     visitor->trace(m_redoStack);
    127 }
    128 
    129 } // namespace blink
    130