/*
 * Copyright (C) 2010 Apple Inc. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#if ENABLE(FULLSCREEN_API)

#include "RenderFullScreen.h"

#include "FullscreenManager.h"
#include "RenderBlockFlow.h"
#include "RenderLayer.h"
#include "RenderLayerCompositor.h"
#include "RenderTreeBuilder.h"
#include <wtf/IsoMallocInlines.h>

namespace WebCore {

WTF_MAKE_ISO_ALLOCATED_IMPL(RenderFullScreen);

RenderFullScreenPlaceholder::RenderFullScreenPlaceholder(Document& document, RenderStyle&& style)
    : RenderBlockFlow(document, WTFMove(style))
{
}

bool RenderFullScreenPlaceholder::isRenderFullScreenPlaceholder() const
{
    return true;
}

WTF_MAKE_ISO_ALLOCATED_IMPL(RenderFullScreenPlaceholder);

RenderFullScreen::RenderFullScreen(Document& document, RenderStyle&& style)
    : RenderFlexibleBox(document, WTFMove(style))
{
    setReplaced(false); 
}

RenderFullScreen::~RenderFullScreen()
{
    ASSERT(!m_placeholder);
}

static RenderStyle createFullScreenStyle()
{
    auto fullscreenStyle = RenderStyle::create();

    // Create a stacking context:
    fullscreenStyle.setZIndex(INT_MAX);

    fullscreenStyle.setFontDescription({ });
    fullscreenStyle.fontCascade().update(nullptr);

    fullscreenStyle.setDisplay(DisplayType::Flex);
    fullscreenStyle.setJustifyContentPosition(ContentPosition::Center);
    fullscreenStyle.setAlignItemsPosition(ItemPosition::Center);
    fullscreenStyle.setFlexDirection(FlexDirection::Column);
    
    fullscreenStyle.setPosition(PositionType::Fixed);
    fullscreenStyle.setWidth(Length(100.0, Percent));
    fullscreenStyle.setHeight(Length(100.0, Percent));
    fullscreenStyle.setLeft(Length(0, WebCore::Fixed));
    fullscreenStyle.setTop(Length(0, WebCore::Fixed));
    
    fullscreenStyle.setBackgroundColor(Color::black);

    return fullscreenStyle;
}

RenderPtr<RenderFullScreen> RenderFullScreen::wrapNewRenderer(RenderTreeBuilder& builder, RenderPtr<RenderElement> renderer, RenderElement& parent, Document& document)
{
    auto newFullscreenRenderer = createRenderer<RenderFullScreen>(document, createFullScreenStyle());
    newFullscreenRenderer->initializeStyle();

    auto& fullscreenRenderer = *newFullscreenRenderer;
    if (!parent.isChildAllowed(fullscreenRenderer, fullscreenRenderer.style()))
        return nullptr;

    builder.attach(fullscreenRenderer, WTFMove(renderer));
    fullscreenRenderer.setNeedsLayoutAndPrefWidthsRecalc();

    document.fullscreenManager().setFullscreenRenderer(builder, fullscreenRenderer);

    return newFullscreenRenderer;
}

void RenderFullScreen::wrapExistingRenderer(RenderElement& renderer, Document& document)
{
    // FIXME: This should be done by RenderTreeUpdater.
    RenderTreeBuilder builder(*document.renderView());

    auto newFullscreenRenderer = createRenderer<RenderFullScreen>(document, createFullScreenStyle());
    newFullscreenRenderer->initializeStyle();

    auto& fullscreenRenderer = *newFullscreenRenderer;
    auto& parent = *renderer.parent();
    if (!parent.isChildAllowed(fullscreenRenderer, fullscreenRenderer.style()))
        return;

    RenderBlock* containingBlock = renderer.containingBlock();
    ASSERT(containingBlock);
    // Since we are moving the |object| to a new parent |fullscreenRenderer|,
    // the line box tree underneath our |containingBlock| is not longer valid.
    containingBlock->deleteLines();

    builder.attach(parent, WTFMove(newFullscreenRenderer), &renderer);

    auto toMove = builder.detach(parent, renderer);

    // Always just do a full layout to ensure that line boxes get deleted properly.
    // Because objects moved from |parent| to |fullscreenRenderer|, we want to
    // make new line boxes instead of leaving the old ones around.
    parent.setNeedsLayoutAndPrefWidthsRecalc();
    containingBlock->setNeedsLayoutAndPrefWidthsRecalc();

    builder.attach(fullscreenRenderer, WTFMove(toMove));
    fullscreenRenderer.setNeedsLayoutAndPrefWidthsRecalc();

    document.fullscreenManager().setFullscreenRenderer(builder, fullscreenRenderer);
}

void RenderFullScreen::unwrapRenderer(bool& requiresRenderTreeRebuild)
{
    RenderTreeBuilder builder(view());

    requiresRenderTreeRebuild = false;
    if (parent()) {
        auto* child = firstChild();
        // Things can get very complicated with anonymous block generation.
        // We can restore correctly without rebuild in simple cases only.
        // FIXME: We should have a mechanism for removing a block without reconstructing the tree.
        if (child != lastChild())
            requiresRenderTreeRebuild = true;
        else if (child && child->isAnonymousBlock()) {
            auto& anonymousBlock = downcast<RenderBlock>(*child);
            if (anonymousBlock.firstChild() != anonymousBlock.lastChild())
                requiresRenderTreeRebuild = true;
        }

        while ((child = firstChild())) {
            if (child->isAnonymousBlock() && !requiresRenderTreeRebuild) {
                if (auto* nonAnonymousChild = downcast<RenderBlock>(*child).firstChild())
                    child = nonAnonymousChild;
                else {
                    builder.destroy(*child);
                    continue;
                }
            }
            // We have to clear the override size, because as a flexbox, we
            // may have set one on the child, and we don't want to leave that
            // lying around on the child.
            if (is<RenderBox>(*child))
                downcast<RenderBox>(*child).clearOverrideContentSize();
            auto childToMove = builder.detach(*child->parent(), *child);
            builder.attach(*parent(), WTFMove(childToMove), this);
            parent()->setNeedsLayoutAndPrefWidthsRecalc();
        }
    }
    if (placeholder())
        builder.destroy(*placeholder());
    ASSERT(!placeholder());

    builder.destroy(*this);
}

}

#endif
