Index: webkit/tools/test_shell/test_shell.h
===================================================================
--- webkit/tools/test_shell/test_shell.h	(revision 2056)
+++ webkit/tools/test_shell/test_shell.h	(working copy)
@@ -34,6 +34,7 @@
 #include "base/basictypes.h"
 #include "base/gfx/native_widget_types.h"
 #include "base/ref_counted.h"
+#include "chrome/browser/printing/win_printing_context.h"
 #include "webkit/tools/test_shell/event_sending_controller.h"
 #include "webkit/tools/test_shell/layout_test_controller.h"
 #include "webkit/tools/test_shell/resource.h"
@@ -217,6 +218,23 @@
     void set_is_modal(bool value) { is_modal_ = value; }
     bool is_modal() const { return is_modal_; }
 
+    // Switches the frame's CSS media type to "print" and calculate the number of
+    // printed pages that are to be expected. |frame| will be used to calculate
+    // the number of expected pages for this frame only.
+    int SwitchFrameToPrintMediaType(WebFrame* frame);
+	
+	// Switches the frame's CSS media type to "display".
+    void SwitchFrameToDisplayMediaType(WebFrame* frame);
+
+	// Prints the page listed in |params|.
+	void PrintPage(int page_number, WebFrame* frame);
+
+    // Prints all the pages listed in |params|.
+	void PrintPages(WebFrame* frame);
+
+	// Return the available number of pages based on the current printer settings.
+	int GetPagesCount(WebFrame* frame);
+
 protected:
     bool Initialize(const std::wstring& startingURL);
     void SizeToDefault();
@@ -286,6 +304,15 @@
 
     // Dump the stats table counters on exit.
     bool dump_stats_table_on_exit_;
+
+	// Document width when in print CSS media type. 0 otherwise.
+	int printed_document_width_;
+
+	// Backup the view size before printing since it needs to be overriden. This
+	// value is set to restore the view size when printing is done.
+	gfx::Size printing_view_size_;
+
+	printing::PrintingContext print_context_;
 };
 
 #endif // WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_H_
Index: webkit/tools/test_shell/resource.h
===================================================================
--- webkit/tools/test_shell/resource.h	(revision 2056)
+++ webkit/tools/test_shell/resource.h	(working copy)
@@ -10,6 +10,7 @@
 #define IDD_ABOUTBOX              103
 #define IDM_ABOUT                 104
 #define IDM_EXIT                  105
+#define IDM_PRINT                 106
 #define IDM_DUMP_BODY_TEXT        110
 #define IDM_DUMP_RENDER_TREE      111
 #define IDM_SHOW_WEB_INSPECTOR    112
Index: webkit/tools/test_shell/test_shell.cc
===================================================================
--- webkit/tools/test_shell/test_shell.cc	(revision 2056)
+++ webkit/tools/test_shell/test_shell.cc	(working copy)
@@ -8,6 +8,7 @@
 #include <objbase.h>
 #include <shlwapi.h>
 #include <wininet.h>
+#include <winspool.h>
 
 #include "webkit/tools/test_shell/test_shell.h"
 
@@ -16,6 +17,7 @@
 #include "base/file_util.h"
 #include "base/gfx/bitmap_platform_device_win.h"
 #include "base/gfx/png_encoder.h"
+#include "base/gfx/vector_canvas.h"
 #include "base/gfx/size.h"
 #include "base/icu_util.h"
 #include "base/md5.h"
@@ -26,6 +28,7 @@
 #include "base/string_util.h"
 #include "base/trace_event.h"
 #include "base/win_util.h"
+#include "chrome/common/render_messages.h"
 #include "googleurl/src/url_util.h"
 #include "net/base/mime_util.h"
 #include "net/url_request/url_request_file_job.h"
@@ -40,6 +43,7 @@
 #include "webkit/glue/webview.h"
 #include "webkit/glue/webwidget.h"
 #include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/port/platform/graphics/PlatformContextSkia.h"
 #include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
 #include "webkit/tools/test_shell/test_navigation_controller.h"
 
@@ -320,6 +324,16 @@
       SizeToDefault();
     }
 
+	TCHAR printername[512];
+	DWORD size = sizeof(printername)-1;
+	if(GetDefaultPrinter(printername, &size))
+	{
+		printing::PrintSettings settings;
+		settings.set_device_name(printername);
+		// Initialize it.
+		print_context_.InitWithSettings(settings);
+	}
+
     return true;
 }
 
@@ -440,6 +454,173 @@
 }
 
 
+int TestShell::SwitchFrameToPrintMediaType(WebFrame* frame) {
+  ViewMsg_Print_Params params;
+  print_context_.settings().RenderParams(&params);
+
+  float ratio = static_cast<float>(params.desired_dpi / params.dpi);
+  float paper_width = params.printable_size.width() * ratio;
+  float paper_height = params.printable_size.height() * ratio;
+  float minLayoutWidth = static_cast<float>(paper_width * params.min_shrink);
+  float maxLayoutWidth = static_cast<float>(paper_width * params.max_shrink);
+
+  // Safari uses: 765 & 1224. Margins aren't exactly the same either.
+  // Scale = 2.222 for MDI printer.
+  int pages;
+  if (!frame->SetPrintingMode(true,
+                              minLayoutWidth,
+                              maxLayoutWidth,
+                              &printed_document_width_)) {
+    NOTREACHED();
+    pages = 0;
+  } else {
+    // Force to recalculate the height, otherwise it reuse the current window
+    // height as the default.
+    float effective_shrink = printed_document_width_ / paper_width;
+    gfx::Size page_size(printed_document_width_,
+                        static_cast<int>(paper_height * effective_shrink) - 1);
+    WebView* view = frame->GetView();
+    if (view) {
+      // Hack around an issue where if the current view height is higher than
+      // the page height, empty pages will be printed even if the bottom of the
+      // web page is empty.
+      printing_view_size_ = view->GetSize();
+      view->Resize(page_size);
+      view->Layout();
+    }
+    pages = frame->ComputePageRects(params.printable_size);
+    DCHECK(pages);
+  }
+  return pages;
+}
+
+void TestShell::SwitchFrameToDisplayMediaType(WebFrame* frame) {
+  // Set the layout back to "normal" document; i.e. CSS media type = "screen".
+  frame->SetPrintingMode(false, 0, 0, NULL);
+  WebView* view = frame->GetView();
+  if (view) {
+    // Restore from the hack described at SwitchFrameToPrintMediaType().
+    view->Resize(printing_view_size_);
+    view->Layout();
+    printing_view_size_.SetSize(0, 0);
+  }
+  printed_document_width_ = 0;
+}
+
+void TestShell::PrintPage(int page_number, WebFrame* frame) {
+  if (printed_document_width_ <= 0) {
+    NOTREACHED();
+    return;
+  }
+
+  ViewMsg_Print_Params params;
+  print_context_.settings().RenderParams(&params);
+
+  gfx::Rect rect;
+  frame->GetPageRect(page_number-1, &rect);
+  DCHECK(rect.height());
+  DCHECK(rect.width());
+  double shrink = static_cast<double>(printed_document_width_) /
+                  params.printable_size.width();
+  // This check would fire each time the page would get truncated on the
+  // right. This is not worth a DCHECK() but should be looked into, for
+  // example, wouldn't be worth trying in landscape?
+  // DCHECK_LE(rect.width(), printed_document_width_);
+
+  // Buffer one page at a time.
+  int src_size_x = printed_document_width_;
+  int src_size_y =
+      static_cast<int>(ceil(params.printable_size.height() *
+                            shrink));
+
+
+  print_context_.NewPage();
+
+  HDC hDC = print_context_.context();
+  BOOL res;
+  
+  // Save the state to make sure the context this function call does not modify
+  // the device context.
+  int saved_state = SaveDC(hDC);
+  DCHECK_NE(saved_state, 0);
+
+  gfx::PlatformDeviceWin::InitializeDC(hDC);
+  
+  // Setup the matrix to translate and scale to the right place. Take in
+  // account the actual shrinking factor.
+  XFORM xform = { 0 };
+  xform.eDx = static_cast<float>(src_size_x);
+  xform.eDy = static_cast<float>(src_size_y);
+  xform.eM11 = static_cast<float>(1. / shrink);
+  xform.eM22 = static_cast<float>(1. / shrink);
+  res = ModifyWorldTransform(hDC, &xform, MWT_LEFTMULTIPLY);
+  DCHECK_NE(res, 0);
+
+  // 100% GDI based.
+  gfx::VectorCanvas canvas(hDC, src_size_x, src_size_y);
+  PlatformContextSkia context(&canvas);
+  // Set the clipping region to be sure to not overflow.
+  SkRect clip_rect;
+  clip_rect.set(0, 0, SkIntToScalar(src_size_x), SkIntToScalar(src_size_y));
+  canvas.clipRect(clip_rect);
+  
+  if (!frame->SpoolPage(page_number-1, &context)) {
+    NOTREACHED() << "Printing page " << page_number << " failed.";
+    return;
+  }
+
+  res = RestoreDC(hDC, saved_state);
+  DCHECK_NE(res, 0);
+
+  print_context_.PageDone();
+}
+
+void TestShell::PrintPages(WebFrame* frame) {
+  
+  if(print_context_.AskUserForSettings(m_mainWnd, GetPagesCount(frame)) != printing::PrintingContext::OK)
+    return;
+
+  ViewMsg_Print_Params params;
+  const printing::PrintSettings &settings = print_context_.settings();
+  
+  settings.RenderParams(&params);
+  
+  int pages = SwitchFrameToPrintMediaType(frame);
+  if (pages)
+  {
+    bool old_state = MessageLoop::current()->NestableTasksAllowed();
+	MessageLoop::current()->SetNestableTasksAllowed(false);
+
+	print_context_.NewDocument(L"New Document", false);
+	if(settings.ranges.size() > 0)
+	{
+		for (unsigned i = 0; i < settings.ranges.size(); ++i)
+		{
+			const printing::PageRange& range = settings.ranges[i];
+			for(int i = range.from; i <= range.to; ++i)
+				PrintPage(i, frame);
+		}
+	}
+	else
+	{
+		for(int i = 1; i <= pages; ++i)
+			PrintPage(i, frame);
+	}
+	print_context_.DocumentDone();
+
+	MessageLoop::current()->SetNestableTasksAllowed(old_state);
+  }
+  SwitchFrameToDisplayMediaType(frame);
+}
+
+int TestShell::GetPagesCount(WebFrame* frame)
+{
+	int pages = SwitchFrameToPrintMediaType(frame);
+	SwitchFrameToDisplayMediaType(frame);
+	return pages;
+}
+
+
 /*static*/
 bool TestShell::CreateNewWindow(const std::wstring& startingURL,
                                 TestShell** result) {
@@ -706,6 +887,9 @@
                 DialogBox(shell->instance_handle_, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd,
                           About);
                 break;
+            case IDM_PRINT:
+				shell->PrintPages(shell->webView()->GetFocusedFrame());
+				break;
             case IDM_EXIT:
                 DestroyWindow(hwnd);
                 break;
Index: webkit/tools/test_shell/resources/test_shell.rc
===================================================================
--- webkit/tools/test_shell/resources/test_shell.rc	(revision 2056)
+++ webkit/tools/test_shell/resources/test_shell.rc	(working copy)
@@ -38,6 +38,7 @@
     POPUP "&File"
     BEGIN
         MENUITEM "E&xit",                IDM_EXIT
+        MENUITEM "&Print...",            IDM_PRINT
     END
     POPUP "&Debug"
     BEGIN
Index: chrome/browser/printing/win_printing_context.cc
===================================================================
--- chrome/browser/printing/win_printing_context.cc	(revision 2056)
+++ chrome/browser/printing/win_printing_context.cc	(working copy)
@@ -249,7 +249,8 @@
 }
 
 PrintingContext::Result PrintingContext::NewDocument(
-    const std::wstring& document_name) {
+    const std::wstring& document_name,
+	bool debug_mode) {
   DCHECK(!in_print_job_);
   if (!hdc_)
     return OnErrror();
@@ -267,28 +268,30 @@
   di.lpszDocName = document_name.c_str();
 
   // Is there a debug dump directory specified? If so, force to print to a file.
-  std::wstring debug_dump_path;
-  if (!g_browser_process || !g_browser_process->print_job_manager()) {
-    // Happens only inside a unit test.
-    debug_dump_path = L".";
-  } else {
-    debug_dump_path = g_browser_process->print_job_manager()->debug_dump_path();
-  }
+  if(debug_mode) {
+	  std::wstring debug_dump_path;
+	  if (!g_browser_process || !g_browser_process->print_job_manager()) {
+		// Happens only inside a unit test.
+		debug_dump_path = L".";
+	  } else {
+		debug_dump_path = g_browser_process->print_job_manager()->debug_dump_path();
+	  }
 
-  if (!debug_dump_path.empty()) {
-    // Create a filename.
-    std::wstring filename;
-    Time now(Time::Now());
-    filename = base::TimeFormatShortDateNumeric(now);
-    filename += L"_";
-    filename += base::TimeFormatTimeOfDay(now);
-    filename += L"_";
-    filename += document_name;
-    filename += L"_";
-    filename += L"buffer.prn";
-    file_util::ReplaceIllegalCharacters(&filename, '_');
-    file_util::AppendToPath(&debug_dump_path, filename);
-    di.lpszOutput = debug_dump_path.c_str();
+	  if (!debug_dump_path.empty()) {
+		// Create a filename.
+		std::wstring filename;
+		Time now(Time::Now());
+		filename = base::TimeFormatShortDateNumeric(now);
+		filename += L"_";
+		filename += base::TimeFormatTimeOfDay(now);
+		filename += L"_";
+		filename += document_name;
+		filename += L"_";
+		filename += L"buffer.prn";
+		file_util::ReplaceIllegalCharacters(&filename, '_');
+		file_util::AppendToPath(&debug_dump_path, filename);
+		di.lpszOutput = debug_dump_path.c_str();
+	  }
   }
 
   DCHECK_EQ(MessageLoop::current()->NestableTasksAllowed(), false);
Index: chrome/browser/printing/win_printing_context.h
===================================================================
--- chrome/browser/printing/win_printing_context.h	(revision 2056)
+++ chrome/browser/printing/win_printing_context.h	(working copy)
@@ -49,7 +49,7 @@
   // like IPC message processing! Some printers have side-effects on this call
   // like virtual printers that ask the user for the path of the saved document;
   // for example a PDF printer.
-  Result NewDocument(const std::wstring& document_name);
+  Result NewDocument(const std::wstring& document_name, bool debug_mode = true);
 
   // Starts a new page.
   Result NewPage();
