/*
 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
 *                     1999-2001 Lars Knoll <knoll@kde.org>
 *                     1999-2001 Antti Koivisto <koivisto@kde.org>
 *                     2000-2001 Simon Hausmann <hausmann@kde.org>
 *                     2000-2001 Dirk Mueller <mueller@kde.org>
 *                     2000 Stefan Schimanski <1Stein@gmx.de>
 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#pragma once

#include "AbstractFrame.h"
#include "AdjustViewSizeOrNot.h"
#include "Document.h"
#include "DragImage.h"
#include "EventHandler.h"
#include "FrameDestructionObserver.h"
#include "FrameLoader.h"
#include "FrameSelection.h"
#include "FrameTree.h"
#include "NavigationScheduler.h"
#include "ScriptController.h"
#include "UserScriptTypes.h"
#include <wtf/HashMap.h>

#if PLATFORM(WIN)
#include "FrameWin.h"
#endif

#if USE(TILED_BACKING_STORE)
#include "TiledBackingStoreClient.h"
#endif

#if PLATFORM(MAC)
#ifndef __OBJC__
class NSArray;
class NSMutableDictionary;
class NSString;
#endif
#endif

#if PLATFORM(WIN)
typedef struct HBITMAP__* HBITMAP;
#endif

namespace WebCore {

class DOMWindow;
class Document;
class Editor;
class FrameView;
class HTMLTableCellElement;
class RegularExpression;
class RenderWidget;
class TiledBackingStore;

struct SimpleRange;

#if !USE(TILED_BACKING_STORE)
class TiledBackingStoreClient { };
#endif

class TreeScope;

enum {
    LayerTreeFlagsIncludeDebugInfo = 1 << 0,
    LayerTreeFlagsIncludeVisibleRects = 1 << 1,
    LayerTreeFlagsIncludeTileCaches = 1 << 2,
    LayerTreeFlagsIncludeRepaintRects = 1 << 3,
    LayerTreeFlagsIncludePaintingPhases = 1 << 4,
    LayerTreeFlagsIncludeContentLayers = 1 << 5,
    LayerTreeFlagsIncludeAcceleratesDrawing = 1 << 6,
    LayerTreeFlagsIncludeBackingStoreAttached = 1 << 7,
    LayerTreeFlagsIncludeRootLayerProperties = 1 << 8,
};
typedef unsigned LayerTreeFlags;

// FIXME: Rename Frame to LocalFrame and AbstractFrame to Frame.
class Frame FINAL : public AbstractFrame, public TiledBackingStoreClient {
public:
	static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);

	void init();
	void setView(PassRefPtr<FrameView>);
	void createView(const IntSize&, const Color&, bool, const IntSize&, bool,
		ScrollbarMode = ScrollbarAuto, bool horizontalLock = false,
		ScrollbarMode = ScrollbarAuto, bool verticalLock = false);

	virtual ~Frame();

    DOMWindow* window() const;

	void addDestructionObserver(FrameDestructionObserver*);
	void removeDestructionObserver(FrameDestructionObserver*);

	void willDetachPage();
	void detachFromPage();
	void disconnectOwnerElement();

	void stopAllLayouts();

	Frame* mainFrame() const;
    bool isMainFrame() const { return this == m_mainFrame; }

	Page* page() const;
	HTMLFrameOwnerElement* ownerElement() const;

	Document* document() const;
	FrameView* view() const;

    Editor& editor() { return document()->editor(); }
    const Editor& editor() const { return document()->editor(); }
	EventHandler* eventHandler() const;
	FrameLoader* loader() const;
	NavigationScheduler* navigationScheduler() const;
    FrameSelection& selection() { return document()->selection(); }
    const FrameSelection& selection() const { return document()->selection(); }
	FrameTree* tree() const;
	ScriptController* script();

	RenderView* contentRenderer() const; // Root of the render tree for the document contained in this frame.
	RenderWidget* ownerRenderer() const; // Renderer for the element that contains this frame.

    bool documentIsBeingReplaced() const { return m_documentIsBeingReplaced; }

    bool hasHadUserInteraction() const { return m_hasHadUserInteraction; }
    void setHasHadUserInteraction() { m_hasHadUserInteraction = true; }

#if ENABLE(PAGE_VISIBILITY_API)
	void dispatchVisibilityStateChangeEvent();
#endif

#if ENABLE(CEHTML)
private:
	typedef HashMap<String, unsigned> URLTimeoutMap;
	mutable OwnPtr<URLTimeoutMap> m_URLTimeoutMap;

public:
	void setTimeoutForURL(const String& url, unsigned timeout);
	unsigned timeoutForURL(const String& url);
	ALWAYS_INLINE unsigned httptimeout() const { return m_httpTimeout; }
	void setHttptimeout(unsigned timeout) { m_httpTimeout = timeout; }
	unsigned m_httpTimeout;
#endif

// ======== All public functions below this point are candidates to move out of Frame into another class. ========

	bool inScope(TreeScope*) const;

	void injectUserScripts(UserScriptInjectionTime);

	String layerTreeAsText(LayerTreeFlags = 0) const;

	static Frame* frameForWidget(const Widget*);

	Settings& settings() const { return *m_settings; }

	void setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio, AdjustViewSizeOrNot);
	bool shouldUsePrintingLayout() const;
	FloatSize resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize);

	void setDocument(PassRefPtr<Document>);

	void setPageZoomFactor(float factor, bool doReload = false) { setPageAndTextZoomFactors(factor, m_textZoomFactor, doReload); }
	float pageZoomFactor() const { return m_pageZoomFactor; }
	void setTextZoomFactor(float factor) { setPageAndTextZoomFactors(m_pageZoomFactor, factor); }
	float textZoomFactor() const { return m_textZoomFactor; }
	void setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor, bool doReload = false);

	// Scale factor of this frame with respect to the container.
	float frameScaleFactor() const;

	void deviceOrPageScaleFactorChanged();

#if ENABLE(ORIENTATION_EVENTS)
	// Orientation is the interface orientation in degrees. Some examples are:
	//  0 is straight up; -90 is when the device is rotated 90 clockwise;
	//  90 is when rotated counter clockwise.
	void sendOrientationChangeEvent(int orientation);
	int orientation() const { return m_orientation; }
#endif

	void clearTimers();
	static void clearTimers(FrameView*, Document*);

	String displayStringModifiedByEncoding(const String&) const;

	DragImageRef nodeImage(Node*);
	DragImageRef dragImageForSelection();

	VisiblePosition visiblePositionForPoint(const IntPoint& framePoint);
	Document* documentAtPoint(const IntPoint& windowPoint);
	Optional<SimpleRange> rangeForPoint(const IntPoint& framePoint);

	String searchForLabelsAboveCell(RegularExpression*, HTMLTableCellElement*, size_t* resultDistanceFromStartOfCell);
	String searchForLabelsBeforeElement(const Vector<String>& labels, Element*, size_t* resultDistance, bool* resultIsInCellAbove);
	String matchLabelsAgainstElement(const Vector<String>& labels, Element*);

#if PLATFORM(MAC)
	NSImage* selectionImage(bool forceBlackText = false) const;
	NSImage* rangeImage(Range*, bool forceBlackText = false) const;
	NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const;
	NSImage* imageFromRect(NSRect) const;
#endif
	void suspendActiveDOMObjectsAndAnimations();
	void resumeActiveDOMObjectsAndAnimations();
	ALWAYS_INLINE bool activeDOMObjectsAndAnimationsSuspended() const { return m_activeDOMObjectsAndAnimationsSuspendedCount > 0; }

// ========

private:
	Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);

	void injectUserScriptsForWorld(DOMWrapperWorld*, const UserScriptVector&, UserScriptInjectionTime);

    virtual bool isLocalFrame() const FINAL { return true; }
    virtual bool isRemoteFrame() const FINAL { return false; }

    virtual AbstractDOMWindow* virtualWindow() const FINAL;

	HashSet<FrameDestructionObserver*> m_destructionObservers;

	Frame* m_mainFrame;
	Page* m_page;
	const RefPtr<Settings> m_settings;
	mutable FrameTree m_treeNode;
	mutable FrameLoader m_loader;
	mutable NavigationScheduler m_navigationScheduler;

	HTMLFrameOwnerElement* m_ownerElement;
	RefPtr<FrameView> m_view;
	RefPtr<Document> m_doc;

	OwnPtr<ScriptController> m_script;

	mutable EventHandler m_eventHandler;

	float m_pageZoomFactor;
	float m_textZoomFactor;

#if ENABLE(ORIENTATION_EVENTS)
	int m_orientation;
#endif

#if USE(TILED_BACKING_STORE)
// FIXME: The tiled backing store belongs in FrameView, not Frame.

public:
	TiledBackingStore* tiledBackingStore() const { return m_tiledBackingStore.get(); }
	void setTiledBackingStoreEnabled(bool);

private:
	// TiledBackingStoreClient interface
	virtual void tiledBackingStorePaintBegin() override;
	virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&) override;
	virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea) override;
	virtual IntRect tiledBackingStoreContentsRect() override;
	virtual IntRect tiledBackingStoreVisibleRect() override;
	virtual Color tiledBackingStoreBackgroundColor() const override;

	OwnPtr<TiledBackingStore> m_tiledBackingStore;
#endif

	int m_activeDOMObjectsAndAnimationsSuspendedCount;
    bool m_documentIsBeingReplaced;
    unsigned m_navigationDisableCount;
    bool m_hasHadUserInteraction { false };
    friend class NavigationDisabler;
};

inline void Frame::init()
{
	m_loader.init();
}

ALWAYS_INLINE FrameLoader* Frame::loader() const
{
	return &m_loader;
}

ALWAYS_INLINE NavigationScheduler* Frame::navigationScheduler() const
{
	return &m_navigationScheduler;
}

ALWAYS_INLINE FrameView* Frame::view() const
{
	return m_view.get();
}

ALWAYS_INLINE ScriptController* Frame::script()
{
	return m_script.get();
}

ALWAYS_INLINE Document* Frame::document() const
{
	return m_doc.get();
}

ALWAYS_INLINE HTMLFrameOwnerElement* Frame::ownerElement() const
{
	return m_ownerElement;
}

ALWAYS_INLINE FrameTree* Frame::tree() const
{
	return &m_treeNode;
}

ALWAYS_INLINE Page* Frame::page() const
{
	return m_page;
}

ALWAYS_INLINE void Frame::detachFromPage()
{
	m_page = nullptr;
}

ALWAYS_INLINE EventHandler* Frame::eventHandler() const
{
	return &m_eventHandler;
}

inline Frame* Frame::mainFrame() const
{
    return m_mainFrame;
}

} // namespace WebCore

#include "Document.h"
#include "DocumentLoader.h"

namespace WebCore {

inline FrameView* Document::view() const
{
    return m_frame ? m_frame->view() : nullptr;
}

inline Page* Document::page() const
{
    return m_frame ? m_frame->page() : nullptr;
}

inline Frame* DocumentLoader::frame() const
{
	return m_frame.get();
}

inline Frame* FrameDestructionObserver::frame() const
{
    return m_frame.get();
}

}

#if 0
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Frame)
    static bool isType(const WebCore::AbstractFrame& frame) { return frame.isLocalFrame(); }
SPECIALIZE_TYPE_TRAITS_END()
#endif
