void Printer::flowRender() { // add extra padding at the bottom to pages with height not divisible by view port int paddingBottom = pageSize.height() - (webView->page()->mainFrame()->contentsSize().height() % pageSize.height()); QString styleString = QString::fromUtf8("padding-bottom: ") + QString::number(paddingBottom) + "px;"; webView->page()->mainFrame()->findFirstElement("body").setAttribute("style", styleString); // render the Qwebview QPainter painter; QRect viewPort(0, 0, 0, 0); painter.begin(paintDevice); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); // get all references to dontbreak divs int start = 0, end = 0; int fullPageResolution = webView->page()->mainFrame()->contentsSize().height(); QWebElementCollection dontbreak = webView->page()->mainFrame()->findAllElements(".dontbreak"); foreach (QWebElement dontbreakElement, dontbreak) { if ((dontbreakElement.geometry().y() + dontbreakElement.geometry().height()) - start < pageSize.height()) { // One more element can be placed end = dontbreakElement.geometry().y() + dontbreakElement.geometry().height(); } else { // fill the page with background color QRect fullPage(0, 0, pageSize.width(), pageSize.height()); QBrush fillBrush(templateOptions->color_palette.color1); painter.fillRect(fullPage, fillBrush); QRegion reigon(0, 0, pageSize.width(), end - start); viewPort.setRect(0, start, pageSize.width(), end - start); // render the base Html template webView->page()->mainFrame()->render(&painter, QWebFrame::ContentsLayer, reigon); // scroll the webview to the next page webView->page()->mainFrame()->scroll(0, dontbreakElement.geometry().y() - start); // rendering progress is 4/5 of total work emit(progessUpdated((end * 80.0 / fullPageResolution) + done)); // add new pages only in print mode, while previewing we don't add new pages if (printMode == Printer::PRINT) static_cast<QPrinter*>(paintDevice)->newPage(); else { painter.end(); return; } start = dontbreakElement.geometry().y(); } } // render the remianing page QRect fullPage(0, 0, pageSize.width(), pageSize.height()); QBrush fillBrush(templateOptions->color_palette.color1); painter.fillRect(fullPage, fillBrush); QRegion reigon(0, 0, pageSize.width(), end - start); webView->page()->mainFrame()->render(&painter, QWebFrame::ContentsLayer, reigon); painter.end(); }
int QPrinter::metric( int m ) const { int val; PageSize s = pageSize(); #if defined(CHECK_RANGE) ASSERT( (uint)s < (uint)NPageSize ); #endif static int widths[] = { 595, 516, 612, 612, 541, 2384, 1684, 1191, 842, 420, 297, 210, 148, 105, 2920, 2064, 91, 1460, 1032, 729, 516, 363, 258, 181, 127, 461, 297, 312, 595, 1224, 792 }; static int heights[] = { 842, 729, 792, 1009, 720, 3370, 2384, 1684, 1191, 595, 420, 297, 210, 148, 4127, 2920, 127, 2064, 1460, 1032, 729, 516, 363, 258, 181, 648, 684, 624, 935, 792, 1224 }; switch ( m ) { case QPaintDeviceMetrics::PdmWidth: val = orient == Portrait ? widths[ s ] : heights[ s ]; if ( !fullPage() ) val -= 2*margins().width(); break; case QPaintDeviceMetrics::PdmHeight: val = orient == Portrait ? heights[ s ] : widths[ s ]; if ( !fullPage() ) val -= 2*margins().height(); break; case QPaintDeviceMetrics::PdmDpiX: val = 72; break; case QPaintDeviceMetrics::PdmDpiY: val = 72; break; case QPaintDeviceMetrics::PdmWidthMM: val = metric( QPaintDeviceMetrics::PdmWidth ); val = (val * 254 + 360) / 720; // +360 to get the right rounding break; case QPaintDeviceMetrics::PdmHeightMM: val = metric( QPaintDeviceMetrics::PdmHeight ); val = (val * 254 + 360) / 720; break; case QPaintDeviceMetrics::PdmNumColors: val = 16777216; break; case QPaintDeviceMetrics::PdmDepth: val = 24; break; default: val = 0; #if defined(CHECK_RANGE) qWarning( "QPixmap::metric: Invalid metric command" ); #endif } return val; }
bool QPrinter::newPage() { if (state != PST_ACTIVE) return FALSE; if (PMSessionEndPage(psession) != noErr) { //end the last page state = PST_ERROR; return FALSE; } if (PMSessionBeginPage(psession, pformat, 0) != noErr) { //start a new one state = PST_ERROR; return FALSE; } if (PMSessionGetGraphicsContext(psession, kPMGraphicsContextQuickdraw, &hd) != noErr) { state = PST_ERROR; return FALSE; } if (fullPage()) { uint top, left, bottom, right; qt_get_margins(pformat, &top, &left, &bottom, &right); QMacSavedPortInfo mp(this); SetOrigin(top, left); } else { QMacSavedPortInfo mp(this); SetOrigin(0, 0); } return TRUE; }
bool QPrinter::cmd(int c, QPainter *, QPDevCmdParam *) { if (!psession && PMCreateSession(&psession) != noErr) return FALSE; if (c == PdcBegin) { // begin; start printing if (state != PST_IDLE) { qDebug("Qt: internal: printer: two PdcBegin(s)."); return FALSE; } //just to be sure they've been setup prepare(&pformat); prepare(&psettings); //validate the settings if (PMSessionValidatePrintSettings(psession, psettings, kPMDontWantBoolean) != noErr) return FALSE; if (PMSessionValidatePageFormat(psession, pformat, kPMDontWantBoolean) != noErr) return FALSE; if (PMSessionBeginDocument(psession, psettings, pformat) != noErr) //begin the document return FALSE; if (PMSessionBeginPage(psession, pformat, 0) != noErr) //begin the page return FALSE; if (PMSessionGetGraphicsContext(psession, kPMGraphicsContextQuickdraw, &hd) != noErr) //get the gworld return FALSE; state = PST_ACTIVE; if (fullPage()) { uint top, left, bottom, right; qt_get_margins(pformat, &top, &left, &bottom, &right); QMacSavedPortInfo mp(this); SetOrigin(top, left); } else { QMacSavedPortInfo mp(this); SetOrigin(0, 0); } } else if (c == PdcEnd) { if (hd && state != PST_IDLE) { PMSessionEndPage(psession); PMSessionEndDocument(psession); hd = NULL; } state = PST_IDLE; } else { // all other commands... if (state == PST_ABORTED || ((state == PST_ACTIVE || state == PST_ERROR) && PMSessionError(psession) != noErr)) return FALSE; } return TRUE; }
int KPrinter::metric(int m) const { if (d->m_pagesize == NULL || !option( "kde-printsize" ).isEmpty()) return d->m_wrapper->qprinterMetric(m); int val(0); bool land = (orientation() == KPrinter::Landscape); uint res(d->m_wrapper->resolution()), top = res/2, left = res/2, bottom = res/3, right = res/2; margins( &top, &left, &bottom, &right ); switch ( m ) { case QPaintDeviceMetrics::PdmWidth: val = (land ? ( int )d->m_pagesize->pageHeight() : ( int )d->m_pagesize->pageWidth()); if ( res != 72 ) val = (val * res + 36) / 72; if ( !fullPage() ) val -= ( left + right ); break; case QPaintDeviceMetrics::PdmHeight: val = (land ? ( int )d->m_pagesize->pageWidth() : ( int )d->m_pagesize->pageHeight()); if ( res != 72 ) val = (val * res + 36) / 72; if ( !fullPage() ) val -= ( top + bottom ); break; case QPaintDeviceMetrics::PdmWidthMM: val = metric( QPaintDeviceMetrics::PdmWidth ); val = (val * 254 + 5*res) / (10*res); // +360 to get the right rounding break; case QPaintDeviceMetrics::PdmHeightMM: val = metric( QPaintDeviceMetrics::PdmHeight ); val = (val * 254 + 5*res) / (10*res); break; default: val = d->m_wrapper->qprinterMetric(m); break; } return val; }
int QPrinter::metric(int m) const { int val = 1; switch (m) { case QPaintDeviceMetrics::PdmWidth: { bool orientInSync = true; PMOrientation o; QPrinter::Orientation tmpOrient = orientation(); if (PMGetOrientation(pformat, &o) == noErr) { orientInSync = ((o == kPMPortrait && tmpOrient == Portrait) || o == kPMLandscape && tmpOrient == Landscape); } PageSize s = pageSize(); if (s >= QPrinter::Custom) { val = tmpOrient == Portrait ? customPaperSize_.width() : customPaperSize_.height(); } else { if (state == PST_ACTIVE || (tmpOrient == Portrait || orientInSync)) { val = qt_get_PDMWidth(pformat, fullPage()); } else { val = qt_get_PDMHeight(pformat, fullPage()); } } break; } case QPaintDeviceMetrics::PdmHeight: { bool orientInSync = true; PMOrientation o; QPrinter::Orientation tmpOrient = orientation(); if (PMGetOrientation(pformat, &o) == noErr) { orientInSync = ((o == kPMPortrait && tmpOrient == Portrait) || o == kPMLandscape && tmpOrient == Landscape); } PageSize s = pageSize(); if (s >= QPrinter::Custom) { val = tmpOrient == Portrait ? customPaperSize_.height() : customPaperSize_.width(); } else { if (state == PST_ACTIVE || (tmpOrient == Portrait || orientInSync)) { val = qt_get_PDMHeight(pformat, fullPage()); } else { val = qt_get_PDMWidth(pformat, fullPage()); } } break; } // We don't have to worry about the printer state here as metric() does that for us. case QPaintDeviceMetrics::PdmWidthMM: val = metric(QPaintDeviceMetrics::PdmWidth); val = (val * 254 + 5 * res) / (10 * res); break; case QPaintDeviceMetrics::PdmHeightMM: val = metric(QPaintDeviceMetrics::PdmHeight); val = (val * 254 + 5 * res) / (10 * res); break; case QPaintDeviceMetrics::PdmPhysicalDpiX: case QPaintDeviceMetrics::PdmPhysicalDpiY: { PMPrinter printer; if (PMSessionGetCurrentPrinter(psession, &printer) == noErr) { PMResolution resolution; PMPrinterGetPrinterResolution(printer, kPMCurrentValue, &resolution); val = (int)resolution.vRes; break; } //otherwise fall through } case QPaintDeviceMetrics::PdmDpiY: case QPaintDeviceMetrics::PdmDpiX: val = res; break; case QPaintDeviceMetrics::PdmNumColors: val = (1 << metric(QPaintDeviceMetrics::PdmDepth)); break; case QPaintDeviceMetrics::PdmDepth: val = 24; break; default: val = 0; #if defined(QT_CHECK_RANGE) qWarning("Qt: QPixmap::metric: Invalid metric command"); #endif } return val; }
// TODO: speed stats // TODO: faster: max_advance_width int RenderFb::render(Pagination* pagination, unsigned int pageNum, bool doBlit) { clc::Log::info("ocher.renderer.fb", "render page %u %u", pageNum, doBlit); m_penX = settings.marginLeft; m_penY = settings.marginTop + g_ft->getAscender(); if (doBlit) m_fb->clear(); unsigned int layoutOffset; unsigned int strOffset; if (!pageNum) { layoutOffset = 0; strOffset = 0; } else if (! pagination->get(pageNum-1, &layoutOffset, &strOffset)) { // Previous page not already paginated? // Perhaps at end of book? clc::Log::error("ocher.renderer.fb", "page %u not found", pageNum); return -1; } const unsigned int N = m_layout.size(); const char *raw = m_layout.data(); Rect fullPage(0, 0, m_fb->width(), m_fb->height()); ASSERT(layoutOffset < N); for (unsigned int i = layoutOffset; i < N; ) { ASSERT(i+2 <= N); uint16_t code = *(uint16_t*)(raw+i); i += 2; unsigned int opType = (code>>12)&0xf; unsigned int op = (code>>8)&0xf; unsigned int arg = code & 0xff; switch (opType) { case Layout::OpPushTextAttr: clc::Log::trace("ocher.render.fb", "OpPushTextAttr"); switch (op) { case Layout::AttrBold: pushAttrs(); a[ai].b = 1; break; case Layout::AttrUnderline: pushAttrs(); a[ai].ul = 1; break; case Layout::AttrItalics: pushAttrs(); a[ai].em = 1; break; case Layout::AttrSizeRel: pushAttrs(); clc::Log::debug("ocher.render.fb", "font rel %d", (int)arg); a[ai].pts += (int)arg; m_ft->setSize(a[ai].pts); break; case Layout::AttrSizeAbs: pushAttrs(); clc::Log::debug("ocher.render.fb", "font abs %d", (int)arg); a[ai].pts = (int)arg; m_ft->setSize(a[ai].pts); break; default: clc::Log::error("ocher.render.fb", "unknown OpPushTextAttr"); ASSERT(0); break; } break; case Layout::OpPushLineAttr: clc::Log::debug("ocher.render.fb", "OpPushLineAttr"); switch (op) { case Layout::LineJustifyLeft: break; case Layout::LineJustifyCenter: break; case Layout::LineJustifyFull: break; case Layout::LineJustifyRight: break; default: clc::Log::error("ocher.render.fb", "unknown OpPushLineAttr"); ASSERT(0); break; } break; case Layout::OpCmd: switch (op) { case Layout::CmdPopAttr: clc::Log::trace("ocher.render.fb", "OpCmd CmdPopAttr"); if (arg == 0) arg = 1; while (arg--) popAttrs(); // TODO: only reset what has changed clc::Log::debug("ocher.render.fb", "font pop %d", a[ai].pts); m_ft->setSize(a[ai].pts); break; case Layout::CmdOutputStr: { clc::Log::trace("ocher.render.fb", "OpCmd CmdOutputStr"); ASSERT(i + sizeof(clc::Buffer*) <= N); clc::Buffer *str = *(clc::Buffer**)(raw+i); ASSERT(strOffset <= str->size()); int breakOffset = outputWrapped(str, strOffset, doBlit); strOffset = 0; if (breakOffset >= 0) { pagination->set(pageNum, i-2, breakOffset); clc::Log::debug("ocher.renderer.fb", "page %u break", pageNum); if (doBlit) m_fb->update(&fullPage, false); return 0; } i += sizeof(clc::Buffer*); break; } case Layout::CmdForcePage: clc::Log::trace("ocher.render.fb", "OpCmd CmdForcePage"); break; default: clc::Log::error("ocher.render.fb", "unknown OpCmd"); ASSERT(0); break; } break; case Layout::OpSpacing: break; case Layout::OpImage: break; default: clc::Log::error("ocher.render.fb", "unknown op type"); ASSERT(0); break; }; } clc::Log::debug("ocher.renderer.fb", "page %u done", pageNum); if (doBlit) m_fb->update(&fullPage, false); return 1; }
void KPrinter::translateQtOptions() { d->m_wrapper->setCreator(creator()); d->m_wrapper->setDocName(docName()); d->m_wrapper->setFullPage(fullPage()); d->m_wrapper->setColorMode((QPrinter::ColorMode)colorMode()); d->m_wrapper->setOrientation((QPrinter::Orientation)orientation()); if ( !option( "kde-printsize" ).isEmpty() ) d->m_wrapper->setPageSize( ( QPrinter::PageSize )option( "kde-printsize" ).toInt() ); else d->m_wrapper->setPageSize((QPrinter::PageSize)pageSize()); d->m_wrapper->setOutputToFile(true); d->m_wrapper->setOutputFileName(d->m_tmpbuffer); d->m_wrapper->setNumCopies(option("kde-qtcopies").isEmpty() ? 1 : option("kde-qtcopies").toInt()); if (!option("kde-margin-top").isEmpty()) { /** * Scale margings as the margin widget always stores values * in dot units ( 1/72th in ), to be resolution independent * when specified by the user ( who usually specifies margins * in metric units ). */ int res = resolution(); d->m_wrapper->setMargins( ( int )( ( option("kde-margin-top").toFloat() * res + 71 ) / 72 ), ( int )( ( option("kde-margin-left").toFloat() * res + 71 ) / 72 ), ( int )( ( option("kde-margin-bottom").toFloat() * res + 71 ) / 72 ), ( int )( ( option("kde-margin-right").toFloat() * res + 71 ) / 72 ) ); } else if ( d->m_pagesize != NULL ) { int res = resolution(); DrPageSize *ps = d->m_pagesize; int top = ( int )( ps->topMargin() * res + 71 ) / 72; int left = ( int )( ps->leftMargin() * res + 71 ) / 72; int bottom = ( int )( ps->bottomMargin() * res + 71 ) / 72; int right = ( int )( ps->rightMargin() * res + 71 ) / 72; if ( !fullPage() ) { // Printers can often print very close to the edges (PPD files say ImageArea==PaperDimension). // But that doesn't mean it looks good. Apps which use setFullPage(false) assume that // KPrinter will give them reasonable margins, so let's QMAX with defaults from Qt in that case. // Keep this in sync with KPMarginPage::initPageSize unsigned int it, il, ib, ir; d->m_wrapper->margins( &it, &il, &ib, &ir ); top = QMAX( top, (int)it ); left = QMAX( left, (int)il ); bottom = QMAX( bottom, (int)ib ); right = QMAX( right, (int)ir ); } d->m_wrapper->setMargins( top, left, bottom, right ); } /*else { int res = d->m_wrapper->resolution(); d->m_wrapper->setMargins( res/3, res/2, res/3, res/2 ); }*/ // for special printers, copies are handled by Qt if (option("kde-isspecial") == "1") d->m_wrapper->setNumCopies(numCopies()); }