18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/* 28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2007 Alp Toker <alp@atoker.com> 38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2007 Apple Inc. 48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This library is free software; you can redistribute it and/or 68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modify it under the terms of the GNU Library General Public 78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * License as published by the Free Software Foundation; either 88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * version 2 of the License, or (at your option) any later version. 98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This library is distributed in the hope that it will be useful, 118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * but WITHOUT ANY WARRANTY; without even the implied warranty of 128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Library General Public License for more details. 148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * You should have received a copy of the GNU Library General Public License 168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * along with this library; see the file COPYING.LIB. If not, write to 178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Boston, MA 02110-1301, USA. 198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */ 208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h" 228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "PrintContext.h" 238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContext.h" 258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Frame.h" 268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FrameView.h" 278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderView.h" 288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace WebCore; 308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore { 328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectPrintContext::PrintContext(Frame* frame) 348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project : m_frame(frame) 358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectPrintContext::~PrintContext() 398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project m_pageRects.clear(); 418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectint PrintContext::pageCount() const 448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return m_pageRects.size(); 468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 485e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockconst IntRect& PrintContext::pageRect(int pageNumber) const 495e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block{ 505e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block return m_pageRects[pageNumber]; 515e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block} 525e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid PrintContext::computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight) 548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project m_pageRects.clear(); 568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project outPageHeight = 0; 578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!m_frame->document() || !m_frame->view() || !m_frame->document()->renderer()) 598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return; 608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch RenderView* root = toRenderView(m_frame->document()->renderer()); 628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!root) { 648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project LOG_ERROR("document to be printed has no renderer"); 658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return; 668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project float ratio = printRect.height() / printRect.width(); 698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 70231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block float pageWidth = (float)root->rightLayoutOverflow(); 718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project float pageHeight = pageWidth * ratio; 728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project outPageHeight = pageHeight; // this is the height of the page adjusted by margins 738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project pageHeight -= headerHeight + footerHeight; 748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (pageHeight <= 0) { 768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project LOG_ERROR("pageHeight has bad value %.2f", pageHeight); 778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return; 788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 805e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block computePageRectsWithPageSize(FloatSize(pageWidth, pageHeight), userScaleFactor); 815e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block} 825e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 835e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockvoid PrintContext::computePageRectsWithPageSize(const FloatSize& pageSizeInPixels, float userScaleFactor) 845e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block{ 855e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block RenderView* root = toRenderView(m_frame->document()->renderer()); 865e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 875e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block if (!root) { 885e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block LOG_ERROR("document to be printed has no renderer"); 895e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block return; 905e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block } 915e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 925e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block if (userScaleFactor <= 0) { 935e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor); 945e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block return; 955e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block } 965e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 975e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block float currPageHeight = pageSizeInPixels.height() / userScaleFactor; 988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project float docHeight = root->layer()->height(); 995e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block float currPageWidth = pageSizeInPixels.width() / userScaleFactor; 1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // always return at least one page, since empty files should print a blank page 1025e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block float printedPagesHeight = 0; 1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project do { 1045e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block float proposedBottom = std::min(docHeight, printedPagesHeight + pageSizeInPixels.height()); 1058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian m_frame->view()->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); 1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); 1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project m_pageRects.append(IntRect(0, (int)printedPagesHeight, (int)currPageWidth, (int)currPageHeight)); 1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project printedPagesHeight += currPageHeight; 1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } while (printedPagesHeight < docHeight); 1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid PrintContext::begin(float width) 1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 115643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // By imaging to a width a little wider than the available pixels, 116643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // thin pages will be scaled down a little, matching the way they 117643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // print in IE and Camino. This lets them use fewer sheets than they 118643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // would otherwise, which is presumably why other browsers do this. 119643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // Wide pages will be scaled down more than this. 120643ca7872b450ea4efacab6188849e5aac2ba161Steve Block const float PrintingMinimumShrinkFactor = 1.25f; 121643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 122643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // This number determines how small we are willing to reduce the page content 123643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // in order to accommodate the widest line. If the page would have to be 124643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // reduced smaller to make the widest line fit, we just clip instead (this 125643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // behavior matches MacIE and Mozilla, at least) 126643ca7872b450ea4efacab6188849e5aac2ba161Steve Block const float PrintingMaximumShrinkFactor = 2.0f; 1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project float minLayoutWidth = width * PrintingMinimumShrinkFactor; 1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project float maxLayoutWidth = width * PrintingMaximumShrinkFactor; 1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: This will modify the rendering of the on-screen frame. 1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Could lead to flicker during printing. 1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project m_frame->setPrinting(true, minLayoutWidth, maxLayoutWidth, true); 1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid PrintContext::spoolPage(GraphicsContext& ctx, int pageNumber, float width) 1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project IntRect pageRect = m_pageRects[pageNumber]; 1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project float scale = width / pageRect.width(); 1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ctx.save(); 1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ctx.scale(FloatSize(scale, scale)); 1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ctx.translate(-pageRect.x(), -pageRect.y()); 1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ctx.clip(pageRect); 1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project m_frame->view()->paintContents(&ctx, pageRect); 1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ctx.restore(); 1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid PrintContext::end() 1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project m_frame->setPrinting(false, 0, 0, true); 1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1545e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockstatic RenderBoxModelObject* enclosingBoxModelObject(RenderObject* object) 1555e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block{ 1565e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 1575e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block while (object && !object->isBoxModelObject()) 1585e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block object = object->parent(); 1595e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block if (!object) 1605e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block return 0; 1615e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block return toRenderBoxModelObject(object); 1625e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block} 1635e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 1645e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockint PrintContext::pageNumberForElement(Element* element, const FloatSize& pageSizeInPixels) 1655e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block{ 1665e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block // Make sure the element is not freed during the layout. 1675e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block RefPtr<Element> elementRef(element); 1685e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block element->document()->updateLayout(); 1695e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 1705e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block RenderBoxModelObject* box = enclosingBoxModelObject(element->renderer()); 1715e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block if (!box) 1725e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block return -1; 1735e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 1745e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block Frame* frame = element->document()->frame(); 1755e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block FloatRect pageRect(FloatPoint(0, 0), pageSizeInPixels); 1765e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block PrintContext printContext(frame); 1775e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block printContext.begin(pageRect.width()); 1785e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block printContext.computePageRectsWithPageSize(pageSizeInPixels, 1); 1795e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 1805e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block int top = box->offsetTop(); 1815e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block int left = box->offsetLeft(); 1825e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block for (int pageNumber = 0; pageNumber < printContext.pageCount(); pageNumber++) { 1835e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block const IntRect& page = printContext.pageRect(pageNumber); 1845e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block if (page.x() <= left && left < page.right() && page.y() <= top && top < page.bottom()) 1855e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block return pageNumber; 1865e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block } 1878a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block printContext.end(); 1885e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block return -1; 1895e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block} 1905e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block 1918a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockint PrintContext::numberOfPages(Frame* frame, const FloatSize& pageSizeInPixels) 1928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{ 1938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block frame->document()->updateLayout(); 1948a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 1958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block FloatRect pageRect(FloatPoint(0, 0), pageSizeInPixels); 1968a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block PrintContext printContext(frame); 1978a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block printContext.begin(pageRect.width()); 1988a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block printContext.computePageRectsWithPageSize(pageSizeInPixels, 1); 1998a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block printContext.end(); 2008a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block return printContext.pageCount(); 2018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block} 2028a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block 2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 204