/* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
**
** Copyright (C) 2011 Opera Software ASA.  All rights reserved.
**
** This file is part of the Opera web browser.  It may not be distributed
** under any circumstances. */

group "doc.nearby_interactive_item_detection";

// FEATURE_NEARBY_INTERACTIVE_ITEM_DETECTION selftests (doc part)

require init;
require NEARBY_INTERACTIVE_ITEM_DETECTION;

language C++;

include "modules/dochand/win.h";
include "modules/doc/frm_doc.h";
include "modules/dochand/fdelm.h";
include "modules/selftest/src/doc_st_utils.h";
include "modules/doc/html_doc.h";
include "modules/windowcommander/src/WindowCommander.h";
include "modules/dochand/viewportcontroller.h";

global
{
	UINT NumberElementsOfType(const Head& item_list, InteractiveItemInfo::Type type)
	{
		UINT count = 0;

		InteractiveItemInfo* iter = static_cast<InteractiveItemInfo*>(item_list.First());
		while (iter)
		{
			if (iter->GetType() == type)
				count++;

			iter = iter->Suc();
		}

		return count;
	}

	UINT NumberOfRectsOfType(const Head& item_list, InteractiveItemInfo::Type type)
	{
		InteractiveItemInfo* iter = static_cast<InteractiveItemInfo*>(item_list.First());

		while (iter)
		{
			if (iter->GetType() == type)
				return iter->GetNumberOfRects();

			iter = iter->Suc();
		}

		return 0;
	}

	BOOL HasRect(const Head& item_list, InteractiveItemInfo::Type type, const OpRect& rect)
	{
		InteractiveItemInfo* iter = static_cast<InteractiveItemInfo*>(item_list.First());

		while (iter)
		{
			if (iter->GetType() == type)
			{
				const InteractiveItemInfo::ItemRect* rect_array = iter->GetRects();
				unsigned int rect_count = iter->GetNumberOfRects();

				for (unsigned int i=0; i < rect_count; i++)
					if (st_rects_equal(rect, rect_array[i].rect))
						return TRUE;
			}

			iter = iter->Suc();
		}

		return FALSE;
	}

	BOOL HasUrl(const Head& item_list, InteractiveItemInfo::Type type, const char* url)
	{
		InteractiveItemInfo* iter = static_cast<InteractiveItemInfo*>(item_list.First());

		while (iter)
		{
			if (iter->GetType() == type)
			{
				BOOL res;
				res = iter->GetURL().CStr() != NULL;

				if (res)
				{
					res = uni_strcmp(iter->GetURL().CStr(), url) == 0;

					if (res)
						return res;
				}
			}

			iter = iter->Suc();
		}

		return FALSE;
	}

	BOOL HasDocumentContext(const Head& item_list, InteractiveItemInfo::Type type)
	{
		InteractiveItemInfo* iter = static_cast<InteractiveItemInfo*>(item_list.First());

		while (iter)
		{
			if (iter->GetType() == type)
				return !!iter->GetDocumentContext();	

			iter = iter->Suc();
		}

		return FALSE;
	}
}

table dummy(const char *) filelist "tests/nearby_interactive_item_detection" recursively;

test("PRECONDITION: AHEM")
{
	//short font_number = styleManager->GetFontNumber(UNI_L("AHEM"));
	//verify(font_number != -1);
}

html
{
//!<!DOCTYPE html>
//!<html>
//!
//!<head>
//!<script>
//!
//!function handle_evt_dummy()
//!{
//!}
//!
//!function on_load()
//!{
//!	var element = document.getElementById("block_with_mouse_down");
//!	element.addEventListener("mousedown", handle_evt_dummy, false);
//!
//!	element = document.getElementById("dummy");
//!	element.setAttribute("id", "function_executed");
//!}
//!
//!window.onload = on_load;
//!
//!</script>
//!<style>
//!
//!*
//!{
//!	margin:0;padding:0;
//!	font-family:'AHEM';
//!	font-size:16px;
//!}
//!
//!#with_usemap
//!{
//!	width:50px;
//!	height:50px;
//!}
//!
//!#block_with_mouse_down
//!{
//!	width:50px;
//!	height:50px;
//!	background-color:yellow;
//!}
//!
//!#form_input
//!{
//!	width:50px;
//!	height:20px;
//!}
//!
//!#form_checkbox
//!{
//!	width:20px;
//!	height:20px;
//!}
//!
//!#form_select
//!{
//!	width:50px;
//!	height:20px;
//!}
//!
//!div.absolute_child
//!{
//!	width:20px;
//!	height:20px;
//!	background-color:orange;
//!	position:absolute;
//!	top:30px;
//!	left:80px;
//!}
//!
//!#scrollable
//!{
//!	width:50px;
//!	height:50px;
//!	background-color:blue;
//!	overflow:auto;
//!}
//!
//!div.inside_scrollable
//!{
//!	width:200px;
//!	height:50px;
//! background-color:red;
//!}
//!
//!#absolute_anchor
//!{
//!	width:20px;
//!	height:20px;
//!	display:block;
//!	position:absolute;
//!	top:60px;
//!	left:80px;
//!	background-color:black;
//!}
//!p.dummy
//!{
//!	visibility:hidden;
//!}
//!
//!</style>
//!</head>
//!
//!<body>
//!<a id="anchor" href="#">LINK<div class="absolute_child"></div></a>
//!
//!<form>
//!<input id="form_input" type="text" /> <br />
//!<input id="form_checkbox" type="checkbox" /> <br />
//!<select id="form_select">
//!<option>dummy</option>
//!</select>
//!</form>
//!
//!<img id="with_usemap" usemap="#the_usemap" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oLHQwQJ0wAdeQAAAANSURBVAjXY2BoYPgPAAKEAYABADlnAAAAAElFTkSuQmCC=" />
//!
//!<div id="block_with_mouse_down">
//!</div>
//!
//!<div id="block_with_mouse_move">
//!</div>
//!
//!<button id="generic_button" type="button">Button</button><br/>
//!
//!<div id="scrollable">
//!<div class="inside_scrollable">
//!</div>
//!</div>
//!
//!<a id="absolute_anchor" href="#"></a>
//!
//!<p class="dummy" id="dummy"></p>
//!
//!</body>
//!
//!<map name="the_usemap">
//!<area id="usemap_area" shape="default" href="#">
//!</map>
//!
//!</html>
}
test("wait until event handlers attached") async;
	require success "PRECONDITION: AHEM";
{
	if (!state.doc)
		ST_failed("There is no document!");
	else
		CheckJSFunctionExecutedObj::WaitUntilJSFunctionExecuted(state.doc);
}
test("single doc nearby interactive item detection")
	require success "wait until event handlers attached";
	/** Tests whether the InteractiveItemInfo list is properly filled. And whether
		the HTML_Document::FindNearbyLinks sets the search rectangle and extended area
		rectangle properly. */
{
	HTML_Document* html_doc = state.doc->GetHtmlDocument();
	AutoDeleteList<InteractiveItemInfo> item_list;
	OpRect search_rect(0, 0, 50, 1000), fake_viewport_rect(0, 0, 1000, 1000), old_viewport_rect;
	int negative_overflow = state.doc ? state.doc->NegativeOverflow() : 0;
	ViewportController* viewCtrl = state.doc ? state.doc->GetWindow()->GetViewportController() : NULL;
	BOOL viewport_size_faked = FALSE;

	verify(viewCtrl);
	verify(html_doc);
	verify(negative_overflow == 0); // shouldn't be any for that doc

	old_viewport_rect = state.doc->GetVisualViewport();
	// Fake visual viewport size
	viewCtrl->LockVisualViewportSize(FALSE);
	viewCtrl->SetVisualViewport(fake_viewport_rect);
	viewport_size_faked = TRUE;

	OP_STATUS status = html_doc->FindNearbyInteractiveItems(search_rect, item_list);

	verify(OpStatus::IsSuccess(status));

	verify(item_list.Cardinal() == 9);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_ANCHOR) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_BUTTON) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_CUSTOM_POINTER_ACTION) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_CHECKBOX) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_SELECT) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_SCROLLBAR) == 2);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_USEMAP_AREA) == 1);

	// additional rect of the anchor that comes from abs positioned element and that does not intersect the search_rect
	verify(NumberOfRectsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_ANCHOR) == 2);
}
finally
{
	if (viewport_size_faked)
	{
		viewCtrl->SetVisualViewport(old_viewport_rect);
		viewCtrl->LockVisualViewportSize(TRUE);
	}
}

html
{
//!<!DOCTYPE html>
//!<html>
//!<head>
//!<script>
//!
//!function handle_evt_dummy()
//!{
//!}
//!
//!</script>
//!<style>
//!
//!#block_with_touchstart
//!{
//!	width:50px;
//!	height:50px;
//!	background-color:yellow;
//!}
//!
//!</style>
//!</head>
//!<body>
//!
//!<div id="block_with_touchstart" ontouchstart="handle_evt_dummy()" ></div>
//!
//!</body>
//!
//!</html>
}
test("touch events test")
	require success "wait until event handlers attached";
	require TOUCH_EVENTS_SUPPORT;
{
	HTML_Document* html_doc = state.doc->GetHtmlDocument();
	AutoDeleteList<InteractiveItemInfo> item_list;
	OpRect search_rect(0, 0, 50, 1000), fake_viewport_rect(0, 0, 1000, 1000), old_viewport_rect;
	int negative_overflow = state.doc ? state.doc->NegativeOverflow() : 0;
	ViewportController* viewCtrl = state.doc ? state.doc->GetWindow()->GetViewportController() : NULL;
	BOOL viewport_size_faked = FALSE;

	verify(viewCtrl);
	verify(html_doc);
	verify(negative_overflow == 0); // shouldn't be any for that doc

	old_viewport_rect = state.doc->GetVisualViewport();
	// Fake visual viewport size
	viewCtrl->LockVisualViewportSize(FALSE);
	viewCtrl->SetVisualViewport(fake_viewport_rect);
	viewport_size_faked = TRUE;

	OP_STATUS status = html_doc->FindNearbyInteractiveItems(search_rect, item_list);

	verify(OpStatus::IsSuccess(status));

	verify(item_list.Cardinal() == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_CUSTOM_TOUCH_ACTION) == 1);
}
finally
{
	if (viewport_size_faked)
	{
		viewCtrl->SetVisualViewport(old_viewport_rect);
		viewCtrl->LockVisualViewportSize(TRUE);
	}
}


test("load frame scrollbars document") async;
	require success "PRECONDITION: AHEM";
	file uni frame_scrollbars "tests/nearby_interactive_item_detection/frame_scrollbars/top_doc.htm";
{
	Window* win = state.GetWindow();
	if (!win)
		ST_failed("No window!");
	else
		WaitUntilLoadedObj::LoadAndWaitUntilLoaded(win, frame_scrollbars);
}
test("frame scrollbars")
	require success "load frame scrollbars document";
	/** Tests whether the FramesDocument::FindNearbyLinks collects the scrollbars
		that belong to the frames. */
{
	AutoDeleteList<InteractiveItemInfo> item_list;
	OpRect search_rect_for_three(160, 110, 80, 200),
		   search_rect_for_one(180, 115, 100, 20),
		   search_rect_for_zero(10, 10, 10, 10),
		   fake_viewport_rect(0, 0, 1000, 1000), old_viewport_rect;
	int negative_overflow = state.doc ? state.doc->NegativeOverflow() : 0;
	ViewportController* viewCtrl = state.doc ? state.doc->GetWindow()->GetViewportController() : NULL;
	AffinePos zero_pos(0, 0);
	BOOL viewport_size_faked = FALSE;

	verify(negative_overflow == 0); // Shouldn't be any for that doc.
	verify(viewCtrl);

	old_viewport_rect = state.doc->GetVisualViewport();
	// Fake visual viewport size
	viewCtrl->LockVisualViewportSize(FALSE);
	viewCtrl->SetVisualViewport(fake_viewport_rect);
	viewport_size_faked = TRUE;

	OP_STATUS status = state.doc->FindNearbyInteractiveItems(search_rect_for_three, item_list, zero_pos);
	verify(OpStatus::IsSuccess(status));
#ifdef SUPPORT_TEXT_DIRECTION
	verify(item_list.Cardinal() == 3);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_SCROLLBAR) == 3);
#else // !SUPPORT_TEXT_DIRECTION
	verify(item_list.Cardinal() == 2);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_SCROLLBAR) == 2);
#endif // SUPPORT_TEXT_DIRECTION

	item_list.Clear();

	status = state.doc->FindNearbyInteractiveItems(search_rect_for_one, item_list, zero_pos);
	verify(OpStatus::IsSuccess(status));

	verify(item_list.Cardinal() == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_SCROLLBAR) == 1);

	item_list.Clear();

	status = state.doc->FindNearbyInteractiveItems(search_rect_for_zero, item_list, zero_pos);
	verify(OpStatus::IsSuccess(status));

	verify(item_list.Cardinal() == 0);
}
finally
{
	if (viewport_size_faked)
	{
		viewCtrl->SetVisualViewport(old_viewport_rect);
		viewCtrl->LockVisualViewportSize(TRUE);
	}
}

test("load multi frame search document") async;
	require success "PRECONDITION: AHEM";
	file uni multi_frame_search "tests/nearby_interactive_item_detection/multi_frame_search/top_doc.htm";
{
	Window* win = state.GetWindow();
	if (!win)
		ST_failed("No window!");
	else
		WaitUntilLoadedObj::LoadAndWaitUntilLoaded(win, multi_frame_search);
}
test("wait until event handlers attached 2") async;
	require success "load multi frame search document";
{
	if (!state.doc)
		ST_failed("There is no document!");
	else
	{
		FramesDocElm* second_iframe = DocSTUtils::GetFrameById(state.doc, "right_iframe");

		if (!second_iframe)
			ST_failed("NULL pointer!");
		else
		{
			FramesDocument* second_iframe_doc = second_iframe->GetCurrentDoc();
			if (!second_iframe_doc)
				ST_failed("NULL pointer!");
			else
				CheckJSFunctionExecutedObj::WaitUntilJSFunctionExecuted(second_iframe_doc);
		}
	}
}
test("multi frame search and clip test")
	require success "wait until event handlers attached 2";
	/** Tests whether each element from two iframes and top document will be found.
		Tests also whether an anchor in left iframe will have the rect reduced to the
		visible iframe part. */
{
	AutoDeleteList<InteractiveItemInfo> item_list;
	OpRect search_rect(170, 0, 60, 45),
		   fake_viewport_rect(0, 0, 1000, 1000),
		   old_viewport_rect;
	int negative_overflow = state.doc ? state.doc->NegativeOverflow() : 0;
	int scrollbar_width = 0;
	ViewportController* viewCtrl = state.doc ? state.doc->GetWindow()->GetViewportController() : NULL;
	AffinePos zero_pos(0, 0);
	FramesDocElm* first_iframe = DocSTUtils::GetFrameById(state.doc, "left_iframe");
	BOOL viewport_size_faked = FALSE;

	verify(viewCtrl);
	verify(negative_overflow == 0); // shouldn't be any for that doc
	verify(first_iframe);

	FramesDocument* first_iframe_doc = first_iframe->GetCurrentDoc();
	verify(first_iframe_doc);

	VisualDevice *frame_dev = first_iframe_doc->GetVisualDevice();
	OpScrollbar* v_scr, *dummy;

	frame_dev->GetScrollbarObjects(&dummy, &v_scr);

	verify(v_scr && v_scr->IsVisible());
	scrollbar_width = frame_dev->ScaleToDoc(v_scr->GetWidth());
	verify(scrollbar_width < 40); // so that we don't have the anchor's rect totally covered by the scrollbar

	old_viewport_rect = state.doc->GetVisualViewport();
	// Fake visual viewport size
	viewCtrl->LockVisualViewportSize(FALSE);
	viewCtrl->SetVisualViewport(fake_viewport_rect);
	viewport_size_faked = TRUE;

	OP_STATUS status = state.doc->FindNearbyInteractiveItems(search_rect, item_list, zero_pos);
	verify(OpStatus::IsSuccess(status));

	verify(item_list.Cardinal() == 4);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_SCROLLBAR) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_ANCHOR) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_CUSTOM_POINTER_ACTION) == 1);

	// additional rect of a div with evt handler that comes from abs positioned element and that does not intersect the search_rect
	verify(NumberOfRectsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_CUSTOM_POINTER_ACTION) == 2);

	verify(HasRect(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_ANCHOR, OpRect(160, 25, 40 - scrollbar_width, 20)));
}
finally
{
	if (viewport_size_faked)
	{
		viewCtrl->SetVisualViewport(old_viewport_rect);
		viewCtrl->LockVisualViewportSize(TRUE);
	}
}

test("load overlapped iframe doc") async;
	require success "PRECONDITION: AHEM";
	file uni overlapped_iframe "tests/nearby_interactive_item_detection/overlapped_iframe/top_doc.htm";
{
	Window* win = state.GetWindow();
	if (!win)
		ST_failed("No window!");
	else
		WaitUntilLoadedObj::LoadAndWaitUntilLoaded(win, overlapped_iframe);
}
test("overlapped iframe")
	require success "load overlapped iframe doc";
	// Tests whether overlapped iframe won't be searched links in.
{
	AutoDeleteList<InteractiveItemInfo> item_list;
	OpRect search_rect(20, 20, 40, 20),
		   fake_viewport_rect(0, 0, 200, 200),
		   old_viewport_rect;
	int negative_overflow = state.doc ? state.doc->NegativeOverflow() : 0;
	ViewportController* viewCtrl = state.doc ? state.doc->GetWindow()->GetViewportController() : NULL;
	AffinePos zero_pos(0, 0);
	BOOL viewport_size_faked = FALSE;

	verify(viewCtrl);
	verify(negative_overflow == 0); // shouldn't be any for that doc

	old_viewport_rect = state.doc->GetVisualViewport();
	// Fake visual viewport size
	viewCtrl->LockVisualViewportSize(FALSE);
	viewCtrl->SetVisualViewport(fake_viewport_rect);
	viewport_size_faked = TRUE;

	OP_STATUS status = state.doc->FindNearbyInteractiveItems(search_rect, item_list, zero_pos);
	verify(OpStatus::IsSuccess(status));

	// We shouldn't hit anchor in iframe
	verify(item_list.Cardinal() == 0);
}
finally
{
	if (viewport_size_faked)
	{
		viewCtrl->SetVisualViewport(old_viewport_rect);
		viewCtrl->LockVisualViewportSize(TRUE);
	}
}

test("load transformed iframe doc") async;
	require CSS_TRANSFORMS;
	require success "PRECONDITION: AHEM";
	file uni transformed_iframe "tests/nearby_interactive_item_detection/transformed_iframe/top_doc.htm";
{
	Window* win = state.GetWindow();
	if (!win)
		ST_failed("No window!");
	else
		WaitUntilLoadedObj::LoadAndWaitUntilLoaded(win, transformed_iframe);
}
test("transformed iframe")
	require success "load transformed iframe doc";
	/**	Tests the behavior of NEARBY_INTERACTIVE_ITEM_DETECTION in case of transformed iframe.
		It is expected to give false positive (an element that is not visible will be hit). */
{
	AutoDeleteList<InteractiveItemInfo> item_list;
	OpRect search_rect(0, 0, 142, 142), // 142 ~= 200 (iframe size) / sqrt(2)
		   fake_viewport_rect(0, 0, 142, 142),
		   old_viewport_rect;
	int negative_overflow = state.doc ? state.doc->NegativeOverflow() : 0;
	int old_width = 0, old_height = 0;
	ViewportController* viewCtrl = state.doc ? state.doc->GetWindow()->GetViewportController() : NULL;
	CoreView* view = state.doc->GetVisualDevice()->GetView();
	AffinePos zero_pos(0, 0);
	BOOL viewport_size_faked = FALSE;

	verify(viewCtrl);
	verify(negative_overflow == 0); // shouldn't be any for that doc

	old_viewport_rect = state.doc->GetVisualViewport();
	view->GetSize(&old_width, &old_height);
	// Fake visual viewport size
	viewCtrl->LockVisualViewportSize(FALSE);
	viewCtrl->SetVisualViewport(fake_viewport_rect);
	// Fake top doc's CoreViewContainer size
	ST_CoreViewHacks::FakeCoreViewSize(view, 142, 142);
	viewport_size_faked = TRUE;

	OP_STATUS status = state.doc->FindNearbyInteractiveItems(search_rect, item_list, zero_pos);
	verify(OpStatus::IsSuccess(status));

	// We should hit an anchor + text input, which is a false positive
	verify(item_list.Cardinal() == 2);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_ANCHOR) == 1); // visible and should be hit
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT) == 1); // not visible and hit (false positive).
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_CHECKBOX) == 0); // not visible and correctly not hit.
}
finally
{
	if (viewport_size_faked)
	{
		ST_CoreViewHacks::FakeCoreViewSize(view, old_width, old_height);
		viewCtrl->SetVisualViewport(old_viewport_rect);
		viewCtrl->LockVisualViewportSize(TRUE);
	}
}

html
{
//!<!DOCTYPE html>
//!<html>
//!
//!<body>
//!
//!<form action="http://somewebpage.com/" method="GET">
//!<input type="text" name="the_input" />
//!<input type="submit" disabled />
//!</form>
//!
//!<input type="checkbox" />
//!<a href="http://www.opera.com/">LINK</a>
//!
//!</body>
//!
//!</html>
}
test("url, title strings and document context")
{
	AutoDeleteList<InteractiveItemInfo> item_list;
	OpRect search_rect(0, 0, 1000, 1000),
		   fake_viewport_rect(0, 0, 1000, 1000),
		   old_viewport_rect;
	HTML_Document* html_doc = state.doc ? state.doc->GetHtmlDocument() : NULL;
	int negative_overflow = state.doc ? state.doc->NegativeOverflow() : 0;
	ViewportController* viewCtrl = state.doc ? state.doc->GetWindow()->GetViewportController() : NULL;
	BOOL viewport_size_faked = FALSE;

	verify(viewCtrl);
	verify(html_doc);
	verify(negative_overflow == 0); // shouldn't be any for that doc

	old_viewport_rect = state.doc->GetVisualViewport();

	// Fake visual viewport size
	viewCtrl->LockVisualViewportSize(FALSE);
	viewCtrl->SetVisualViewport(fake_viewport_rect);
	viewport_size_faked = TRUE;

	OP_STATUS status = html_doc->FindNearbyInteractiveItems(search_rect, item_list);
	verify(OpStatus::IsSuccess(status));

	verify(item_list.Cardinal() == 3);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_ANCHOR) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT) == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_CHECKBOX) == 1);

	verify(HasUrl(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_CHECKBOX, ""));
	verify(HasDocumentContext(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_CHECKBOX) == FALSE);

	verify(HasUrl(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_ANCHOR, "http://www.opera.com/"));
	verify(HasDocumentContext(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_ANCHOR) == FALSE);

	verify(HasUrl(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT, ""));
	verify(HasDocumentContext(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT) == TRUE);
}
finally
{
	if (viewport_size_faked)
	{
		viewCtrl->SetVisualViewport(old_viewport_rect);
		viewCtrl->LockVisualViewportSize(TRUE);
	}
}

html
{
//<!DOCTYPE html>
//!<html>
//!
//!<body>
//!
//!<form action="http://somewebpage.com/" method="GET">
//!<input type="password" name="the_input" />
//!<input type="submit" disabled />
//!</form>
//!
//!</body>
//!
//!</html>
}
test("url, title and document context for text input other than INPUT_TEXT")
	/* input types INPUT_SEARCH, INPUT_NUMBER, INPUT_EMAIL and INPUT_URI
	   fall in the same category as INPUT_TEXT. */
{
	AutoDeleteList<InteractiveItemInfo> item_list;
	OpRect search_rect(0, 0, 1000, 1000),
		   fake_viewport_rect(0, 0, 1000, 1000),
		   old_viewport_rect;
	HTML_Document* html_doc = state.doc ? state.doc->GetHtmlDocument() : NULL;
	int negative_overflow = state.doc ? state.doc->NegativeOverflow() : 0;
	ViewportController* viewCtrl = state.doc ? state.doc->GetWindow()->GetViewportController() : NULL;
	BOOL viewport_size_faked = FALSE;

	verify(viewCtrl);
	verify(html_doc);
	verify(negative_overflow == 0); // shouldn't be any for that doc

	old_viewport_rect = state.doc->GetVisualViewport();

	// Fake visual viewport size
	viewCtrl->LockVisualViewportSize(FALSE);
	viewCtrl->SetVisualViewport(fake_viewport_rect);
	viewport_size_faked = TRUE;

	OP_STATUS status = html_doc->FindNearbyInteractiveItems(search_rect, item_list);
	verify(OpStatus::IsSuccess(status));

	verify(item_list.Cardinal() == 1);
	verify(NumberElementsOfType(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT) == 1);

	verify(HasUrl(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT, ""));
	verify(HasDocumentContext(item_list, InteractiveItemInfo::INTERACTIVE_ITEM_TYPE_FORM_INPUT) == TRUE);
}
finally
{
	if (viewport_size_faked)
	{
		viewCtrl->SetVisualViewport(old_viewport_rect);
		viewCtrl->LockVisualViewportSize(TRUE);
	}
}
