/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */
#ifndef nsIReflowCommand_h___
#define nsIReflowCommand_h___

#include "nsISupports.h"

class  nsIAtom;
class  nsIFrame;
class  nsIPresContext;
class  nsIRenderingContext;
struct nsHTMLReflowMetrics;
struct nsSize;

// IID for the nsIReflowCommand interface {C3658E40-FF20-11d1-85BC-00A02468FAB6}
#define NS_IREFLOWCOMMAND_IID         \
{ 0xc3658e40, 0xff20, 0x11d1, \
  {0x85, 0xbc, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}}

/**
 * A reflow command is an object that is generated in response to a content
 * model change notification. The reflow command is given to a presentation
 * shell where it is queued and then dispatched by invoking the reflow
 * commands's Dispatch() member function.
 *
 * Reflow command processing follows a path from the root frame down to the
 * target frame (the frame for which the reflow command is destined). Reflow
 * commands are processed by invoking the frame's Reflow() member function.
 *
 * The typical flow of control for a given reflow command starts with a content
 * change notification. The content notifications are sent to document observers.
 * The presentation shell forwards the notifications to the style set. The style
 * system responds to the notifications by creating new frame (or destroying
 * existing frames) as appropriate, and then generating a reflow command.
 *
 * @see nsIDocumentObserver
 * @see nsIStyleSet
 * @see nsIFrameReflow#Reflow()
 * @see nsIPresShell#AppendReflowCommand()
 * @see nsIPresShell#ProcessReflowCommands()
 */
class nsIReflowCommand : public nsISupports {
public:
  enum ReflowType {
    /**
     * Reflow command generated by the style system in response to a
     * ContentAppended content notification. The target frame of the reflow
     * command is the container frame itself. The "child frame" is a linked
     * list of newly created child frames.
     *
     * The target frame should insert the new frames into the specified child
     * list, and then reflow the child frames using an eReflowReason_Initial
     * reflow reason.
     *
     * ContentInserted content notifications also generate a FrameAppended reflow
     * command if the container frame has no existing child frames.
     *
     * @see #GetTarget()
     * @see #GetChildFrame()
     * @see #GetChildListName()
     */
    FrameAppended = 0,

    /**
     * Reflow command generated by the style system in response to a
     * ContentInserted content notification. The target frame of the reflow
     * command is the container frame itself. The "child frame" is a linked
     * list of newly created child frames. The "previous sibling" frame is the
     * existing frame immediately preceding where the first of the newly created
     * frames should be inserted. If the newly created frames should be the
     * target frame's first child frames then "previous sibling" will be nsnull.
     *
     * The target frame should insert the new frames immediately after the previous
     * sibling frame, and then reflow the new frames using an eReflowReason_Initial
     * reflow reason. Use GetChildListName() to get the name of the child list to
     * which you should insert the new frames.
     *
     * The target frame is determined as follows:
     *   - find the previous existing frame and use its content parent
     *   - if there is no previous frame then find the frame that follows and use
     *     its content parent
     *
     * @see #GetTarget()
     * @see #GetChildFrame()
     * @see #GetPrevSiblingFrame()
     * @see #GetChildListName()
     */
    FrameInserted,

    /**
     * Reflow command generated by the style system in response to a
     * ContentRemoved content notification. The "child frame" is the frame
     * associated with the content that has been removed. The target frame
     * is the content parent of the "child frame".
     *
     * Use GetChildListName() to get the name of the child list associated with
     * the frame to be deleted
     *
     * @see #GetTarget()
     * @see #GetChildFrame()
     * @see #GetChildListName()
     */
    FrameRemoved,

    // This reflow command is used when a leaf node's content changes
    // (e.g. some text in a text run, an image's source, etc.). The
    // target of the reflow command is the frame that changed (see
    // nsIFrame#ContentChanged() for how the target frame is
    // determined).
    ContentChanged,

    // This reflow command is used when the style for a frame has
    // changed. This also implies that if the frame is a container
    // that its childrens style has also changed. The target of the
    // reflow command is the frame that changed style.
    StyleChanged,

    // XXX Everything below is speculative...

    // When an incremental reflow operation affects a next-in-flow,
    // these commands are used to get the next-in-flow to update
    // itself.
    PullupReflow,
    PushReflow,

    // This command is used to see if a prev-in-flow wants to pullup
    // some children from a next-in-flow that has changed because of
    // an incremental reflow.
    CheckPullupReflow,

    // Trap door for extensions.
    UserDefined
  };

  /**
   * Dispatch the reflow command.
   *
   * Builds a path from the target frame back to the root frame, and then
   * invokes the root frame's Reflow() member function.
   *
   * @see nsIFrame#Reflow()
   */
  NS_IMETHOD Dispatch(nsIPresContext&      aPresContext,
                      nsHTMLReflowMetrics& aDesiredSize,
                      const nsSize&        aMaxSize,
                      nsIRenderingContext& aRendContext) = 0;

  /**
   * Get the next frame in the command processing path. Note that this removes
   * the frame from the path so you must only call it once.
   */
  NS_IMETHOD GetNext(nsIFrame*& aNextFrame) = 0;

  /**
   * Get the target of the reflow command.
   */
  NS_IMETHOD GetTarget(nsIFrame*& aTargetFrame) const = 0;

  /**
   * Change the target of the reflow command.
   */
  NS_IMETHOD SetTarget(nsIFrame* aTargetFrame) = 0;

  /**
   * Get the type of reflow command.
   */
  NS_IMETHOD GetType(ReflowType& aReflowType) const = 0;

  /**
   * Get the child frame associated with the reflow command.
   */
  NS_IMETHOD GetChildFrame(nsIFrame*& aChildFrame) const = 0;

  /**
   * Returns the name of the child list to which the child frame belongs.
   * Only used for reflow command types FrameAppended, FrameInserted, and
   * FrameRemoved
   *
   * Returns nsnull if the child frame is associated with the unnamed
   * principal child list
   */
  NS_IMETHOD GetChildListName(nsIAtom*& aListName) const = 0;

  /**
   * Get the previous sibling frame associated with the reflow command.
   * This is used for FrameInserted reflow commands.
   */
  NS_IMETHOD GetPrevSiblingFrame(nsIFrame*& aSiblingFrame) const = 0;
};

#endif /* nsIReflowCommand_h___ */
