LibreWeb-Browser/src/qt-renderer.cc

260 lines
6.1 KiB
C++

#include "qt-renderer.h"
#include "scene.h"
#include "cmark-gfm.h"
#include <node.h>
#include <QFont>
#include <QGraphicsTextItem>
#include <QGraphicsRectItem>
#include <QGraphicsSimpleTextItem>
#include <QPainter>
QtRenderer::QtRenderer():
scene(NULL),
defaultFontSize(12),
sceneMarginX(3.0),
sceneMarginY(3.0),
bold(false),
italic(false),
headingLevel(0),
listLevel(0),
currentX(0.0),
currentY(0.0),
fontFamilty("Open Sans"),
wordSpacing(4.0), // spacing may depend on the font
heighestHigh(0.0),
paragraphHeightOffset(5.0),
headingHeightOffset(10.0),
listXOffset(15.0),
bulletWithTemp(0.0) {
font = new QFont();
font->setPixelSize(defaultFontSize);
font->setFamily(fontFamilty);
}
void QtRenderer::setScene(Scene* scene)
{
this->scene = scene;
}
/**
* Render the whole document to scene/screen
*/
void QtRenderer::renderDocument(cmark_node *root, int width)
{
cmark_event_type ev_type;
cmark_iter *iter = cmark_iter_new(root);
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cmark_node *cur = cmark_iter_get_node(iter);
renderNode(cur, ev_type);
}
}
/**
* Calculates the locations, render and paint the content/objects
* to a QGraphicsScene
*/
void QtRenderer::renderNode(cmark_node *node, cmark_event_type ev_type)
{
bool entering = (ev_type == CMARK_EVENT_ENTER);
switch (node->type) {
case CMARK_NODE_DOCUMENT:
if (entering) {
currentX = sceneMarginX;
currentY = sceneMarginY;
}
break;
case CMARK_NODE_BLOCK_QUOTE:
break;
case CMARK_NODE_LIST:
if (entering) {
listLevel++;
} else {
listLevel--;
if (listLevel < 0)
listLevel = 0;
}
if (listLevel == 0) {
// Reset X to be safe
currentX = sceneMarginX;
} else if (listLevel > 0) {
if (entering) {
currentX += listXOffset;
} else {
currentX -= listXOffset;
}
}
break;
case CMARK_NODE_ITEM:
// Line break for list items
currentY += heighestHigh;
// Reset heighest high (Y-axis)
heighestHigh = 0;
// Add bullet before text items
if (entering) {
const QRectF rec = drawBullet();
bulletWithTemp = rec.width() + 2.0; // + offset
currentX += bulletWithTemp;
} else {
currentX -= bulletWithTemp;
}
break;
case CMARK_NODE_HEADING:
if (entering) {
headingLevel = node->as.heading.level;
} else {
headingLevel = 0; // reset
}
// Move to left again
currentX = sceneMarginX;
// New heading
currentY += heighestHigh + headingHeightOffset;
// Reset heighest high (Y-axis)
heighestHigh = 0;
break;
case CMARK_NODE_CODE_BLOCK:
break;
case CMARK_NODE_HTML_BLOCK:
break;
case CMARK_NODE_CUSTOM_BLOCK:
break;
case CMARK_NODE_THEMATIC_BREAK:
break;
case CMARK_NODE_PARAGRAPH:
// Skip paragraph if listing is enabled
if (listLevel == 0) {
// Move to left again
currentX = sceneMarginX;
// New paragraph
currentY += heighestHigh + paragraphHeightOffset;
// Reset heighest high (Y-axis)
heighestHigh = 0;
}
break;
case CMARK_NODE_TEXT: {
const QRectF rec = drawText(cmark_node_get_literal(node));
// Skip paragraph if listing is enabled
if (listLevel == 0) {
currentX += rec.width();
}
if (rec.height() > heighestHigh)
heighestHigh = rec.height();
}
break;
case CMARK_NODE_LINEBREAK:
// Move to left again
currentX = sceneMarginX;
// Line break (no soft break)
currentY += heighestHigh;
// Reset heighest high (Y-axis)
heighestHigh = 0;
break;
case CMARK_NODE_SOFTBREAK:
// ignore
// Only insert a space between the words
currentX += wordSpacing;
break;
case CMARK_NODE_CODE:
break;
case CMARK_NODE_HTML_INLINE:
break;
case CMARK_NODE_CUSTOM_INLINE:
break;
case CMARK_NODE_STRONG:
bold = entering;
break;
case CMARK_NODE_EMPH:
italic = entering;
break;
case CMARK_NODE_LINK:
break;
case CMARK_NODE_IMAGE:
break;
case CMARK_NODE_FOOTNOTE_REFERENCE:
break;
case CMARK_NODE_FOOTNOTE_DEFINITION:
break;
default:
assert(false);
break;
}
}
QRectF const QtRenderer::drawText(const QString& text)
{
// We can still extend the QGraphicsSimpleTextItem class (or QAbstractGraphicsShapeItem) and override paint method.
// Or just use QPainter with a paint device (like QWidgets), to have maximal control.
QGraphicsSimpleTextItem *textItem = new QGraphicsSimpleTextItem(text);
//font->setBold(bold);
//font->setItalic(italic);
if (headingLevel > 0) {
//font->setBold(true);
switch(headingLevel) {
case 1:
font->setPixelSize(24);
break;
case 2:
font->setPixelSize(20);
break;
case 3:
font->setPixelSize(16);
break;
case 4:
font->setPixelSize(14);
break;
case 5:
font->setPixelSize(12);
break;
default:
break;
}
}
textItem->setFont(*font);
textItem->setPos(currentX, currentY);
scene->addItem(textItem);
if (headingLevel > 0) {
font->setPixelSize(defaultFontSize);
}
return textItem->boundingRect();
}
QRectF const QtRenderer::drawBullet()
{
QGraphicsSimpleTextItem *bullet = new QGraphicsSimpleTextItem("\u2022");
bullet->setFont(*font);
bullet->setPos(currentX, currentY);
scene->addItem(bullet);
return bullet->boundingRect();
}