// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "base/compiler_specific.h"

MSVC_PUSH_WARNING_LEVEL(0);
#include "RenderLayer.h"
#include "RenderObject.h"
MSVC_POP_WARNING();
#undef LOG

#include "webkit/glue/stacking_order_iterator.h"

//
// RenderLayerIterator
//

RenderLayerIterator::RenderLayerIterator() {
}

void RenderLayerIterator::Reset(const WebCore::IntRect& bounds,
                                WebCore::RenderLayer* rl) {
  bounds_ = bounds;
  root_layer_ = rl;
  if (rl) {
    context_stack_.push_back(Context(rl));
  }
}

WebCore::RenderLayer* RenderLayerIterator::Next() {
  while (context_stack_.size()) {
    Context* ctx = &(context_stack_.back());
    if (!ctx->layer()->boundingBox(root_layer_).intersects(bounds_)) {
      // Doesn't overlap bounds; skip this layer.
      context_stack_.pop_back();
    } else if (ctx->HasMoreNeg()) {
      context_stack_.push_back(ctx->NextNeg());
    } else if (ctx->HasSelf()) {
      // Emit self.
      return ctx->NextSelf();
    } else if (ctx->HasMoreOverflow()) {
      context_stack_.push_back(ctx->NextOverflow());
    } else if (ctx->HasMorePos()) {
      context_stack_.push_back(ctx->NextPos());
    } else {
      // Nothing left in this context.  Pop.
      context_stack_.pop_back();
    }
  }
  return NULL;
}

RenderLayerIterator::Context::Context(WebCore::RenderLayer* layer)
   :  layer_(layer),
      next_neg_(0),
      next_self_(0),
      next_overflow_(0),
      next_pos_(0) {
  ASSERT(layer_);
  layer_->updateZOrderLists();
  layer_->updateNormalFlowList();
}

bool RenderLayerIterator::Context::HasMoreNeg() {
  return layer_->negZOrderList() &&
    next_neg_ < layer_->negZOrderList()->size();
}

RenderLayerIterator::Context RenderLayerIterator::Context::NextNeg() {
  ASSERT(HasMoreNeg());
  return Context(layer_->negZOrderList()->at(next_neg_++));
}

bool RenderLayerIterator::Context::HasSelf() {
  return next_self_ < 1;
}

WebCore::RenderLayer* RenderLayerIterator::Context::NextSelf() {
  ASSERT(HasSelf());
  next_self_ = 1;
  return layer_;
}

bool RenderLayerIterator::Context::HasMoreOverflow() {
  return layer_->normalFlowList() &&
    next_overflow_ >= 0 &&
    next_overflow_ < layer_->normalFlowList()->size();
}

RenderLayerIterator::Context RenderLayerIterator::Context::NextOverflow() {
  ASSERT(HasMoreOverflow());
  return Context(layer_->normalFlowList()->at(next_overflow_++));
}

bool RenderLayerIterator::Context::HasMorePos() {
  return layer_->posZOrderList() &&
    next_pos_ < layer_->posZOrderList()->size();
}

RenderLayerIterator::Context RenderLayerIterator::Context::NextPos() {
  ASSERT(HasMorePos());
  return Context(layer_->posZOrderList()->at(next_pos_++));
}

//
// StackingOrderIterator
//

StackingOrderIterator::StackingOrderIterator() {
  Reset(WebCore::IntRect(0, 0, 0, 0), NULL);
}

void StackingOrderIterator::Reset(const WebCore::IntRect& bounds,
                                  WebCore::RenderLayer* rl) {
  layer_iterator_.Reset(bounds, rl);
  current_object_ = NULL;
  current_layer_root_ = NULL;
}

WebCore::RenderObject* StackingOrderIterator::Next() {
  if (current_object_) {
    // Get the next object inside the current layer.
    current_object_ = current_object_->nextInPreOrder(current_layer_root_);

    // Skip any sub-layers we encounter along the way; they are
    // visited (in the correct stacking order) by layer_iterator_.
    while (current_object_ && current_object_->hasLayer()) {
      current_object_ = current_object_->
                        nextInPreOrderAfterChildren(current_layer_root_);
    }
  }

  if (!current_object_) {
    // Start the next layer.
    WebCore::RenderLayer* layer = layer_iterator_.Next();
    if (layer) {
      current_object_ = layer->renderer();
      current_layer_root_ = current_object_;
    }
  }
  return current_object_;
}