Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 21106 → Rev 21107

/trunk/Scribus/AUTHORS
71,6 → 71,20
Giovanni Mugnai musical777@gmail.com
 
 
Refactoring text layout code and the new boxes model, Oman House of Open Source
Technology team:
 
Anood Almuharbi anood.almuharbi@gmail.com
Asma ALbahanta as.bahanta@gmail.com
Dawood Albadi daawood.albadi@gmail.com
Ibrahim Alrashdi ibrahimalrashdi745@gmail.com
Ibtisam Nasser ibtisammabsali@gmail.com
Khaled Hosny khaledhosny@eglug.org
Noseeba noseeba1@gmail.com
Shamsa Hamed shamsahamed59@gmail.com
Sheikha sheikha443@gmail.com
 
 
Official Documentation:
 
Peter Linnell plinnell@scribus.net
/trunk/Scribus/scribus/canvas.cpp
2061,6 → 2061,7
void Canvas::DrawPageIndicatorSub(ScPainter *p, ScPage *page)
{
p->save();
int fm = p->fillMode();
p->setAntialiasing(false);
p->translate(page->xOffset(), page->yOffset());
double lineWidth = 1.0 / m_viewMode.scale;
2072,6 → 2073,7
p->setPen(PrefsManager::instance()->appPrefs.displayPrefs.pageBorderColor, 1 / m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
p->drawRect(0, 0, pageWidth, pageHeight);
p->setAntialiasing(true);
p->setFillMode(fm);
p->restore();
}
 
/trunk/Scribus/scribus/canvasmode.cpp
1016,141 → 1016,21
 
void CanvasMode::commonDrawTextCursor(QPainter* p, PageItem_TextFrame* textframe, const QPointF& offset)
{
double dx, dy, dy1;
QLineF cursor;
QPen cPen ( Qt::black, 0.9 , Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin );
 
// normalize Current Position
textframe->itemText.normalizeCursorPosition();
int textCursorPos ( textframe->itemText.cursorPosition() );
cursor = textframe->textLayout.positionToPoint(textCursorPos);
 
if ( textframe->lastInFrame() >= textframe->itemText.length()
|| textframe->itemText.length() == 0 )
{
dx = textframe->textToFrameDistLeft();
dy = textframe->textToFrameDistTop();
dy1 = textframe->textToFrameDistTop() + (textframe->itemText.defaultStyle().charStyle().fontSize() / 10.0);
cPen.setColor(ScColorEngine::getRGBColor(m_doc->PageColors[textframe->itemText.charStyle(textCursorPos).fillColor()], m_doc));
 
cPen.setColor ( ScColorEngine::getRGBColor ( m_doc->PageColors[textframe->itemText.defaultStyle().charStyle().fillColor() ], m_doc ) );
}
else if ( textCursorPos > textframe->lastInFrame() )
{
// Happens often when typing directly into frame.
// And the cursor curses nothing, vertigo.
textCursorPos = qMax(0, textframe->lastInFrame());
QChar textCursorChar = textframe->itemText.text(textCursorPos);
if (textCursorChar == SpecialChars::PARSEP || textCursorChar == SpecialChars::LINEBREAK)
{
// The cursor must be moved to the beginning of the next line
FRect bbox = textframe->textLayout.boundingBox ( textCursorPos );
double lineSpacing(textframe->itemText.paragraphStyle(textCursorPos).lineSpacing());
 
// take care if cursor is not in first column
int curCol(1);
double ccPos(textframe->textLayout.boundingBox ( textCursorPos ).x());
double leftOffset(textframe->textToFrameDistLeft());
for(int ci(1); ci <= textframe->columns(); ++ci)
{
double cLeft(((ci-1) * textframe->columnWidth()) + ((ci -1) * textframe->columnGap()) + leftOffset);
double cRight((ci * textframe->columnWidth()) + ((ci -1) * textframe->columnGap()) + leftOffset);
if((cLeft <= ccPos) && (ccPos <= cRight))
{
curCol = ci;
break;
}
}
dx = (textframe->columnWidth() * (curCol - 1)) + (textframe->columnGap() * (curCol - 1)) + leftOffset;
dy = bbox.y();
 
if ( bbox.height() <= 2 )
dy1 = bbox.y() + textframe->itemText.charStyle ( textCursorPos ).fontSize() / 30.0;
else
dy1 = bbox.y() + bbox.height();
 
dy += lineSpacing;
dy1 += lineSpacing;
}
else if (textCursorChar == SpecialChars::COLBREAK)
{
// A bit tricky :)
// We want to position the cursor at the beginning of the next column, if any.
// At first we need to know in which column the cursor is.
int curCol(1);
double ccPos(textframe->textLayout.boundingBox ( textCursorPos ).x());
double leftOffset(textframe->textToFrameDistLeft());
for(int ci(1); ci <= textframe->columns(); ++ci)
{
double cLeft(((ci-1) * textframe->columnWidth()) + ((ci -1) * textframe->columnGap()) + leftOffset);
double cRight((ci * textframe->columnWidth()) + ((ci -1) * textframe->columnGap()) + leftOffset);
if((cLeft <= ccPos) && (ccPos <= cRight))
{
curCol = ci;
break;
}
}
if(textframe->columns() > curCol)
{
dx = (textframe->columnWidth() * curCol) + (textframe->columnGap() * curCol) + leftOffset;
dy = textframe->textToFrameDistTop();
dy1 = textframe->textToFrameDistTop() + textframe->textLayout.boundingBox ( textCursorPos ).height();
}
else // there is no column after the current column
{
FRect bbox = textframe->textLayout.boundingBox ( textCursorPos );
dx = bbox.x();
dy = bbox.y();
dx += textframe->itemText.getGlyphs(textCursorPos)->wide();
if ( bbox.height() <= 2 )
dy1 = bbox.y() + textframe->itemText.charStyle ( textCursorPos ).fontSize() / 30.0;
else
dy1 = bbox.y() + bbox.height();
}
}
else
{
FRect bbox = textframe->textLayout.boundingBox ( textCursorPos );
dx = bbox.x();
dy = bbox.y();
dx += textframe->itemText.getGlyphs(textCursorPos)->wide();
if ( bbox.height() <= 2 )
dy1 = bbox.y() + textframe->itemText.charStyle ( textCursorPos ).fontSize() / 30.0;
else
dy1 = bbox.y() + bbox.height();
 
}
cPen.setColor ( ScColorEngine::getRGBColor ( m_doc->PageColors[textframe->itemText.charStyle ( textCursorPos ).fillColor() ], m_doc ) );
}
else
{
FRect bbox = textframe->textLayout.boundingBox ( textCursorPos );
dx = bbox.x();
dy = bbox.y();
if ( bbox.height() <= 2 )
dy1 = bbox.y() + textframe->itemText.charStyle ( textCursorPos ).fontSize() / 30.0;
else
dy1 = bbox.y() + bbox.height();
 
cPen.setColor ( ScColorEngine::getRGBColor ( m_doc->PageColors[textframe->itemText.charStyle ( textCursorPos ).fillColor() ], m_doc ) );
}
//handle Right to Left writing
if (textframe->imageFlippedH())
dx = textframe->width() - dx;
if (textframe->imageFlippedV())
{
dy = textframe->height() - dy;
dy1 = textframe->height() - dy1;
}
p->save();
p->setTransform(textframe->getTransform(), true);
p->setPen ( cPen );
p->setRenderHint ( QPainter::Antialiasing, true );
// avoid displaying the cursor on the frameborder
dx = qMax ( ( cPen.widthF() / 2.0 ), dx );
 
dy = qMin ( qMax ( dy,0.0 ) , textframe->height() );
dy1 = qMin ( qMax ( dy1,0.0 ), textframe->height() );
 
p->drawLine ( QLineF ( dx,dy,dx,dy1 ).translated(offset) );
 
p->drawLine(cursor.translated(offset));
p->restore();
}
 
/trunk/Scribus/scribus/pageitem.cpp
2549,7 → 2549,7
 
/**
layout glyphs translates the chars into a number of glyphs, applying the Charstyle
'style'. The following fields are set in layout: glyph, more, scaleH, scaleV, xoffset, yoffset, xadvance.
'style'. The following fields are set in layout: glyph, scaleH, scaleV, xoffset, yoffset, xadvance.
If the DropCap-bit in style.effects is set and yadvance is > 0, scaleH/V, x/yoffset and xadvance
are modified to scale the glyphs to this height.
Otherwise yadvance is set to the max ascender of all generated glyphs.
2557,9 → 2557,9
sets xadvance to the advance width without kerning. If more than one glyph
is generated, kerning is included in all but the last xadvance.
*/
double PageItem::layoutGlyphs(const CharStyle& style, const QString& chars, LayoutFlags flags, GlyphLayout& layout)
GlyphLayout PageItem::layoutGlyphs(const CharStyle& style, const QString& chars, LayoutFlags flags)
{
double retval = 0.0;
GlyphLayout gl;
const ScFace font = style.font();
double asce = font.ascent(style.fontSize() / 10.0);
int chst = style.effects() & ScStyle_UserStyles;
2578,36 → 2578,34
}
else */
{
layout.glyph = font.char2CMap(chars[0].unicode());
gl.glyph = font.char2CMap(chars[0].unicode());
}
double tracking = 0.0;
if ( (flags & ScLayout_StartOfLine) == 0)
tracking = style.fontSize() * style.tracking() / 10000.0;
 
layout.xoffset = tracking;
layout.yoffset = 0;
gl.xoffset = tracking;
gl.yoffset = 0;
if (chst != ScStyle_Default)
{
if (chst & ScStyle_Superscript)
{
retval -= asce * m_Doc->typographicPrefs().valueSuperScript / 100.0;
layout.yoffset -= asce * m_Doc->typographicPrefs().valueSuperScript / 100.0;
layout.scaleV = layout.scaleH = qMax(m_Doc->typographicPrefs().scalingSuperScript / 100.0, 10.0 / style.fontSize());
gl.yoffset -= asce * m_Doc->typographicPrefs().valueSuperScript / 100.0;
gl.scaleV = gl.scaleH = qMax(m_Doc->typographicPrefs().scalingSuperScript / 100.0, 10.0 / style.fontSize());
}
else if (chst & ScStyle_Subscript)
{
retval += asce * m_Doc->typographicPrefs().valueSubScript / 100.0;
layout.yoffset += asce * m_Doc->typographicPrefs().valueSubScript / 100.0;
layout.scaleV = layout.scaleH = qMax(m_Doc->typographicPrefs().scalingSubScript / 100.0, 10.0 / style.fontSize());
gl.yoffset += asce * m_Doc->typographicPrefs().valueSubScript / 100.0;
gl.scaleV = gl.scaleH = qMax(m_Doc->typographicPrefs().scalingSubScript / 100.0, 10.0 / style.fontSize());
}
else {
layout.scaleV = layout.scaleH = 1.0;
gl.scaleV = gl.scaleH = 1.0;
}
layout.scaleH *= style.scaleH() / 1000.0;
layout.scaleV *= style.scaleV() / 1000.0;
gl.scaleH *= style.scaleH() / 1000.0;
gl.scaleV *= style.scaleV() / 1000.0;
if (chst & ScStyle_AllCaps)
{
layout.glyph = font.char2CMap(chars[0].toUpper().unicode());
gl.glyph = font.char2CMap(chars[0].toUpper().unicode());
}
if (chst & ScStyle_SmallCaps)
{
2615,15 → 2613,15
QChar uc = chars[0].toUpper();
if (uc != chars[0])
{
layout.glyph = font.char2CMap(chars[0].toUpper().unicode());
layout.scaleV *= smallcapsScale;
layout.scaleH *= smallcapsScale;
gl.glyph = font.char2CMap(chars[0].toUpper().unicode());
gl.scaleV *= smallcapsScale;
gl.scaleH *= smallcapsScale;
}
}
}
else {
layout.scaleH = style.scaleH() / 1000.0;
layout.scaleV = style.scaleV() / 1000.0;
gl.scaleH = style.scaleH() / 1000.0;
gl.scaleV = style.scaleV() / 1000.0;
}
/* if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) {
2642,313 → 2640,15
}
else */
{
layout.xadvance = font.glyphWidth(layout.glyph, style.fontSize() / 10) * layout.scaleH;
layout.yadvance = font.glyphBBox(layout.glyph, style.fontSize() / 10).ascent * layout.scaleV;
gl.xadvance = font.glyphWidth(gl.glyph, style.fontSize() / 10);
gl.yadvance = font.glyphBBox(gl.glyph, style.fontSize() / 10).ascent;
}
if (layout.xadvance > 0)
layout.xadvance += tracking;
if (gl.xadvance > 0)
gl.xadvance += tracking;
 
if (chars.length() > 1) {
layout.grow();
layoutGlyphs(style, chars.mid(1), ScLayout_None, *layout.more);
layout.xadvance += font.glyphKerning(layout.glyph, layout.more->glyph, style.fontSize() / 10) * layout.scaleH;
if (layout.more->yadvance > layout.yadvance)
layout.yadvance = layout.more->yadvance;
}
else {
layout.shrink();
}
return retval;
return gl;
}
 
void PageItem::drawGlyphs(ScPainter *p, const CharStyle& style, LayoutFlags flags, GlyphLayout& glyphs)
{
uint glyph = glyphs.glyph;
const ScFace font = style.font();
if ((m_Doc->guidesPrefs().showControls) &&
(glyph == font.char2CMap(QChar(' ')) || glyph >= ScFace::CONTROL_GLYPHS))
{
bool stroke = false;
if (glyph >= ScFace::CONTROL_GLYPHS)
glyph -= ScFace::CONTROL_GLYPHS;
else
glyph = 32;
QTransform chma, chma4, chma5;
FPointArray points;
if (glyph == SpecialChars::TAB.unicode())
{
points = m_Doc->symTab.copy();
chma4.translate(glyphs.xoffset + glyphs.xadvance - ((style.fontSize() / 10.0) * glyphs.scaleH * 0.7), glyphs.yoffset - ((style.fontSize() / 10.0) * glyphs.scaleV * 0.5));
}
else if (glyph == SpecialChars::COLBREAK.unicode())
{
points = m_Doc->symNewCol.copy();
chma4.translate(glyphs.xoffset, glyphs.yoffset-((style.fontSize() / 10.0) * glyphs.scaleV * 0.6));
}
else if (glyph == SpecialChars::FRAMEBREAK.unicode())
{
points = m_Doc->symNewFrame.copy();
chma4.translate(glyphs.xoffset, glyphs.yoffset-((style.fontSize() / 10.0) * glyphs.scaleV * 0.6));
}
else if (glyph == SpecialChars::PARSEP.unicode())
{
points = m_Doc->symReturn.copy();
chma4.translate(glyphs.xoffset, glyphs.yoffset-((style.fontSize() / 10.0) * glyphs.scaleV * 0.8));
}
else if (glyph == SpecialChars::LINEBREAK.unicode())
{
points = m_Doc->symNewLine.copy();
chma4.translate(glyphs.xoffset, glyphs.yoffset-((style.fontSize() / 10.0) * glyphs.scaleV * 0.4));
}
else if (glyph == SpecialChars::NBSPACE.unicode() ||
glyph == 32)
{
stroke = (glyph == 32);
points = m_Doc->symNonBreak.copy();
chma4.translate(glyphs.xoffset, glyphs.yoffset-((style.fontSize() / 10.0) * glyphs.scaleV * 0.4));
}
else if (glyph == SpecialChars::NBHYPHEN.unicode())
{
points = font.glyphOutline(font.char2CMap(QChar('-')), style.fontSize() / 100);
chma4.translate(glyphs.xoffset, glyphs.yoffset-((style.fontSize() / 10.0) * glyphs.scaleV));
}
else if (glyph == SpecialChars::SHYPHEN.unicode())
{
points.resize(0);
points.addQuadPoint(0, -10, 0, -10, 0, -6, 0, -6);
stroke = true;
}
else if (glyph == SpecialChars::OBJECT.unicode())
{
//for showing marks entries as control chars
points.resize(0);
points.addQuadPoint(0, -8, 1, -8, 0, -6, 1, -6);
stroke = true;
}
else // ???
{
points.resize(0);
points.addQuadPoint(0, -10, 0, -10, 0, -9, 0, -9);
points.addQuadPoint(0, -9, 0, -9, 1, -9, 1, -9);
points.addQuadPoint(1, -9, 1, -9, 1, -10, 1, -10);
points.addQuadPoint(1, -10, 1, -10, 0, -10, 0, -10);
}
chma.scale(glyphs.scaleH * style.fontSize() / 100.0, glyphs.scaleV * style.fontSize() / 100.0);
points.map(chma * chma4);
p->setupPolygon(&points, true);
QColor oldBrush = p->brush();
p->setBrush( (flags & ScLayout_SuppressSpace) ? Qt::green
: PrefsManager::instance()->appPrefs.displayPrefs.controlCharColor);
if (stroke)
{
QColor tmp = p->pen();
p->setPen(p->brush(), 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
p->setLineWidth(style.fontSize() * glyphs.scaleV / 200.0);
p->strokePath();
p->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
}
else
{
p->setFillMode(1);
p->fillPath();
}
p->setBrush(oldBrush);
if (glyphs.more)
{
p->translate(glyphs.xadvance, 0);
drawGlyphs(p, style, ScLayout_None, *glyphs.more);
}
return;
}
else if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode()) ||
glyph == (ScFace::CONTROL_GLYPHS + 32))
glyph = font.char2CMap(QChar(' '));
else if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode()))
glyph = font.char2CMap(QChar('-'));
if (glyph >= ScFace::CONTROL_GLYPHS || (style.effects() & ScLayout_SuppressSpace)) {
// qDebug("drawGlyphs: skipping %d", glyph);
// all those are empty
if (glyphs.more)
{
p->translate(glyphs.xadvance, 0);
drawGlyphs(p, style, ScLayout_None, *glyphs.more);
}
return;
}
// if (font.canRender(QChar(glyph)))
{
FPointArray gly = font.glyphOutline(glyph);
// Do underlining first so you can get typographically correct
// underlines when drawing a white outline
if (((style.effects() & ScStyle_Underline) || ((style.effects() & ScStyle_UnderlineWords) && glyph != font.char2CMap(QChar(' ')))) && (style.strokeColor() != CommonStrings::None))
{
double st, lw;
if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
{
if (style.underlineOffset() != -1)
st = (style.underlineOffset() / 1000.0) * (font.descent(style.fontSize() / 10.0));
else
st = font.underlinePos(style.fontSize() / 10.0);
if (style.underlineWidth() != -1)
lw = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
else
lw = qMax(font.strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
st = font.underlinePos(style.fontSize() / 10.0);
lw = qMax(font.strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
st += (style.fontSize() / 10.0) * glyphs.scaleV * (style.baselineOffset() / 1000.0);
QColor tmpC = p->pen();
int oldStrokeMode = p->strokeMode();
p->setPen(p->brush());
p->setLineWidth(lw);
p->setStrokeMode(1);
if (style.effects() & ScStyle_Subscript)
p->drawLine(FPoint(glyphs.xoffset, glyphs.yoffset - st), FPoint(glyphs.xoffset + glyphs.xadvance, glyphs.yoffset - st));
else
p->drawLine(FPoint(glyphs.xoffset, -st), FPoint(glyphs.xoffset + glyphs.xadvance, -st));
p->setStrokeMode(oldStrokeMode);
p->setPen(tmpC);
}
if (gly.size() > 3)
{
if (glyph == 0)
{
// qDebug() << QString("glyph 0: (%1,%2) * %3 %4 + %5").arg(glyphs.xoffset).arg(glyphs.yoffset).arg(glyphs.scaleH).arg(glyphs.scaleV).arg(glyphs.xadvance));
}
p->save();
p->translate(glyphs.xoffset, glyphs.yoffset - ((style.fontSize() / 10.0) * glyphs.scaleV));
if (m_isReversed)
{
p->scale(-1, 1);
p->translate(-glyphs.xadvance, 0);
}
if (style.baselineOffset() != 0)
p->translate(0, -(style.fontSize() / 10.0) * (style.baselineOffset() / 1000.0));
double glxSc = glyphs.scaleH * style.fontSize() / 100.00;
double glySc = glyphs.scaleV * style.fontSize() / 100.0;
p->scale(glxSc, glySc);
// p->setFillMode(1);
bool fr = p->fillRule();
p->setFillRule(false);
// double a = gly.point(0).x();
// double b = gly.point(0).y();
// double c = gly.point(3).x();
// double d = gly.point(3).y();
// qDebug() << QString("drawglyphs: %1 (%2,%3) (%4,%5) scaled %6,%7 trans %8,%9")
// .arg(gly.size()).arg(a).arg(b).arg(c).arg(d)
// .arg(p->worldMatrix().m11()).arg(p->worldMatrix().m22()).arg(p->worldMatrix().dx()).arg(p->worldMatrix().dy());
p->setupPolygon(&gly, true);
if (m_Doc->layerOutline(LayerID))
{
p->save();
p->setPen(m_Doc->layerMarker(LayerID), 0.5, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
p->setFillMode(ScPainter::None);
p->setBrushOpacity(1.0);
p->setPenOpacity(1.0);
p->strokePath();
p->restore();
p->setFillRule(fr);
p->restore();
if (glyphs.more)
{
p->translate(glyphs.xadvance, 0);
drawGlyphs(p, style, ScLayout_None, *glyphs.more);
}
return;
}
if (glyph == 0)
{
p->setPen(PrefsManager::instance()->appPrefs.displayPrefs.controlCharColor, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
p->setLineWidth(style.fontSize() * glyphs.scaleV * style.outlineWidth() * 2 / 10000.0);
p->strokePath();
}
else if ((font.isStroked()) && (style.strokeColor() != CommonStrings::None) && ((style.fontSize() * glyphs.scaleV * style.outlineWidth() / 10000.0) != 0))
{
QColor tmp = p->brush();
p->setStrokeMode(1);
p->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
p->setLineWidth(style.fontSize() * glyphs.scaleV * style.outlineWidth() / 10000.0);
p->strokePath();
}
else
{
if ((style.effects() & ScStyle_Shadowed) && (style.strokeColor() != CommonStrings::None))
{
p->save();
p->translate((style.fontSize() * glyphs.scaleH * style.shadowXOffset() / 10000.0) / glxSc, -(style.fontSize() * glyphs.scaleV * style.shadowYOffset() / 10000.0) / glySc);
QColor tmp = p->brush();
p->setBrush(p->pen());
p->setupPolygon(&gly, true);
p->fillPath();
p->setBrush(tmp);
p->restore();
p->setupPolygon(&gly, true);
}
if (style.fillColor() != CommonStrings::None)
p->fillPath();
if ((style.effects() & ScStyle_Outline) && (style.strokeColor() != CommonStrings::None) && ((style.fontSize() * glyphs.scaleV * style.outlineWidth() / 10000.0) != 0))
{
p->setStrokeMode(1);
p->setLineWidth((style.fontSize() * glyphs.scaleV * style.outlineWidth() / 10000.0) / glySc);
p->strokePath();
}
}
p->setFillRule(fr);
p->restore();
}
else {
// qDebug() << "drawGlyphs: empty glyph" << glyph;
}
if ((style.effects() & ScStyle_Strikethrough) && (style.strokeColor() != CommonStrings::None))
{
double st, lw;
if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
{
if (style.strikethruOffset() != -1)
st = (style.strikethruOffset() / 1000.0) * (font.ascent(style.fontSize() / 10.0));
else
st = font.strikeoutPos(style.fontSize() / 10.0);
if (style.strikethruWidth() != -1)
lw = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
else
lw = qMax(font.strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
st = font.strikeoutPos(style.fontSize() / 10.0);
lw = qMax(font.strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
st += (style.fontSize() / 10.0) * glyphs.scaleV * (style.baselineOffset() / 1000.0);
int oldStrokeMode = p->strokeMode();
p->setPen(p->brush());
p->setLineWidth(lw);
p->setStrokeMode(1);
p->drawLine(FPoint(glyphs.xoffset, glyphs.yoffset - st), FPoint(glyphs.xoffset + glyphs.xadvance, glyphs.yoffset - st));
p->setStrokeMode(oldStrokeMode);
}
}
/* else
{
p->setLineWidth(1);
p->setPen(red);
p->setBrush(red);
p->setFillMode(1);
p->drawRect(glyphs.xoffset, glyphs.yoffset - (style.fontSize() / 10.0) * glyphs.scaleV , (style.fontSize() / 10.0) * glyphs.scaleH, (style.fontSize() / 10.0) * glyphs.scaleV);
}
*/
if (glyphs.more)
{
p->translate(glyphs.xadvance, 0);
drawGlyphs(p, style, ScLayout_None, *glyphs.more);
}
}
 
void PageItem::DrawPolyL(QPainter *p, QPolygon pts)
{
if (Segments.count() != 0)
/trunk/Scribus/scribus/pageitem.h
415,9 → 415,8
/// Return current text properties (current char + paragraph properties)
void currentTextProps(ParagraphStyle& parStyle) const;
// deprecated:
double layoutGlyphs(const CharStyle& style, const QString& chars, LayoutFlags flags, GlyphLayout& layout);
GlyphLayout layoutGlyphs(const CharStyle& style, const QString& chars, LayoutFlags flags);
void SetQColor(QColor *tmp, QString farbe, double shad);
void drawGlyphs(ScPainter *p, const CharStyle& style, LayoutFlags flags, GlyphLayout& glyphs );
void DrawPolyL(QPainter *p, QPolygon pts);
QString ExpandToken(uint base);
const FPointArray shape() const { return PoLine; }
/trunk/Scribus/scribus/pageitem_pathtext.cpp
46,6 → 46,9
#include "undostate.h"
#include "util.h"
#include "util_math.h"
#include "text/boxes.h"
#include "text/textlayoutpainter.h"
#include "text/screenpainter.h"
 
using namespace std;
 
79,18 → 82,8
double dx;
FPoint point = FPoint(0, 0);
FPoint tangent = FPoint(0, 0);
QColor tmp;
CurX = m_textDistanceMargins.left();
QString cachedStroke = "";
QString cachedFill = "";
double cachedFillShade = -1;
double cachedStrokeShade = -1;
QString actStroke = "";
QString actFill = "";
double actFillShade = -1;
double actStrokeShade = -1;
QColor cachedFillQ;
QColor cachedStrokeQ;
 
if (!m_Doc->layerOutline(LayerID))
{
if (PoShow)
202,7 → 195,6
double wordExtra = 0;
for (a = firstChar; a < itemRenderText.length(); ++a)
{
GlyphLayout* glyphs = itemRenderText.getGlyphs(a);
chstr = itemRenderText.text(a, 1);
if (chstr[0] == SpecialChars::PAGENUMBER || chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::PAGECOUNT
|| chstr[0] == SpecialChars::TAB || chstr[0] == SpecialChars::LINEBREAK)
211,13 → 203,11
spaceCount++;
if (a < itemRenderText.length()-1)
chstr += itemRenderText.text(a+1, 1);
glyphs->yadvance = 0;
layoutGlyphs(itemRenderText.charStyle(a), chstr, itemRenderText.flags(a), *glyphs);
glyphs->shrink();
GlyphLayout glyphs = layoutGlyphs(itemRenderText.charStyle(a), chstr, itemRenderText.flags(a));
if (itemRenderText.hasObject(a))
totalTextLen += (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs->scaleH;
totalTextLen += (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs.scaleH;
else
totalTextLen += glyphs->wide()+itemRenderText.charStyle(a).fontSize() * itemRenderText.charStyle(a).tracking() / 10000.0;
totalTextLen += glyphs.xadvance+itemRenderText.charStyle(a).fontSize() * itemRenderText.charStyle(a).tracking() / 10000.0;
}
for (int segs = 0; segs < PoLine.size()-3; segs += 4)
{
252,10 → 242,10
QList<QPainterPath> pathList = decomposePath(guidePath);
QPainterPath currPath = pathList[0];
int currPathIndex = 0;
PathLineBox* linebox = new PathLineBox();
for (a = firstChar; a < itemRenderText.length(); ++a)
{
CurY = 0;
GlyphLayout* glyphs = itemRenderText.getGlyphs(a);
PathData* pdata = & (textLayout.point(a));
chstr = itemRenderText.text(a,1);
if (chstr[0] == SpecialChars::PAGENUMBER || chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::PAGECOUNT
263,15 → 253,16
continue;
if (a < itemRenderText.length()-1)
chstr += itemRenderText.text(a+1, 1);
glyphs->yadvance = 0;
layoutGlyphs(itemRenderText.charStyle(a), chstr, itemRenderText.flags(a), *glyphs);
glyphs->shrink(); // HACK
 
GlyphLayout glyphs = layoutGlyphs(itemRenderText.charStyle(a), chstr, itemRenderText.flags(a));
GlyphRun run(&itemRenderText.charStyle(a), itemRenderText.flags(a), a, a, itemRenderText.object(a));
run.glyphs().append(glyphs);
 
if (itemRenderText.hasObject(a))
dx = (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs->scaleH / 2.0;
dx = (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs.scaleH / 2.0;
else
dx = glyphs->wide() / 2.0;
dx = glyphs.xadvance / 2.0;
CurX += dx;
 
double currPerc = currPath.percentAtLength(CurX);
if (currPerc >= 0.9999999)
{
293,7 → 284,7
QPointF currPoint = currPath.pointAtPercent(currPerc);
tangent = FPoint(cos(currAngle * M_PI / 180.0), sin(currAngle * M_PI / 180.0));
point = FPoint(currPoint.x(), currPoint.y());
glyphs->xoffset = 0;
glyphs.xoffset = 0;
pdata->PtransX = point.x();
pdata->PtransY = point.y();
pdata->PRot = currAngle * M_PI / 180.0;
315,63 → 306,56
else
trafo *= QTransform( a, 4 * a, 0, -1, point.x(), point.y() );
}
QTransform sca = p->worldMatrix();
trafo *= sca;
p->save();
QTransform savWM = p->worldMatrix();
p->setWorldMatrix(trafo);
if (!m_Doc->RePos)
 
 
const CharStyle& cStyle(run.style());
double scaleV = cStyle.scaleV() / 1000.0;
double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0);
double ascent = cStyle.font().ascent(cStyle.fontSize()/10.00) * scaleV + offset;
double descent = cStyle.font().descent(cStyle.fontSize()/10.00) * scaleV - offset;
linebox->setAscent(ascent);
linebox->setDescent(descent);
Box* box;
if (itemRenderText.hasObject(a))
{
actFill = itemRenderText.charStyle(a).fillColor();
actFillShade = itemRenderText.charStyle(a).fillShade();
if (actFill != CommonStrings::None)
{
p->setFillMode(ScPainter::Solid);
if ((cachedFillShade != actFillShade) || (cachedFill != actFill))
{
SetQColor(&tmp, actFill, actFillShade);
p->setBrush(tmp);
cachedFillQ = tmp;
cachedFill = actFill;
cachedFillShade = actFillShade;
}
else
p->setBrush(cachedFillQ);
}
else
p->setFillMode(ScPainter::None);
actStroke = itemRenderText.charStyle(a).strokeColor();
actStrokeShade = itemRenderText.charStyle(a).strokeShade();
if (actStroke != CommonStrings::None)
{
if ((cachedStrokeShade != actStrokeShade) || (cachedStroke != actStroke))
{
SetQColor(&tmp, actStroke, actStrokeShade);
p->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
cachedStrokeQ = tmp;
cachedStroke = actStroke;
cachedStrokeShade = actStrokeShade;
}
else
p->setPen(cachedStrokeQ, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
}
p->translate(0.0, BaseOffs);
if (itemRenderText.hasObject(a))
DrawObj_Embedded(p, cullingArea, itemRenderText.charStyle(a), itemRenderText.object(a));
else
drawGlyphs(p, itemRenderText.charStyle(a), itemRenderText.flags(a), *glyphs);
box = new ObjectBox(run);
box->setAscent(run.object()->height() - run.object()->lineWidth());
box->setDescent(0);
}
p->setWorldMatrix(savWM);
p->restore();
else
{
box = new GlyphBox(run);
box->setAscent(linebox->ascent());
box->setDescent(linebox->descent());
}
 
box->setMatrix(trafo);
linebox->addBox(box);
 
 
MaxChars = a+1;
CurX -= dx;
if (itemRenderText.hasObject(a))
CurX += (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs->scaleH + extraOffset;
CurX += (itemRenderText.object(a)->width() + itemRenderText.object(a)->lineWidth()) * glyphs.scaleH + extraOffset;
else if (chstr[0] == SpecialChars::BLANK)
CurX += glyphs->wide()+itemRenderText.charStyle(a).fontSize() * itemRenderText.charStyle(a).tracking() / 10000.0 + wordExtra + extraOffset;
CurX += glyphs.xadvance+itemRenderText.charStyle(a).fontSize() * itemRenderText.charStyle(a).tracking() / 10000.0 + wordExtra + extraOffset;
else
CurX += glyphs->wide()+itemRenderText.charStyle(a).fontSize() *itemRenderText.charStyle(a).tracking() / 10000.0 + extraOffset;
CurX += glyphs.xadvance+itemRenderText.charStyle(a).fontSize() *itemRenderText.charStyle(a).tracking() / 10000.0 + extraOffset;
}
 
textLayout.addColumn(0, 0);
textLayout.appendLine(linebox);
 
if (!m_Doc->RePos)
{
int fm = p->fillMode();
p->setFillMode(1);
p->save();
ScreenPainter painter(p, this);
textLayout.render(&painter);
p->setFillMode(fm);
p->restore();
}
}
 
bool PageItem_PathText::createInfoGroup(QFrame *infoGroup, QGridLayout *infoGroupLayout)
/trunk/Scribus/scribus/pageitem_textframe.cpp
55,6 → 55,8
#include "scribusview.h"
#include "scribusstructs.h"
#include "selection.h"
#include "text/boxes.h"
#include "text/screenpainter.h"
#include "ui/guidemanager.h"
#include "ui/marksmanager.h"
#include "undomanager.h"
346,7 → 348,7
stream << "scaleV" << "\t";
stream << "\n";
 
for (int zc = line.firstItem; zc < line.lastItem; ++zc)
for (int zc = line.firstChar; zc < line.lastChar; ++zc)
{
const ScText* item = itemText.item(zc);
 
388,46 → 390,6
}
*/
 
/**
Clones the tab fill char as often as necssary after all distances are known
*/
static void fillInTabLeaders(StoryText & itemText, LineSpec & curLine)
{
// fill in tab leaders
double xPos = curLine.x;
for (int ti= curLine.firstItem; ti <= curLine.lastItem; ++ti)
{
GlyphLayout* glyphs = itemText.getGlyphs(ti);
if (itemText.text(ti) == SpecialChars::TAB)
{
GlyphLayout * tglyph = glyphs->more;
 
if (!tglyph)
continue;
 
const CharStyle & charStyle(itemText.charStyle(ti));
double wt = charStyle.font().glyphWidth(tglyph->glyph, charStyle.fontSize() * tglyph->scaleV / 10.0);
double len = glyphs->xadvance;
int count = static_cast<int>(len / wt);
double sPos = -len;
tglyph->xoffset = sPos;
// qDebug() << QString("tab leaders: %1 %2 width=%3 count=%4").arg(sPos).arg(curLine.y).arg(wt).arg(count);
for (int cx = 1; cx < count; ++cx)
{
// clone fillchar
tglyph->grow();
*(tglyph->more) = *tglyph;
tglyph->more->more = NULL;
tglyph = tglyph->more;
tglyph->xoffset = sPos + wt * cx;
}
}
xPos += glyphs->wide();
}
}
 
 
 
enum TabStatus {
TabNONE = 0,
TabLEFT = TabNONE,
442,19 → 404,36
fields which describe what type of tab is currently active
*/
struct TabControl {
bool active;
int status;
int charIndex;
double xPos;
QChar fillChar;
bool active;
int status;
double xPos;
QChar fillChar;
GlyphLayout* tabGlyph;
};
 
struct LineSpec
{
qreal x;
qreal y;
qreal width;
qreal ascent;
qreal descent;
qreal colLeft;
 
int firstRun;
int lastRun;
qreal naturalWidth;
bool isFirstLine;
qreal height;
};
 
/**
fields which describe how the current line is placed into the frame
*/
*/
struct LineControl {
LineSpec line;
int itemsInLine;
QList<GlyphRun>& glyphRuns;
bool isEmpty;
int hyphenCount;
double colWidth;
double colGap;
472,8 → 451,8
double leftIndent;
double rightMargin;
double mustLineEnd;
int restartIndex; //index of char where line computing should be restarted
int restartRowIndex; //index of char where row of text is started
int restartIndex; //index of glyph run where line computing should be restarted
int restartRowIndex; //index of glyph run where row of text is started
double restartX; //starting X position of line if must be restarted
double rowDesc;
 
487,38 → 466,36
 
double maxShrink;
double maxStretch;
ScribusDoc *doc;
 
 
/// remember frame dimensions and offsets
void init(double w, double h, const MarginStruct& extra, double lCorr)
LineControl(double w, double h, const MarginStruct& extra, double lCorr, ScribusDoc* d, QList<GlyphRun>& runs, double colwidth, double colgap)
: glyphRuns(runs)
, hasDropCap(false)
, doc(d)
{
insets = extra;
lineCorr = lCorr;
frameWidth = w;
frameHeight = h;
hasDropCap = false;
}
 
/// start at column 0
void initColumns(double width, double gap)
{
column = 0;
colWidth = width;
colGap = gap;
colWidth = colwidth;
colGap = colgap;
hyphenCount = 0;
}
 
/// move position to next column
void nextColumn(double asce = 0.0)
void nextColumn(TextLayout &textLayout)
{
startOfCol = true;
colLeft = (colWidth + colGap) * column + insets.left() + lineCorr;
textLayout.addColumn(colLeft, colWidth);
//now colRight is REAL column right edge
colRight = colLeft + colWidth;
if (legacy)
colRight += lineCorr;
xPos = colLeft;
yPos = asce + insets.top() + lineCorr;
line.colLeft = colLeft;
yPos = insets.top() + lineCorr;
}
 
bool isEndOfCol(double morespace = 0)
529,19 → 506,18
/**
init fields for a new line at current position
*/
void startLine(int first)
void startLine(int firstRun)
{
itemsInLine = 0;
isEmpty = true;
line.x = xPos;
line.y = yPos;
line.firstItem = first;
line.lastItem = 0;
line.firstRun = firstRun;
line.lastRun = 0;
line.ascent = 0.0;
line.descent = 0.0;
line.width = 0.0;
line.naturalWidth = 0.0;
line.colLeft = colLeft;
line.isFirstLine = false;
breakIndex = -1;
breakXPos = 0.0;
maxShrink = 0.0;
586,18 → 562,17
breakXPos = pos;
breakIndex = index;
}
 
/// called when a mandatory break is found
void breakLine(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy, int last)
void breakLine(const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy, int last)
{
breakIndex = last;
breakXPos = line.x;
for (int j = line.firstItem; j <= last; ++j)
if ( !itemText.hasFlag(j, ScLayout_SuppressSpace) )
breakXPos += itemText.getGlyphs(j)->wide();
for (int i = line.firstRun; i <= breakIndex; i++)
breakXPos += glyphRuns.at(i).width();
// #8194, #8717 : update line ascent and descent with sensible values
// so that endOfLine() returns correct result
updateHeightMetrics(itemText);
updateHeightMetrics();
// #9060 : update line offset too
// updateLineOffset(itemText, style, offsetPolicy);
}
605,7 → 580,7
/// use the last remembered break to set line width and itemrange
void finishLine(double endX)
{
line.lastItem = breakIndex;
line.lastRun = breakIndex;
line.naturalWidth = breakXPos - line.x;
line.width = endX - line.x;
maxShrink = maxStretch = 0;
620,7 → 595,7
startLine(restartRowIndex);
addLeftIndent = true;
afterOverflow = false;
return restartRowIndex -1;
return restartRowIndex - 1;
}
 
int restartLine(bool recalcY, bool add)
630,7 → 605,7
xPos = restartX;
startLine(restartIndex);
afterOverflow = false;
return restartIndex -1;
return restartIndex - 1;
}
 
bool isEndOfLine(double moreSpace = 0)
732,147 → 707,29
return qMin(EndX2, maxX);
}
 
double getLineAscent(const StoryText& itemText)
void updateHeightMetrics()
{
double result = 0;
QChar firstChar = itemText.text (line.firstItem);
if ((firstChar == SpecialChars::PAGENUMBER) || (firstChar == SpecialChars::PAGECOUNT))
firstChar = '8';
PageItem *obj = itemText.object (line.firstItem);
const CharStyle& fcStyle(itemText.charStyle(line.firstItem));
if ((firstChar == SpecialChars::PARSEP) || (firstChar == SpecialChars::LINEBREAK))
result = fcStyle.font().ascent(fcStyle.fontSize() / 10.0);
else if (obj)
result = qMax(result, (obj->height() + obj->lineWidth()) * (fcStyle.scaleV() / 1000.0));
else
result = fcStyle.font().realCharAscent(firstChar, fcStyle.fontSize() / 10.0);
for (int zc = 0; zc < itemsInLine; ++zc)
{
QChar ch = itemText.text(line.firstItem + zc);
if ((ch == SpecialChars::PAGENUMBER) || (ch == SpecialChars::PAGECOUNT))
ch = '8'; // should have highest ascender even in oldstyle
const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc));
if ((ch == SpecialChars::TAB) || (ch == QChar(10))
|| SpecialChars::isBreak (ch, true) || (ch == SpecialChars::NBHYPHEN) || (ch.isSpace()))
continue;
double asce;
PageItem *obj = itemText.object (line.firstItem + zc);
if (obj)
asce = obj->height() + obj->lineWidth() * (cStyle.scaleV() / 1000.0);
else
asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0);
// qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result);
result = qMax(result, asce);
}
return result;
line.ascent = line.descent = 0;
// Can happen when inserting a new line at end of text, WTF!
if (line.firstRun >= glyphRuns.length())
return;
const CharStyle& cStyle(glyphRuns.at(line.firstRun).style());
double scaleV = cStyle.scaleV() / 1000.0;
double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0);
line.ascent = cStyle.font().ascent(cStyle.fontSize()/10.00) * scaleV + offset;
line.descent = cStyle.font().descent(cStyle.fontSize()/10.00) * scaleV - offset;
}
 
double getLineDescent(const StoryText& itemText)
{
double result = 0;
QChar firstChar = itemText.text(line.firstItem);
if ((firstChar == SpecialChars::PAGENUMBER) || (firstChar == SpecialChars::PAGECOUNT))
firstChar = '8';
const CharStyle& fcStyle(itemText.charStyle(line.firstItem));
if ((firstChar == SpecialChars::PARSEP) || (firstChar == SpecialChars::LINEBREAK))
result = fcStyle.font().descent(fcStyle.fontSize() / 10.0);
else if (itemText.object(line.firstItem))
result = 0.0;
else
result = fcStyle.font().realCharDescent(firstChar, fcStyle.fontSize() / 10.0);
for (int zc = 0; zc < itemsInLine; ++zc)
{
QChar ch = itemText.text(line.firstItem + zc);
if ((ch == SpecialChars::PAGENUMBER) || (ch == SpecialChars::PAGECOUNT))
ch = '8'; // should have highest ascender even in oldstyle
const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc));
if ((ch == SpecialChars::TAB) || (ch == QChar(10))
|| SpecialChars::isBreak (ch, true) || (ch == SpecialChars::NBHYPHEN) || (ch.isSpace()))
continue;
double desc;
if (itemText.object(line.firstItem + zc))
desc = 0.0;
else
desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0);
// qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result);
result = qMax(result, desc);
}
return result;
}
 
double getLineHeight(const StoryText& itemText)
{
double result = 0;
const CharStyle& firstStyle(itemText.charStyle(line.firstItem));
PageItem *obj = itemText.object (line.firstItem);
if (obj)
result = qMax(result, (obj->height() + obj->lineWidth()) * (firstStyle.scaleV() / 1000.0));
else
result = firstStyle.font().height(firstStyle.fontSize() / 10.0);
for (int zc = 0; zc < itemsInLine; ++zc)
{
QChar ch = itemText.text(line.firstItem+zc);
if ((ch == SpecialChars::TAB) || (ch == QChar(10))
|| SpecialChars::isBreak (ch, true) || (ch == SpecialChars::NBHYPHEN) || (ch.isSpace()))
continue;
const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc));
PageItem *obj = itemText.object (line.firstItem + zc);
double asce;
if (obj)
asce = (obj->height() + obj->lineWidth()) * (cStyle.scaleV() / 1000.0);
else
asce = cStyle.font().height (cStyle.fontSize() / 10.0);
// qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result);
result = qMax(result, asce);
}
return result;
}
 
void updateHeightMetrics(const StoryText& itemText)
{
double asce, desc, hei;
line.ascent = 0;
line.descent = 0;
line.height = 0;
for (int zc = 0; zc < itemsInLine; ++zc)
{
QChar ch = itemText.text(line.firstItem+zc);
if ((ch == SpecialChars::TAB) || (ch == QChar(10))
|| SpecialChars::isBreak (ch, true) || (ch == SpecialChars::NBHYPHEN) || (ch.isSpace()))
continue;
const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc));
double scaleV = cStyle.scaleV() / 1000.0;
double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0);
 
if (itemText.object(line.firstItem+zc) != 0)
{
asce = (itemText.object(line.firstItem+zc)->height() + itemText.object(line.firstItem+zc)->lineWidth()) * scaleV + offset;
desc = 0.0;
hei = asce;
}
else //if ((itemText.flags(current.line.firstItem+zc) & ScLayout_DropCap) == 0)
{
asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0) * scaleV + offset;
desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0) * scaleV - offset;
hei = cStyle.font().height(cStyle.fontSize() / 10.0) * scaleV;
}
// qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result);
line.ascent = qMax(line.ascent, asce);
line.descent = qMax(line.descent, desc);
line.height = qMax(line.height, hei);
}
}
 
// yPos should not be changed when all line is already calculated - at new y position there can be overflow!!!
// edit: can't happen as it should only move upwards, and this is covered by the calculations done.
//void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy)
//{
// if (itemsInLine <= 0)
// if (charsInLine <= 0)
// return;
// if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing))
// {
// //FIXME: use glyphs, not chars
// double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).fontSize() / 10.0);
// double firstasce = itemText.charStyle(line.firstChar).font().ascent(itemText.charStyle(line.firstChar).fontSize() / 10.0);
// double adj (0.0);
// double currasce (this->getLineAscent(itemText));
// if (offsetPolicy == FLOPRealGlyphHeight)
893,11 → 750,11
// }
// else if ((!startOfCol) && (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing))
// {
// QChar ch = itemText.text(line.firstItem);
// QChar ch = itemText.text(line.firstChar);
// double firstasce = style.lineSpacing();
// double currasce = getLineHeight(itemText);
// double adj = firstasce - currasce;
// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj);
// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstChar).arg(-adj);
// line.ascent = currasce;
// line.y -= adj;
// yPos -= adj;
904,6 → 761,40
// }
//}
 
LineBox* createLineBox()
{
LineBox* result = new LineBox();
result->moveTo(line.x - colLeft, line.y);
result->setWidth(line.width);
result->setAscent(line.ascent);
result->setDescent(line.descent);
 
for (int i = line.firstRun; i <= line.lastRun; ++i)
{
addBox(result, glyphRuns.at(i));
}
 
return result;
}
 
void addBox(LineBox *lineBox, const GlyphRun& run)
{
Box* result;
if (run.object())
{
result = new ObjectBox(run);
result->setAscent(run.object()->height() - run.object()->lineWidth());
result->setDescent(0);
}
else
{
result = new GlyphBox(run);
result->setAscent(lineBox->ascent());
result->setDescent(lineBox->descent());
}
lineBox->addBox(result);
}
 
private:
double frameWidth;
double frameHeight;
911,6 → 802,34
double lineCorr;
};
 
/**
Clones the tab fill char as often as necssary after all distances are known
*/
static void fillInTabLeaders(LineControl & current)
{
// fill in tab leaders
for(int i = current.line.firstRun; i <= current.line.lastRun; i++)
{
GlyphRun& glyphRun = current.glyphRuns[i];
CharStyle charStyle(glyphRun.style());
if (glyphRun.hasFlag(ScLayout_TabLeaders))
{
GlyphLayout tglyph = glyphRun.glyphs().last();
double width = glyphRun.width();
double wt = charStyle.font().glyphWidth(tglyph.glyph, charStyle.fontSize() * tglyph.scaleV / 10.0);
int count = static_cast<int>(width / wt);
glyphRun.glyphs().clear();
for(int cx = 0; cx < count; ++cx)
{
GlyphLayout more = tglyph;
more.xadvance = width / count;
glyphRun.glyphs().append(more);
}
}
}
}
 
 
static bool checkCJK(QChar ch) {
unsigned int code = ch.unicode();
if ( (0x2E80 < code && code < 0x2EFF) || // CJK Radicals Supplement
957,10 → 876,6
return true;
}
 
static bool implicitSpace(QChar f, QChar s) {
return checkCJK(f) && checkCJK(s);
}
 
static bool implicitBreak(QChar f, QChar s) {
if (checkCJK(f) && checkCJK(s)) {
return allowedCJKBreakAfter(f) && allowedCJKBreakBefore(s);
969,7 → 884,7
}
 
/// called when line length is known and line is to be justified
static void justifyLine(StoryText& itemText, LineSpec& line)
static void justifyLine(const ParagraphStyle& style, LineControl& curr)
{
 
double glyphNatural = 0;
979,24 → 894,21
int spaceInsertion = 0;
double imSpace = -1;
 
const ParagraphStyle& style(itemText.paragraphStyle(line.firstItem));
 
// measure natural widths for glyphs and spaces
for (int sof = line.firstItem; sof <= line.lastItem; ++sof)
for (int i = curr.line.firstRun; i <= curr.line.lastRun; ++i)
{
GlyphLayout* glyph = itemText.getGlyphs(sof);
QChar ch = itemText.text(sof);
if (!SpecialChars::isExpandingSpace(ch))
GlyphRun glyphrun = curr.glyphRuns[i];
if (!glyphrun.hasFlag(ScLayout_ExpandingSpace))
{
glyphNatural += glyph->wide();
glyphNatural += glyphrun.width();
}
else if ( !itemText.hasFlag(sof, ScLayout_SuppressSpace) )
else if ( !glyphrun.hasFlag(ScLayout_SuppressSpace) )
{
spaceNatural += glyph->wide();
if (imSpace < 0.0 || imSpace > glyph->wide())
imSpace = glyph->wide();
spaceNatural += glyphrun.width();
if (imSpace < 0.0 || imSpace > glyphrun.width())
imSpace = glyphrun.width();
}
if (sof != line.firstItem && implicitSpace(itemText.text(sof - 1), ch)) {
if (i != curr.line.firstRun && glyphrun.hasFlag(ScLayout_ImplicitSpace))
{
spaceInsertion += 1;
}
}
1005,16 → 917,16
 
// decision: prio 1: stretch glyph; prio 2: insert spaces; prio 3: stretch spaces
 
if (line.width < spaceNatural + glyphNatural * style.minGlyphExtension() && spaceNatural > 0)
if (curr.line.width < spaceNatural + glyphNatural * style.minGlyphExtension() && spaceNatural > 0)
{
glyphExtension = style.minGlyphExtension() - 1;
spaceExtension = (line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural - 1;
spaceExtension = (curr.line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural - 1;
imSpace = 0;
}
else if (line.width < spaceNatural + glyphNatural * style.maxGlyphExtension() && glyphNatural > 0)
else if (curr.line.width < spaceNatural + glyphNatural * style.maxGlyphExtension() && glyphNatural > 0)
{
spaceExtension = 0;
glyphExtension = (line.width - spaceNatural) / glyphNatural - 1;
glyphExtension = (curr.line.width - spaceNatural) / glyphNatural - 1;
imSpace = 0;
}
else
1021,7 → 933,7
{
glyphExtension = style.maxGlyphExtension() - 1;
if (spaceInsertion) {
double remaining = line.width - glyphNatural * (1 + glyphExtension) - spaceNatural;
double remaining = curr.line.width - glyphNatural * (1 + glyphExtension) - spaceNatural;
if (imSpace > 0) {
if (remaining / spaceInsertion < imSpace) {
imSpace = remaining / spaceInsertion;
1036,7 → 948,7
}
} else {
if (spaceNatural > 0)
spaceExtension = (line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural - 1;
spaceExtension = (curr.line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural - 1;
else
spaceExtension = 0;
}
1051,47 → 963,51
.arg(style.minWordTracking()).arg(style.minGlyphExtension());
*/
 
int startItem = line.firstItem;
if (itemText.hasFlag(startItem, ScLayout_DropCap))
int startItem = curr.line.firstRun;
if (curr.glyphRuns[startItem].hasFlag(ScLayout_DropCap))
startItem++;
// distribute whitespace on spaces and glyphs
for (int yof = startItem; yof <= line.lastItem; ++yof)
 
for (int i = startItem; i <= curr.line.lastRun; ++i)
{
GlyphLayout* glyph = itemText.getGlyphs(yof);
QChar ch = itemText.text(yof);
double wide = glyph->wide();
if (!SpecialChars::isExpandingSpace(ch))
GlyphRun& glyphrun = curr.glyphRuns[i];
if (i != curr.line.firstRun && glyphrun.hasFlag(ScLayout_ImplicitSpace))
{
glyph->last()->xadvance += wide * glyphExtension;
while (glyph)
GlyphRun& lastRun = curr.glyphRuns[i-1];
lastRun.glyphs().last().xadvance += imSpace;
}
double wide = glyphrun.width();
if (!glyphrun.hasFlag(ScLayout_ExpandingSpace))
{
for (int j = 0; j < glyphrun.glyphs().count(); ++j)
{
glyph->xoffset *= glyphScale;
glyph->scaleH *= glyphScale;
glyph = glyph->more;
GlyphLayout& glyph = glyphrun.glyphs()[j];
glyph.xadvance += wide * glyphExtension;
glyph.xoffset *= glyphScale;
glyph.scaleH *= glyphScale;
}
}
else if (!itemText.hasFlag(yof, ScLayout_SuppressSpace))
else if (!glyphrun.hasFlag(ScLayout_SuppressSpace))
{
glyph->last()->xadvance += wide * spaceExtension;
GlyphLayout& glyph = glyphrun.glyphs().last();
glyph.xadvance += wide * spaceExtension;
 
}
if (yof != line.firstItem && implicitSpace(itemText.text(yof - 1), ch)) {
itemText.getGlyphs(yof - 1)->last()->xadvance += imSpace;
}
}
}
 
 
/// called when linelength is known and line is not justified
static void indentLine(StoryText& itemText, LineSpec& line, double leftIndent)
static void indentLine(const ParagraphStyle& style, LineControl& curr, double leftIndent)
{
if (line.naturalWidth > line.width)
if (curr.line.naturalWidth > curr.line.width)
{
justifyLine(itemText, line);
justifyLine(style, curr);
}
if (leftIndent > 0)
{
line.x += leftIndent;
line.width -= leftIndent;
curr.line.x += leftIndent;
curr.line.width -= leftIndent;
}
}
 
1099,8 → 1015,8
///// calculate how much the first char should stick out to the left
//static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line)
//{
// int b = line.firstItem;
// while (b < line.lastItem && (itemText.flags(b)) & ScLayout_SuppressSpace))
// int b = line.firstChar;
// while (b < line.lastChar && (itemText.flags(b) & ScLayout_SuppressSpace))
// ++b;
//
// double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
1135,19 → 1051,20
//}
 
/// calculate how much the last char should stick out to the right
static double opticalRightMargin(const StoryText& itemText, const LineSpec& line)
static double opticalRightMargin(const StoryText& itemText, const QList<GlyphRun> runs, const LineSpec& line)
{
int b = line.lastItem;
while (b > line.firstItem &&
(SpecialChars::isBreakingSpace(itemText.text(b)) || SpecialChars::isBreak(itemText.text(b)))
int b = line.lastRun;
while (b > line.firstRun &&
(SpecialChars::isBreakingSpace(itemText.text(runs[b].firstChar())) ||
SpecialChars::isBreak(itemText.text(runs[b].firstChar())))
)
--b;
if (b >= line.firstItem)
if (b >= line.firstRun)
{
const CharStyle& chStyle(itemText.charStyle(b));
const CharStyle& chStyle(runs[b].style());
double chs = chStyle.fontSize() * (chStyle.scaleH() / 1000.0);
QChar chr = itemText.hasFlag(b, ScLayout_SoftHyphenVisible) ?
QChar('-') : itemText.text(b);
QChar chr = runs[b].hasFlag(ScLayout_SoftHyphenVisible) ?
QChar('-') : itemText.text(runs[b].firstChar());
double rightCorr = chStyle.font().realCharWidth(chr, chs / 10.0);
if (QString("-,.`´'~").indexOf(chr) >= 0
|| chr == QChar(0x2018)
1309,6 → 1226,154
}
}
 
QList<GlyphRun> PageItem_TextFrame::shapeText()
{
// maps expanded characters to itemText tokens.
QMap<int, int> textMap;
QString text;
for (int i = firstInFrame(); i < itemText.length(); ++i)
{
Mark* mark = itemText.mark(i);
if (itemText.hasMark(i))
{
mark->OwnPage = OwnPage;
//itemPtr and itemName set to this frame only if mark type is different than MARK2ItemType
if (!mark->isType(MARK2ItemType))
{
mark->setItemPtr(this);
mark->setItemName(itemName());
}
 
//anchors and indexes has no visible inserts in text
if (mark->isType(MARKAnchorType) || mark->isType(MARKIndexType))
continue;
 
//set note marker charstyle
if (mark->isNoteType())
{
TextNote* note = mark->getNotePtr();
if (note == NULL)
continue;
mark->setItemPtr(this);
NotesStyle* nStyle = note->notesStyle();
Q_ASSERT(nStyle != NULL);
QString chsName = nStyle->marksChStyle();
CharStyle currStyle(itemText.charStyle(i));
if (!chsName.isEmpty())
{
CharStyle marksStyle(m_Doc->charStyle(chsName));
if (!currStyle.equiv(marksStyle))
{
currStyle.setParent(chsName);
itemText.applyCharStyle(i, 1, currStyle);
}
}
 
StyleFlag s(itemText.charStyle(i).effects());
if (mark->isType(MARKNoteMasterType))
{
if (nStyle->isSuperscriptInMaster())
s |= ScStyle_Superscript;
else
s &= ~ScStyle_Superscript;
}
else
{
if (nStyle->isSuperscriptInNote())
s |= ScStyle_Superscript;
else
s &= ~ScStyle_Superscript;
}
if (s != itemText.charStyle(i).effects())
{
CharStyle haveSuperscript;
haveSuperscript.setFeatures(s.featureList());
itemText.applyCharStyle(i, 1, haveSuperscript);
}
}
}
 
bool bullet = false;
if (i == 0 || itemText.text(i - 1) == SpecialChars::PARSEP)
{
ParagraphStyle style = itemText.paragraphStyle(i);
if (style.hasBullet() || style.hasNum())
{
bullet = true;
if (mark == NULL || !mark->isType(MARKBullNumType))
{
itemText.insertMark(new BulNumMark(), i);
i--;
continue;
}
if (style.hasBullet())
mark->setString(style.bulletStr());
else if (style.hasNum() && mark->getString().isEmpty())
{
mark->setString("?");
m_Doc->flag_Renumber = true;
}
}
}
 
if (!bullet && mark && mark->isType(MARKBullNumType))
{
itemText.removeChars(i, 1);
i--;
continue;
}
 
QString str = ExpandToken(i);
if (str.isEmpty())
str = SpecialChars::ZWNBSPACE;
 
for (int j = 0; j < str.length(); j++)
textMap.insert(text.length() + j, i);
 
text.append(str);
}
 
QList<GlyphRun> glyphRuns;
glyphRuns.reserve(text.length());
for (int i = 0; i < text.length(); i++)
{
const QChar ch(text.at(i));
int a = textMap.value(i);
 
GlyphRun run(&itemText.charStyle(a), itemText.flags(a), a, a, itemText.object(a));
if (SpecialChars::isExpandingSpace(ch))
run.setFlag(ScLayout_ExpandingSpace);
 
GlyphLayout gl = layoutGlyphs(run.style(), QString(ch), itemText.flags(a));
 
if (!glyphRuns.isEmpty())
{
GlyphLayout& last = glyphRuns.last().glyphs().last();
last.xadvance += run.style().font().glyphKerning(last.glyph, gl.glyph, run.style().fontSize() / 10) * last.scaleH;
}
 
//show control characters for marks
if (itemText.hasMark(a))
{
GlyphLayout control;
control.glyph = SpecialChars::OBJECT.unicode() + ScFace::CONTROL_GLYPHS;
run.glyphs().append(control);
}
 
if (SpecialChars::isExpandingSpace(ch))
gl.xadvance *= run.style().wordTracking();
 
if (itemText.hasObject(a))
gl.xadvance = itemText.object(a)->width() + itemText.object(a)->lineWidth();
 
run.glyphs().append(gl);
 
glyphRuns.append(run);
}
 
return glyphRuns;
}
 
void PageItem_TextFrame::layout()
{
// qDebug()<<"==Layout==" << itemName() ;
1342,10 → 1407,7
QPoint pt1, pt2;
QRect pt;
double chs, chsd = 0;
double EndX, OFs, wide, kernVal;
QString chstr;
QChar currentCh;
GlyphLayout* glyphs;
double EndX, OFs;
ParagraphStyle style;
int opticalMargins = ParagraphStyle::OM_None;
 
1356,7 → 1418,7
TabControl tabs;
tabs.active = false; // RTab
tabs.status = TabNONE; // TabCode
tabs.charIndex = -1; // StartRT
tabs.tabGlyph = 0; // was int charIndex ~ StartRT
tabs.xPos = 0; // RTabX
 
QList<ParagraphStyle::TabRecord> tTabValues;
1378,14 → 1440,6
if (lineColor() != CommonStrings::None)
lineCorr = m_lineWidth / 2.0;
 
// TODO: refactor this into PageItem
MarginStruct savedTextDistanceMargins(m_textDistanceMargins);
 
LineControl current;
current.init(m_width, m_height, m_textDistanceMargins, lineCorr);
current.initColumns(columnWidth(), ColGap);
current.hyphenCount = 0;
 
//hold Y position of last computed line of text (with glyphs descent)
//for moving next line if glyphs are higher than that
double lastLineY = 0;
1456,7 → 1510,11
m_availableRegion = matrix.map(m_availableRegion);
}
 
current.nextColumn();
QList<GlyphRun> glyphRuns = shapeText();
 
LineControl current(m_width, m_height, m_textDistanceMargins, lineCorr, m_Doc, glyphRuns, columnWidth(), ColGap);
current.nextColumn(textLayout);
 
lastLineY = m_textDistanceMargins.top();
 
//automatic line spacing factor (calculated once)
1486,13 → 1544,13
desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0);
current.yPos = itemText.defaultStyle().lineSpacing() + m_textDistanceMargins.top() + lineCorr - desc;
}
current.startLine(firstInFrame());
current.startLine(0);
 
outs = false;
OFs = 0;
MaxChars = 0;
double realEnd = 0;
current.restartIndex = current.restartRowIndex = firstInFrame();
current.restartIndex = current.restartRowIndex = 0;
current.afterOverflow = false;
current.addLine = false;
current.recalculateY = true;
1513,81 → 1571,35
int regionMinY = 0, regionMaxY= 0;
 
double autoLeftIndent = 0.0;
for (int i = 0; i < glyphRuns.length(); ++i)
{
if (glyphRuns[i].glyphs().isEmpty())
continue;
 
for (int a = firstInFrame(); a < itLen; ++a)
{
currentCh = itemText.text(a);
glyphs = itemText.getGlyphs(a);
int a = glyphRuns[i].firstChar();
bool HasObject = itemText.hasObject(a);
PageItem* currentObject = HasObject? itemText.object(a): NULL;
PageItem* currentObject = itemText.object(a);
bool HasMark = itemText.hasMark(a);
Mark* mark = itemText.mark(a);
 
if (itemText.charStyle(a).effects() & ScStyle_UnderlineWords)
{
CharStyle tmp(itemText.charStyle(a));
StyleFlag effects = tmp.effects();
if (!itemText.text(a).isSpace())
effects |= ScStyle_Underline;
effects &= ~ScStyle_UnderlineWords;
tmp.setFeatures(effects.featureList());
itemText.applyCharStyle(a, 1, tmp);
}
 
if (HasMark)
{
//show control characters for marks
glyphs->glyph = SpecialChars::OBJECT.unicode() + ScFace::CONTROL_GLYPHS;
 
mark->OwnPage = OwnPage;
//itemPtr and itemName set to this frame only if mark type is different than MARK2ItemType
if (!mark->isType(MARK2ItemType))
{
mark->setItemPtr(this);
mark->setItemName(itemName());
}
//anchors and indexes has no visible inserts in text
if (mark->isType(MARKAnchorType) || mark->isType(MARKIndexType))
{
glyphs->shrink();
continue;
}
Mark* mark = itemText.mark(a);
//store mark pointer and position in text
if (mark->isType(MARKNoteMasterType))
noteMarksPosMap.insert(a, mark);
//set note marker charstyle
if (mark->isNoteType())
{
TextNote* note = mark->getNotePtr();
if (note == NULL)
continue;
mark->setItemPtr(this);
NotesStyle* nStyle = note->notesStyle();
Q_ASSERT(nStyle != NULL);
QString chsName = nStyle->marksChStyle();
CharStyle currStyle(itemText.charStyle(a));
if (!chsName.isEmpty())
{
CharStyle marksStyle(m_Doc->charStyle(chsName));
if (!currStyle.equiv(marksStyle))
{
currStyle.setParent(chsName);
itemText.applyCharStyle(a, 1, currStyle);
}
}
}
 
StyleFlag s(itemText.charStyle(a).effects());
if (mark->isType(MARKNoteMasterType))
{
if (nStyle->isSuperscriptInMaster())
s |= ScStyle_Superscript;
else
s &= ~ScStyle_Superscript;
}
else
{
if (nStyle->isSuperscriptInNote())
s |= ScStyle_Superscript;
else
s &= ~ScStyle_Superscript;
}
if (s != itemText.charStyle(a).effects())
{
CharStyle haveSuperscript;
haveSuperscript.setFeatures(s.featureList());
itemText.applyCharStyle(a, 1, haveSuperscript);
}
}
}
BulNumMode = false;
if (a==0 || itemText.text(a-1) == SpecialChars::PARSEP)
{
1596,37 → 1608,13
if (style.hasBullet() || style.hasNum())
{
BulNumMode = true;
if (mark == NULL || !mark->isType(MARKBullNumType))
{
BulNumMark* bnMark = new BulNumMark();
itemText.insertMark(bnMark,a);
a--;
itLen = itemText.length();
continue;
}
if (style.hasBullet())
mark->setString(style.bulletStr());
else if (style.hasNum())
{
if (mark->getString().isEmpty())
{
mark->setString("?");
m_Doc->flag_Renumber = true;
}
}
}
}
if (!BulNumMode && mark && mark->isType(MARKBullNumType))
{
itemText.removeChars(a,1);
a--;
itLen = itemText.length();
continue;
}
if (current.itemsInLine == 0)
 
if (current.isEmpty)
opticalMargins = style.opticalMargins();
//-->#13490
if (isNoteFrame() && !mark)
if (isNoteFrame() && !HasMark)
{
StyleFlag s(itemText.charStyle(a).effects());
s &= ~ScStyle_Superscript;
1636,12 → 1624,8
}
//--<#13490
CharStyle charStyle = ((itemText.text(a) != SpecialChars::PARSEP) ? itemText.charStyle(a) : style.charStyle());
chstr = ExpandToken(a);
int chstrLen = chstr.length();
if (chstr.isEmpty())
chstr = SpecialChars::ZWNBSPACE;
 
curStat = SpecialChars::getCJKAttr(currentCh);
curStat = SpecialChars::getCJKAttr(itemText.text(a));
//set style for paragraph effects
if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP)
{
1678,7 → 1662,7
{
if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP)
{
if (currentCh != SpecialChars::PARSEP)
if (itemText.text(a) != SpecialChars::PARSEP)
{
DropCmode = style.hasDropCap();
if (DropCmode)
1692,20 → 1676,20
 
const ScFace font = charStyle.font();
 
itemText.clearFlag(a, ScLayout_DropCap);
itemText.clearFlag(a, ScLayout_SoftHyphenVisible);
glyphRuns[i].clearFlag(ScLayout_DropCap);
glyphRuns[i].clearFlag(ScLayout_SoftHyphenVisible);
 
// No space at begin of line,
if (legacy)
{
// unless at begin of par (eeks)
if ( (current.itemsInLine == 0) && (SpecialChars::isBreakingSpace(currentCh))
if ( (current.isEmpty) && (SpecialChars::isBreakingSpace(itemText.text(a)))
&& (a > 0 && ! SpecialChars::isBreak(itemText.text(a-1)))
&& ! (a > 0 && SpecialChars::isBreakingSpace(itemText.text(a-1))
&& (!itemText.hasFlag(a-1, ScLayout_SuppressSpace))))
&& (!glyphRuns[i - 1].hasFlag(ScLayout_SuppressSpace))))
{
itemText.setFlag(a, ScLayout_SuppressSpace);
glyphs->xadvance = 0;
glyphRuns[i].setFlag(ScLayout_SuppressSpace);
glyphRuns[i].glyphs().first().xadvance = 0;
continue;
}
else
1713,16 → 1697,16
}
else // from 134 on use NBSPACE for this effect
{
if ( current.itemsInLine == 0 && (SpecialChars::isBreakingSpace(currentCh) || currentCh.isSpace()))
if ( current.isEmpty && (SpecialChars::isBreakingSpace(itemText.text(a)) || itemText.text(a).isSpace()))
{
itemText.setFlag(a, ScLayout_SuppressSpace);
glyphs->xadvance = 0;
glyphRuns[i].setFlag(ScLayout_SuppressSpace);
glyphRuns[i].glyphs()[0].xadvance = 0;
continue;
}
else
itemText.clearFlag(a, ScLayout_SuppressSpace);
}
if (current.itemsInLine == 0)
if (current.isEmpty)
{
if (style.rightMargin() == 0)
{
1745,7 → 1729,7
if (!current.afterOverflow && current.recalculateY && !current.startOfCol)
current.yPos += style.gapBefore();
DropCapDrop = 0;
if (chstr[0] != SpecialChars::PARSEP)
if (itemText.text(a) != SpecialChars::PARSEP)
DropCmode = style.hasDropCap();
else
DropCmode = false;
1770,10 → 1754,10
//text height, width, ascent and descent should be calculated for whole text provided by ScText in current position
//and that may be more than one char (variable text for example)
double realCharHeight = 0.0, realCharAscent = 0.0;
for (int i = 0; i < chstrLen; ++i)
{
realCharHeight = qMax(realCharHeight, font.realCharHeight(chstr[i], 1));
realCharAscent = qMax(realCharAscent, font.realCharAscent(chstr[i], 1));
foreach (GlyphLayout gl, glyphRuns[i].glyphs()) {
GlyphMetrics gm = font.glyphBBox(gl.glyph);
realCharHeight = qMax(realCharHeight, gm.ascent + gm.descent);
realCharAscent = qMax(realCharAscent, gm.ascent);
}
double fontAscent = font.ascent(style.charStyle().fontSize() / 10.0);
if (realCharHeight == 0.0)
1782,8 → 1766,8
realCharAscent = fontAscent;
chsd = (10 * ((DropCapDrop + fontAscent) / realCharHeight));
chs = (10 * ((DropCapDrop + fontAscent) / realCharAscent));
itemText.setFlag(a, ScLayout_DropCap);
glyphs->yoffset -= DropCapDrop;
glyphRuns[i].setFlag(ScLayout_DropCap);
glyphRuns[i].glyphs().first().yoffset += DropCapDrop;
if (HasObject)
{
chs = qRound((currentObject->height() + currentObject->lineWidth()) * 10);
1797,113 → 1781,92
else
chs = charStyle.fontSize();
}
// set StartOfLine (and find tracking?)
if (current.itemsInLine == 0)
// set StartOfLine
if (current.isEmpty)
{
itemText.setFlag(a, ScLayout_StartOfLine);
kernVal = 0;
glyphRuns[i].setFlag(ScLayout_StartOfLine);
}
else
{
kernVal = 0; // chs * charStyle.tracking() / 10000.0;
itemText.clearFlag(a, ScLayout_StartOfLine);
glyphRuns[i].clearFlag(ScLayout_StartOfLine);
}
glyphs->yadvance = 0;
layoutGlyphs(charStyle, chstr, itemText.flags(a), *glyphs);
// glyphs->yadvance = 0;
 
// find out width, ascent and descent of char
if (HasObject)
GlyphLayout& firstGlyph = glyphRuns[i].glyphs().first();
GlyphLayout& lastGlyph = glyphRuns[i].glyphs().last();
 
// apply cjk kerning
//TODO: cjk spacing and kerning should be done in layoutGlyphs!
if (i + 1 < glyphRuns.length())
{
wide = currentObject->width() + currentObject->lineWidth();
glyphs->xadvance = wide * glyphs->scaleH;
}
else
{
wide = glyphs->wide();
// apply kerning
if (a+1 < itemText.length())
{
uint glyph2 = font.char2CMap(itemText.text(a+1));
double kern = font.glyphKerning(glyphs->last()->glyph, glyph2, chs / 10.0) * glyphs->scaleH;
wide += kern;
glyphs->last()->xadvance += kern;
// change xadvance, xoffset according to JIS X4051
int nextStat = SpecialChars::getCJKAttr(itemText.text(a+1));
int prevStat;
if (curStat != 0)
{ // current char is CJK
if (nextStat == 0 && !SpecialChars::isBreakingSpace(itemText.text(a+1))){
switch(curStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_KANJI:
case SpecialChars::CJK_KANA:
case SpecialChars::CJK_NOTOP:
kern = charStyle.fontSize() / 10 / 4;
wide += kern;
glyphs->last()->xadvance += kern;
}
} else { // next char is CJK, too
switch(curStat & SpecialChars::CJK_CHAR_MASK){
GlyphRun nextRun = glyphRuns[i + 1];
// change xadvance, xoffset according to JIS X4051
int nextStat = SpecialChars::getCJKAttr(itemText.text(nextRun.firstChar()));
if (curStat != 0)
{ // current char is CJK
if (nextStat == 0 && !SpecialChars::isBreakingSpace(itemText.text(nextRun.firstChar()))){
switch(curStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_KANJI:
case SpecialChars::CJK_KANA:
case SpecialChars::CJK_NOTOP:
lastGlyph.xadvance += charStyle.fontSize() / 10 / 4;
}
} else { // next char is CJK, too
switch(curStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_FENCE_END:
switch(nextStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_FENCE_BEGIN:
case SpecialChars::CJK_FENCE_END:
switch(nextStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_FENCE_BEGIN:
case SpecialChars::CJK_FENCE_END:
case SpecialChars::CJK_COMMA:
case SpecialChars::CJK_PERIOD:
case SpecialChars::CJK_MIDPOINT:
kern = -charStyle.fontSize() / 10 / 2;
wide += kern;
glyphs->last()->xadvance += kern;
}
break;
case SpecialChars::CJK_COMMA:
case SpecialChars::CJK_PERIOD:
switch(nextStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_FENCE_BEGIN:
case SpecialChars::CJK_FENCE_END:
kern = -charStyle.fontSize() / 10 / 2;
wide += kern;
glyphs->last()->xadvance += kern;
}
break;
case SpecialChars::CJK_MIDPOINT:
switch(nextStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_FENCE_BEGIN:
kern = -charStyle.fontSize() / 10 / 2;
wide += kern;
glyphs->last()->xadvance += kern;
}
break;
lastGlyph.xadvance -= charStyle.fontSize() / 10 / 2;
}
break;
case SpecialChars::CJK_COMMA:
case SpecialChars::CJK_PERIOD:
switch(nextStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_FENCE_BEGIN:
if (a == current.line.firstItem){ // first char of the line
prevStat = SpecialChars::CJK_FENCE_BEGIN;
} else {
prevStat = SpecialChars::getCJKAttr(itemText.text(a-1)) & SpecialChars::CJK_CHAR_MASK;
}
if (prevStat == SpecialChars::CJK_FENCE_BEGIN){
kern = -charStyle.fontSize() / 10 / 2;
wide += kern;
glyphs->last()->xadvance += kern;
glyphs->last()->xoffset += kern;
}
break;
case SpecialChars::CJK_FENCE_END:
lastGlyph.xadvance -= charStyle.fontSize() / 10 / 2;;
}
 
}
} else { // current char is not CJK
if (nextStat != 0 && !SpecialChars::isBreakingSpace(currentCh)){
break;
case SpecialChars::CJK_MIDPOINT:
switch(nextStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_KANJI:
case SpecialChars::CJK_KANA:
case SpecialChars::CJK_NOTOP:
// use the size of the current char instead of the next one
kern = charStyle.fontSize() / 10 / 4;
wide += kern;
glyphs->last()->xadvance += kern;
case SpecialChars::CJK_FENCE_BEGIN:
lastGlyph.xadvance -= charStyle.fontSize() / 10 / 2;
}
break;
case SpecialChars::CJK_FENCE_BEGIN:
int prevStat = 0;
if (i == current.line.firstRun){ // first char of the line
prevStat = SpecialChars::CJK_FENCE_BEGIN;
} else if (i != 0) {
prevStat = SpecialChars::getCJKAttr(itemText.text(glyphRuns[i - 1].lastChar())) & SpecialChars::CJK_CHAR_MASK;
}
if (prevStat == SpecialChars::CJK_FENCE_BEGIN){
lastGlyph.xadvance -= charStyle.fontSize() / 10 / 2;
lastGlyph.xoffset -= charStyle.fontSize() / 10 / 2;
}
break;
}
}
} else { // current char is not CJK
if (nextStat != 0 && !SpecialChars::isBreakingSpace(itemText.text(glyphRuns[i].lastChar()))){
switch(nextStat & SpecialChars::CJK_CHAR_MASK){
case SpecialChars::CJK_KANJI:
case SpecialChars::CJK_KANA:
case SpecialChars::CJK_NOTOP:
// use the size of the current char instead of the next one
lastGlyph.xadvance += charStyle.fontSize() / 10 / 4;
}
}
}
}
 
// find out width, ascent and descent of char
double wide = glyphRuns[i].width();
 
if (DropCmode)
{
// drop caps are wider...
1912,22 → 1875,23
double itemHeight = currentObject->height() + currentObject->lineWidth();
if (itemHeight == 0)
itemHeight = font.height(style.charStyle().fontSize() / 10.0);
wide = currentObject->width() + currentObject->lineWidth();
asce = currentObject->height() + currentObject->lineWidth();
realAsce = calculateLineSpacing (style, this) * DropLines;
glyphs->scaleH /= glyphs->scaleV;
glyphs->scaleV = (realAsce / itemHeight);
glyphs->scaleH *= glyphs->scaleV;
firstGlyph.scaleH /= firstGlyph.scaleV;
firstGlyph.scaleV = (realAsce / itemHeight);
firstGlyph.scaleH *= firstGlyph.scaleV;
}
else
{
double realCharHeight = 0.0;
wide = 0.0; realAsce = 0.0;
for (int i = 0; i < chstrLen; ++i)
{
realCharHeight = qMax(realCharHeight, font.realCharHeight(chstr[i], charStyle.fontSize() / 10.0));
realAsce = qMax(realAsce, font.realCharHeight(chstr[i], chsd / 10.0));
wide += font.realCharWidth(chstr[i], chsd / 10.0);
foreach (GlyphLayout gl, glyphRuns[i].glyphs()) {
GlyphMetrics gm;
gm = font.glyphBBox(gl.glyph, charStyle.fontSize() / 10.0);
realCharHeight = qMax(realCharHeight, gm.ascent + gm.descent);
gm = font.glyphBBox(gl.glyph, chsd / 10.0);
realAsce = qMax(realAsce, gm.ascent + gm.descent);
wide += gm.width;
}
wide = (wide* scaleH) + (1 - scaleH);
realAsce = realAsce * scaleV + offset;
1935,37 → 1899,33
realCharHeight = font.height(style.charStyle().fontSize() / 10.0);
asce = font.ascent(hlcsize10);
// qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]);
glyphs->scaleH /= glyphs->scaleV;
glyphs->scaleV = (realAsce / realCharHeight);
glyphs->scaleH *= glyphs->scaleV;
glyphs->xoffset -= 0.5; //drop caps are always to far from column left edge
firstGlyph.scaleH /= firstGlyph.scaleV;
firstGlyph.scaleV = (realAsce / realCharHeight);
firstGlyph.scaleH *= firstGlyph.scaleV;
firstGlyph.xoffset -= 0.5; //drop caps are always to far from column left edge
}
glyphs->xadvance = wide;
firstGlyph.xadvance = wide / firstGlyph.scaleH;
desc = realDesc = 0;
}
else // !DropCMode
{
if (SpecialChars::isExpandingSpace(currentCh))
{
double wordtracking = charStyle.wordTracking();
glyphs->xadvance *= wordtracking;
wide *= wordtracking;
}
// find ascent / descent
if (HasObject)
desc = realDesc = 0;
else
{
for (int i = 0; i < chstrLen; ++i)
if (itemText.text(a) != SpecialChars::OBJECT)
{
if (chstr[i] == SpecialChars::OBJECT)
continue;
realDesc = qMax(realDesc, font.realCharDescent(chstr[i], hlcsize10));
realAsce = font.realCharAscent(chstr[i], hlcsize10);
foreach (GlyphLayout gl, glyphRuns[i].glyphs()) {
GlyphMetrics gm = font.glyphBBox(gl.glyph, hlcsize10);
realDesc = qMax(realDesc, gm.descent);
realAsce = gm.ascent;
}
}
 
realDesc = realDesc * scaleV - offset;
desc = -font.descent(hlcsize10);
current.rememberShrinkStretch(currentCh, wide, style);
current.rememberShrinkStretch(itemText.text(a), wide, style);
}
if (HasObject)
{
1979,8 → 1939,8
realAsce = asce * scaleV + offset;
else
{
for (int i = 0; i < chstrLen; ++i)
realAsce = qMax(realAsce, font.realCharAscent(chstr[i], hlcsize10) * scaleV + offset);
foreach (GlyphLayout gl, glyphRuns[i].glyphs())
realAsce = qMax(realAsce, font.glyphBBox(gl.glyph, hlcsize10).ascent * scaleV + offset);
}
}
}
1987,7 → 1947,7
// if (BulNumMode)
// hl->glyph.last()->xadvance += style.parEffectOffset();
//check for Y position at beginning of line
if (current.itemsInLine == 0 && !current.afterOverflow)
if (current.isEmpty && !current.afterOverflow)
{
if (current.recalculateY)
{
1996,7 → 1956,7
{
lastLineY = qMax(lastLineY, m_textDistanceMargins.top() + lineCorr);
//fix for proper rendering first empty line (only with PARSEP)
if (chstr[0] == SpecialChars::PARSEP)
if (itemText.text(a) == SpecialChars::PARSEP)
current.yPos += style.lineSpacing();
if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing || FlopBaseline)
{
2101,7 → 2061,7
regionMaxY = static_cast<int>(floor(current.yPos + desc));
}
 
if (current.itemsInLine == 0 && !current.afterOverflow)
if (current.isEmpty && !current.afterOverflow)
{
//start a new line
goNoRoom = false;
2219,12 → 2179,12
}
if (newColumn)
{
current.nextColumn();
current.nextColumn(textLayout);
current.mustLineEnd = current.colRight;
current.restartX = current.xPos;
lastLineY = current.yPos;
current.rowDesc = 0;
a--;
i--;
current.recalculateY = true;
current.addLeftIndent = true;
continue;
2231,13 → 2191,15
}
current.line.x = current.restartX = current.xPos;
current.line.y = current.yPos;
if (glyphRuns[current.line.firstRun].hasFlag(ScLayout_DropCap))
current.line.y -= DropCapDrop;
}
 
//check if line must start at new Y position due to current glyph height or previous line descent
if (!SpecialChars::isBreak(currentCh, true)
&& !SpecialChars::isBreakingSpace(currentCh)
&& !SpecialChars::isExpandingSpace(currentCh)
&& currentCh != SpecialChars::TAB)
if (!SpecialChars::isBreak(itemText.text(a), true)
&& !SpecialChars::isBreakingSpace(itemText.text(a))
&& !SpecialChars::isExpandingSpace(itemText.text(a))
&& itemText.text(a) != SpecialChars::TAB)
{
double diff = 0;
if (current.startOfCol || DropCmode)
2247,7 → 2209,7
if (HasObject)
diff = (currentObject->height() + currentObject->lineWidth()) * scaleV + offset - (current.yPos - lastLineY);
else
diff = font.realCharAscent(QChar('l'), hlcsize10) * scaleV + offset - (current.yPos - lastLineY);
diff = font.capHeight(hlcsize10) * scaleV + offset - (current.yPos - lastLineY);
}
else
{
2290,7 → 2252,7
maxDY = 0;
}
}
a = current.restartRow(false);
i = current.restartRow(false);
continue;
}
}
2297,7 → 2259,7
// right tab stuff
if (tabs.active)
{
if (((currentCh == '.') && (tabs.status == TabPOINT)) || ((currentCh == ',') && (tabs.status == TabCOMMA)) || (currentCh == SpecialChars::TAB))
if (((itemText.text(a) == '.') && (tabs.status == TabPOINT)) || ((itemText.text(a) == ',') && (tabs.status == TabCOMMA)) || (itemText.text(a) == SpecialChars::TAB))
{
tabs.active = false;
tabs.status = TabNONE;
2304,7 → 2266,7
}
}
// tab positioning
if (currentCh == SpecialChars::TAB)
if (itemText.text(a) == SpecialChars::TAB)
{
wide = 1;
if (tabs.active)
2342,23 → 2304,19
}
 
// remember fill char
if (!tabs.fillChar.isNull()) {
glyphs->growWithTabLayout();
TabLayout * tglyph = dynamic_cast<TabLayout*>(glyphs->more);
if (tglyph)
{
tglyph->fillChar = tabs.fillChar;
tglyph->glyph = font.char2CMap(tabs.fillChar);
tglyph->yoffset = glyphs->yoffset;
tglyph->scaleV = tglyph->scaleH = chs / charStyle.fontSize();
tglyph->xadvance = 0;
}
if (!tabs.fillChar.isNull())
{
glyphRuns[i].setFlag(ScLayout_TabLeaders);
GlyphLayout tglyph;
tglyph.glyph = font.char2CMap(tabs.fillChar);
tglyph.yoffset = firstGlyph.yoffset;
tglyph.scaleV = tglyph.scaleH = chs / charStyle.fontSize();
tglyph.xadvance = 0;
glyphRuns[i].glyphs().append(tglyph);
}
}
current.xPos -= (legacy ? 1.0 : 0.0);
glyphs->xadvance = current.xPos + wide + kernVal - tabs.xPos;
// wide = current.xPos - RTabX;
tabs.charIndex = a;
firstGlyph.xadvance = current.xPos + wide - tabs.xPos;
tabs.tabGlyph = &firstGlyph;
}
}
 
2366,9 → 2324,9
if (DropCmode)
{
double yoffset = 0.0;
for (int i = 0; i < chstrLen; ++i)
yoffset = qMax(yoffset, font.realCharHeight(chstr[i], chsd / 10.0) - font.realCharAscent(chstr[i], chsd / 10.0));
glyphs->yoffset -= yoffset;
foreach (GlyphLayout gl, glyphRuns[i].glyphs())
yoffset = qMax(yoffset, font.glyphBBox(gl.glyph, chsd / 10.0).descent);
firstGlyph.yoffset -= yoffset;
}
// remember x pos
double breakPos = current.xPos;
2375,11 → 2333,11
 
if (!tabs.active) // normal case
{
current.xPos += wide+kernVal;
current.xPos += wide;
}
else if (tabs.active && tabs.status == TabCENTER) // center tab
{
current.xPos += (wide+kernVal) / 2;
current.xPos += wide / 2;
current.xPos = qMax(current.xPos, current.colLeft);
}
else // other tabs.active
2387,17 → 2345,17
current.xPos = qMax(current.xPos, current.colLeft);
}
// remember possible break
if ( (SpecialChars::isBreakingSpace(currentCh) || currentCh == SpecialChars::TAB))
if ( (SpecialChars::isBreakingSpace(itemText.text(a)) || itemText.text(a) == SpecialChars::TAB))
{
if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) )
{
current.rememberBreak(a, breakPos, style.rightMargin());
current.rememberBreak(i, breakPos, style.rightMargin());
}
}
if (HasObject)
current.rememberBreak(a, breakPos, style.rightMargin());
current.rememberBreak(i, breakPos, style.rightMargin());
// CJK break
if (a > current.line.firstItem)
if (i > current.line.firstRun)
{ // not the first char
if ((lastStat == 0) && (curStat == 0))
{ // both non-CJK
2406,7 → 2364,7
// non-CJK char does not have CJK_NOBREAK_AFTER/CJK_NOBREAK_BEFORE
if ((lastStat & SpecialChars::CJK_NOBREAK_AFTER) == 0 &&
(curStat & SpecialChars::CJK_NOBREAK_BEFORE) == 0){
current.rememberBreak(a-1, breakPos, style.rightMargin());
current.rememberBreak(i-1, breakPos, style.rightMargin());
}
}
 
2423,17 → 2381,18
double overflowWidth = 0.0;
double hyphWidth = 0.0;
bool inOverflow = false;
if (itemText.hasFlag(a,ScLayout_HyphenationPossible) || currentCh == SpecialChars::SHYPHEN)
if (glyphRuns[i].hasFlag(ScLayout_HyphenationPossible) || itemText.text(a) == SpecialChars::SHYPHEN)
hyphWidth = font.charWidth('-', hlcsize10) * (charStyle.scaleH() / 1000.0);
if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(currentCh, Cols > 1) || (current.xPos - current.maxShrink + hyphWidth) >= current.mustLineEnd)
if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(itemText.text(a), Cols > 1) || (current.xPos - current.maxShrink + hyphWidth) >= current.mustLineEnd)
{
 
//end of row reached - right column, end of column, break char or line must end
if (current.itemsInLine == 0 && !current.afterOverflow && !SpecialChars::isBreak(currentCh, Cols > 1))
if (current.isEmpty && !current.afterOverflow && !SpecialChars::isBreak(itemText.text(a), Cols > 1))
{
//no glyphs in line, so start new row
if (SpecialChars::isBreak(currentCh, Cols > 1))
current.restartRowIndex = a +1;
a = current.restartRow(true);
if (SpecialChars::isBreak(itemText.text(a), Cols > 1))
current.restartRowIndex = i + 1;
i = current.restartRow(true);
inOverflow = false;
outs = false;
continue;
2442,13 → 2401,14
if (current.breakIndex < 0)
{
//force break
if (!SpecialChars::isBreak(currentCh, Cols > 1))
if (!SpecialChars::isBreak(itemText.text(a), Cols > 1))
{
//force line end at previouse glyph
a--;
i--;
a = glyphRuns[i].firstChar();
current.mustLineEnd = current.line.x;
}
current.breakLine(itemText, style, firstLineOffset(),a);
current.breakLine(style, firstLineOffset(), i);
}
if (!current.addLine && !current.lastInRowLine && current.afterOverflow)
{
2457,7 → 2417,7
//if we have some text here - insert text WITHOUT right margin
//if there is no place for text - insert text WITH right margin and end line
current.lastInRowLine = false;
if (current.line.firstItem == current.restartIndex)
if (current.line.firstRun == current.restartIndex)
current.lastInRowLine = true;
if (current.hasDropCap && DropLinesCount == 0 && current.restartIndex == current.restartRowIndex)
{
2465,12 → 2425,13
maxDX = 0;
current.yPos = maxDY;
}
a = current.restartLine(false,true);
i = current.restartLine(false,true);
outs = false;
inOverflow = false;
continue;
}
outs = true;
 
current.addLine = true;
current.lastInRowLine = true;
current.rightMargin = style.rightMargin();
2480,7 → 2441,7
else
{
int charStart, charEnd;
if (current.itemsInLine == 0)
if (current.isEmpty)
{
charStart = static_cast<int>(floor(current.line.x));
charEnd = static_cast<int>(ceil(current.xPos));
2491,10 → 2452,10
charEnd = static_cast<int>(ceil(current.xPos - current.maxShrink));
}
if (legacy &&
(((currentCh == '-' || itemText.hasFlag(a, ScLayout_HyphenationPossible)) && (current.hyphenCount < m_Doc->hyphConsecutiveLines() || m_Doc->hyphConsecutiveLines() == 0))
|| currentCh == SpecialChars::SHYPHEN))
(((itemText.text(a) == '-' || glyphRuns[i].hasFlag(ScLayout_HyphenationPossible)) && (current.hyphenCount < m_Doc->hyphConsecutiveLines() || m_Doc->hyphConsecutiveLines() == 0))
|| itemText.text(a) == SpecialChars::SHYPHEN))
{
if (itemText.hasFlag(a, ScLayout_HyphenationPossible) || currentCh == SpecialChars::SHYPHEN)
if (glyphRuns[i].hasFlag(ScLayout_HyphenationPossible) || itemText.text(a) == SpecialChars::SHYPHEN)
{
pt1 = QPoint(charStart, regionMinY);
pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), regionMaxY -1);
2505,7 → 2466,7
pt2 = QPoint(charEnd, regionMaxY -1);
}
}
else if (!legacy && SpecialChars::isBreakingSpace(currentCh))
else if (!legacy && SpecialChars::isBreakingSpace(itemText.text(a)))
{
pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), regionMinY);
pt2 = QPoint(charEnd, regionMaxY -1);
2536,11 → 2497,11
}
if (outs)
{
if (current.itemsInLine == 0)
if (current.isEmpty)
{
current.line.x = current.xPos = realEnd;
a--;
current.startLine(a+1);
i--;
current.startLine(i+1);
if (!current.wasFirstInRow)
current.addLeftIndent = true;
if (current.hasDropCap && DropLinesCount == 0 && !current.afterOverflow)
2554,8 → 2515,9
}
if (current.breakIndex < 0)
{
a--;
current.breakLine(itemText, style, firstLineOffset(), a);
i--;
a = glyphRuns[i].firstChar();
current.breakLine(style, firstLineOffset(), i);
}
//check if after overflow text can be placed
overflowWidth = realEnd - (current.xPos - current.maxShrink);
2577,7 → 2539,7
current.lastInRowLine = true;
current.mustLineEnd = current.line.x;
}
else if (current.line.firstItem == current.restartIndex)
else if (current.line.firstRun == current.restartIndex)
current.lastInRowLine = true;
}
else
2587,7 → 2549,7
current.hasDropCap = false;
maxDX = 0;
}
a = current.restartLine(false, true);
i = current.restartLine(false, true);
inOverflow = false;
outs = false;
continue;
2604,13 → 2566,13
}
 
// hyphenation
if ((itemText.hasFlag(a, ScLayout_HyphenationPossible)
|| currentCh == '-'
|| currentCh == SpecialChars::SHYPHEN)
&& (!outs) && !itemText.text(a-1).isSpace() )
if ((glyphRuns[i].hasFlag(ScLayout_HyphenationPossible)
|| itemText.text(a) == '-'
|| itemText.text(a) == SpecialChars::SHYPHEN)
&& (!outs) && !itemText.text(glyphRuns[i - 1].lastChar()).isSpace() )
{
breakPos = current.xPos;
if (currentCh != '-')
if (itemText.text(a) != '-')
{
breakPos += hyphWidth;
}
2622,22 → 2584,22
 
if (legacy || (breakPos - rightHang < current.colRight - style.rightMargin()))
{
if ((current.hyphenCount < m_Doc->hyphConsecutiveLines()) || (m_Doc->hyphConsecutiveLines() == 0) || currentCh == SpecialChars::SHYPHEN)
if ((current.hyphenCount < m_Doc->hyphConsecutiveLines()) || (m_Doc->hyphConsecutiveLines() == 0) || itemText.text(a) == SpecialChars::SHYPHEN)
{
current.rememberBreak(a, breakPos, style.rightMargin() + hyphWidth);
current.rememberBreak(i, breakPos, style.rightMargin() + hyphWidth);
}
}
}
 
if ((currentCh == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1))
if ((itemText.text(a) == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1))
goNoRoom = true;
if ((currentCh == SpecialChars::COLBREAK) && (Cols > 1))
if ((itemText.text(a) == SpecialChars::COLBREAK) && (Cols > 1))
goNextColumn = true;
 
if (a != firstInFrame() && implicitBreak(itemText.text(a - 1), itemText.text(a)))
current.rememberBreak(a - 1, breakPos);
current.rememberBreak(i -1, breakPos);
 
++current.itemsInLine;
current.isEmpty = (i - current.line.firstRun + 1) == 0;
 
if (tabs.active)
{
2645,10 → 2607,10
if (tabs.status == TabCENTER)
cen = 2;
 
double newTabAdvance = itemText.getGlyphs(tabs.charIndex)->xadvance - (wide+kernVal) / cen;
double newTabAdvance = tabs.tabGlyph->xadvance - wide / cen;
 
if (newTabAdvance >= 0) {
itemText.getGlyphs(tabs.charIndex)->xadvance = newTabAdvance;
tabs.tabGlyph->xadvance = newTabAdvance;
}
else {
tabs.active = false;
2658,7 → 2620,7
if ((DropCmode || BulNumMode) && !outs)
{
current.xPos += style.parEffectOffset();
glyphs->last()->xadvance += style.parEffectOffset();
lastGlyph.xadvance += style.parEffectOffset();
if (DropCmode)
{
DropCmode = false;
2678,10 → 2640,10
{
tabs.active = false;
tabs.status = TabNONE;
if (SpecialChars::isBreak(currentCh, Cols > 1))
if (SpecialChars::isBreak(itemText.text(a), Cols > 1))
{
// find end of line
current.breakLine(itemText, style, firstLineOffset(), a);
current.breakLine(style, firstLineOffset(), i);
EndX = current.endOfLine(m_availableRegion, style.rightMargin(), regionMinY, regionMaxY);
current.finishLine(EndX);
//addLine = true;
2688,7 → 2650,7
assert(current.addLine);
//current.startOfCol = false;
//addLeftIndent = true;
if (currentCh == SpecialChars::PARSEP)
if (itemText.text(a) == SpecialChars::PARSEP)
{
maxDX = 0;
if (current.hasDropCap)
2702,7 → 2664,7
// if (style.alignment() != 0)
{
if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
current.line.width += opticalRightMargin(itemText, current.line);
current.line.width += opticalRightMargin(itemText, glyphRuns, current.line);
 
OFs = 0;
if (style.alignment() == ParagraphStyle::Rightaligned)
2714,22 → 2676,22
 
if (style.alignment() == ParagraphStyle::Extended
|| (style.alignment() == ParagraphStyle::Justified
&& (currentCh == SpecialChars::LINEBREAK ||
currentCh == SpecialChars::FRAMEBREAK ||
currentCh == SpecialChars::COLBREAK)
&& !itemText.text(current.line.lastItem - 1).isSpace()))
&& (itemText.text(a) == SpecialChars::LINEBREAK ||
itemText.text(a) == SpecialChars::FRAMEBREAK ||
itemText.text(a) == SpecialChars::COLBREAK)
&& !itemText.text(glyphRuns[current.line.lastRun - 1].lastChar()).isSpace()))
{
justifyLine(itemText, current.line);
justifyLine(style, current);
}
else
{
if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
current.line.naturalWidth += opticalRightMargin(itemText, current.line);
current.line.naturalWidth += opticalRightMargin(itemText, glyphRuns, current.line);
double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing()/2.0 - current.line.x;
if (current.line.naturalWidth > optiWidth)
current.line.width = qMax(current.line.width - current.maxShrink, optiWidth);
// simple offset
indentLine(itemText, current.line, OFs);
indentLine(style, current, OFs);
}
current.xPos = current.colRight;
}
2737,11 → 2699,14
else // outs -- last char went outside the columns (or into flow-around shape)
{
if (current.breakIndex >= 0)
a = current.breakIndex;
assert( a >= 0 );
assert( a < itemText.length() );
glyphs = itemText.getGlyphs(a);
current.itemsInLine = a - current.line.firstItem + 1;
{
i = current.breakIndex;
a = glyphRuns[i].firstChar();
}
assert( i >= 0 );
assert( i < glyphRuns.length() );
//glyphs = itemText.getGlyphs(a);
current.isEmpty = (i - current.line.firstRun + 1) == 0;
if (current.addLine)
{
// go back to last break position
2752,11 → 2717,11
style.setLineSpacing(m_Doc->guidesPrefs().valueBaselineGrid);
 
if (itemText.text(a) == ' ') {
itemText.setFlag(a, ScLayout_SuppressSpace);
glyphs->xadvance = 0;
glyphRuns[i].setFlag(ScLayout_SuppressSpace);
glyphRuns[i].glyphs()[0].xadvance = 0;
}
 
current.updateHeightMetrics(itemText);
current.updateHeightMetrics();
//current.updateLineOffset(itemText, style, firstLineOffset());
//current.xPos = current.breakXPos;
EndX = current.endOfLine(m_availableRegion, current.rightMargin, regionMinY, regionMaxY);
2763,29 → 2728,33
current.finishLine(EndX);
 
hyphWidth = 0.0;
if (itemText.hasFlag(a, ScLayout_HyphenationPossible) || itemText.text(a) == SpecialChars::SHYPHEN)
if (glyphRuns[i].hasFlag(ScLayout_HyphenationPossible) || itemText.text(a) == SpecialChars::SHYPHEN)
{
// insert hyphen
if (current.lastInRowLine)
//increase hyphen count only for hyphens a the end of text row, omit hyphens before overflow
current.hyphenCount++;
itemText.setFlag(a, ScLayout_SoftHyphenVisible);
glyphs->grow();
glyphs->more->glyph = font.char2CMap(QChar('-'));
glyphs->more->xadvance = font.charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * scaleH; //FIX ME - hyphen is not rendered with proper width - check yhis with large glyphs horizontal scaling eg. 20%
hyphWidth = glyphs->more->xadvance;
glyphRuns[i].setFlag(ScLayout_SoftHyphenVisible);
GlyphLayout hyphen;
hyphen.glyph = font.char2CMap(QChar('-'));
hyphen.xadvance = font.glyphBBox(hyphen.glyph, itemText.charStyle(a).fontSize() / 10.0).width;
hyphWidth = hyphen.xadvance * scaleH;
glyphRuns[i].glyphs().append(hyphen);
}
else
{
if (itemText.text(a) != '-')
current.hyphenCount = 0;
itemText.clearFlag(a, ScLayout_SoftHyphenVisible);
glyphs->shrink();
if (glyphRuns[i].hasFlag(ScLayout_SoftHyphenVisible))
{
glyphRuns[i].clearFlag(ScLayout_SoftHyphenVisible);
glyphRuns[i].glyphs().removeLast();
}
}
 
// Justification
if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
current.line.width += opticalRightMargin(itemText, current.line);
current.line.width += opticalRightMargin(itemText, glyphRuns, current.line);
// #12565: Right alignment of hyphens
// The additional character width has already been taken into account
// above via the line break position, so it's not necessary to increase
2805,12 → 2774,12
OFs = (current.line.width - current.line.naturalWidth) / 2;
 
if ((style.alignment() == ParagraphStyle::Justified) || (style.alignment() == ParagraphStyle::Extended))
justifyLine(itemText, current.line);
justifyLine(style, current);
else
{
if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
current.line.naturalWidth += opticalRightMargin(itemText, current.line);
indentLine(itemText, current.line, OFs);
current.line.naturalWidth += opticalRightMargin(itemText, glyphRuns, current.line);
indentLine(style, current, OFs);
}
current.xPos = current.line.x + current.line.width;
}
2833,10 → 2802,10
if (current.isEndOfCol(desc))
{
//check if really line extends bottom margin
current.updateHeightMetrics(itemText);
current.updateHeightMetrics();
if (current.isEndOfCol(current.line.descent))
{
if (current.itemsInLine == 0 || current.column+1 == Cols)
if (current.isEmpty || current.column+1 == Cols)
{
goNoRoom = true;
MaxChars = a + 1;
2849,22 → 2818,23
}
else
setMaxY(maxYDesc);
if (current.line.firstItem <= current.line.lastItem && current.itemsInLine > 0)
if (current.line.firstRun <= current.line.lastRun && !current.isEmpty)
{
if (current.addLine && current.breakIndex >= 0)
{
if (itemText.charStyle(current.line.firstItem).effects() & ScLayout_DropCap)
if (glyphRuns[current.line.firstRun].style().effects() & ScLayout_DropCap)
{
// put line back to top
current.line.y -= DropCapDrop;
itemText.getGlyphs(current.line.firstItem)->yoffset += DropCapDrop;
glyphRuns[current.line.firstRun].glyphs().first().yoffset += DropCapDrop;
}
fillInTabLeaders(itemText, current.line);
fillInTabLeaders(current);
//if right margin is set we temporally save line, not append it
textLayout.appendLine(current.line);
textLayout.appendLine(current.createLineBox());
setMaxY(maxYDesc);
current.restartIndex = current.line.lastItem +1;
a = current.restartIndex -1;
current.restartIndex = current.line.lastRun + 1;
i = current.line.lastRun;
a = glyphRuns[i].firstChar();
current.rowDesc = qMax(current.rowDesc,current.yPos + current.line.descent);
if (!current.lastInRowLine)
{
2879,7 → 2849,7
else if (!inOverflow && !current.afterOverflow && current.lastInRowLine)
{
current.yPos++;
a = current.restartLine(true, true);
i = current.restartLine(true, true);
inOverflow = false;
outs = false;
current.mustLineEnd = current.colRight;
2930,7 → 2900,8
outs = false;
current.addLine = false;
current.lastInRowLine = false;
current.startLine(a+1);
// WTF does i+1 mean here, what if i is the last run we have!
current.startLine(i+1);
if (goNoRoom)
{
goNoRoom = false;
2945,7 → 2916,7
{
if (firstLineOffset() == FLOPRealGlyphHeight)
asce = 0;
current.nextColumn();
current.nextColumn(textLayout);
current.mustLineEnd = current.colRight;
current.addLeftIndent = true;
lastLineY = m_textDistanceMargins.top();
2961,23 → 2932,23
}
}
}
if (a == itemText.length() -1)
if (i == glyphRuns.length() - 1)
{
if (!current.afterOverflow || current.addLine)
{
current.addLine = true;
current.lastInRowLine = true;
current.breakLine(itemText, style, firstLineOffset(),a);
current.breakLine(style, firstLineOffset(), i);
}
if (current.afterOverflow && !current.addLine)
{
if (current.restartIndex < current.line.firstItem)
if (current.restartIndex < current.line.firstRun)
{
a = current.restartLine(false,true);
i = current.restartLine(false,true);
continue;
}
else
current.breakLine(itemText, style, firstLineOffset(),a);
current.breakLine(style, firstLineOffset(), i);
}
}
}
2988,10 → 2959,11
}
// end of itemText
// now place the last line
if (current.itemsInLine > 0 )
if (!current.isEmpty)
{
int a = itemText.length()-1;
current.breakLine(itemText, style, firstLineOffset(), a);
int i = glyphRuns.length() - 1;
current.breakLine(style, firstLineOffset(), i);
 
if (current.startOfCol)
{
3029,7 → 3001,7
current.finishLine(EndX);
 
if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
current.line.width += opticalRightMargin(itemText, current.line);
current.line.width += opticalRightMargin(itemText, glyphRuns, current.line);
 
OFs = 0;
if (style.alignment() == ParagraphStyle::Rightaligned)
3043,27 → 3015,27
&& (itemText.text(a) == SpecialChars::LINEBREAK ||
itemText.text(a) == SpecialChars::FRAMEBREAK ||
itemText.text(a) == SpecialChars::COLBREAK)
&& !itemText.text(current.line.firstItem + current.itemsInLine-1).isSpace()))
&& !itemText.text(a).isSpace()))
{
justifyLine(itemText, current.line);
justifyLine(style, current);
}
else
{
if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
current.line.naturalWidth += opticalRightMargin(itemText, current.line);
indentLine(itemText, current.line, OFs);
current.line.naturalWidth += opticalRightMargin(itemText, glyphRuns, current.line);
indentLine(style, current, OFs);
}
if ( itemText.charStyle(current.line.firstItem).effects() & ScLayout_DropCap )
if (glyphRuns[current.line.firstRun].style().effects() & ScLayout_DropCap)
{
// put line back to top
current.line.y -= DropCapDrop;
itemText.getGlyphs(current.line.firstItem)->yoffset += DropCapDrop;
glyphRuns[current.line.firstRun].glyphs().first().yoffset += DropCapDrop;
}
fillInTabLeaders(itemText, current.line);
fillInTabLeaders(current);
current.startOfCol = false;
goNextColumn = false;
 
textLayout.appendLine(current.line);
textLayout.appendLine(current.createLineBox());
setMaxY(maxYDesc);
current.startOfCol = false;
 
3077,20 → 3049,12
MaxChars = itemText.length();
if ((verticalAlign > 0) && (NextBox == NULL))
{
int vertAlign = verticalAlign;
double topDist = m_textDistanceMargins.top();
double hAdjust = 0;
if (verticalAlign == 1)
hAdjust = (height() - (m_textDistanceMargins.bottom() + lineCorr) - maxY) / 2.0;
else if (verticalAlign == 2)
hAdjust = (height() - (m_textDistanceMargins.bottom() + lineCorr) - maxY);
double hAdjust = height() - textLayout.box()->naturalHeight();
if (hAdjust > 0)
{
m_textDistanceMargins.setTop(topDist + hAdjust);
verticalAlign = 0;
layout();
m_textDistanceMargins.setTop(topDist);
verticalAlign = vertAlign;
if (verticalAlign == 1)
hAdjust /= 2;
textLayout.box()->moveBy(0, hAdjust);
}
}
invalid = false;
3220,20 → 3184,6
if (m_Doc->RePos)
return;
QTransform pf2;
QPoint pt1, pt2;
double wide;
QString cachedStroke = "";
QString cachedFill = "";
double cachedFillShade = -1;
double cachedStrokeShade = -1;
QString actStroke = "";
QString actFill = "";
double actFillShade = -1;
double actStrokeShade = -1;
QColor cachedFillQ;
QColor cachedStrokeQ;
// QValueList<ParagraphStyle::TabRecord> tTabValues;
double desc, asce;
// tTabValues.clear();
p->save(); //SA1
 
3696,326 → 3646,16
}
assert( firstInFrame() >= 0 );
assert( lastInFrame() < itemText.length() );
LineSpec ls;
 
uint llp = 0;
while (llp < textLayout.lines())
{
ls = textLayout.line(llp++);
const ParagraphStyle& LineStyle = itemText.paragraphStyle(ls.firstItem);
if (LineStyle.backgroundColor() != CommonStrings::None)
{
QColor tmp;
SetQColor(&tmp, LineStyle.backgroundColor(), LineStyle.backgroundShade());
double y0 = ls.y;
double y2 = ls.y;
double ascent = ls.ascent;
double descent = ls.descent;
double rMarg = LineStyle.rightMargin();
double lMarg = ls.colLeft;
double adjX = 0;
if (LineStyle.firstIndent() <= 0)
adjX += LineStyle.leftMargin() + LineStyle.firstIndent();
while (llp < textLayout.lines())
{
ls = textLayout.line(llp);
if ((ls.colLeft > lMarg) || (itemText.paragraphStyle(ls.firstItem) != LineStyle))
{
if (y2 == 0)
y2 = y0;
break;
}
if (itemText.text(ls.lastItem) == SpecialChars::PARSEP)
{
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < textLayout.lines())
{
if ((textLayout.line(llp + 1).lastItem - textLayout.line(llp + 1).firstItem) > 0)
descent += LineStyle.lineSpacing() - (ls.descent + textLayout.line(llp + 1).ascent);
}
llp++;
break;
}
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < textLayout.lines())
descent += LineStyle.lineSpacing() - (ls.descent + textLayout.line(llp + 1).ascent);
llp++;
}
p->save();
p->setupPolygon(&PoLine);
p->setClipPath();
p->setAntialiasing(false);
p->setFillMode(1);
p->setStrokeMode(0);
p->setBrush(tmp);
p->drawRect(lMarg + adjX, y0 - ascent, columnWidth() - adjX - rMarg, y2 - y0 + descent + ascent);
p->setAntialiasing(true);
p->restore();
}
}
for (uint ll=0; ll < textLayout.lines(); ++ll)
{
ls = textLayout.line(ll);
double CurX = ls.x;
// Draw text selection rectangles
QRectF selectedFrame;
QList<QRectF> sFList;
bool previousWasObject(false);
double selX = ls.x;
GlyphLayout* glyphs = 0;
int last = qMin(ls.lastItem, itemText.length() - 1);
for (int as = ls.firstItem; as <= last; ++as)
{
bool selecteds = itemText.selected(as);
glyphs = itemText.getGlyphs(as);
bool HasObject = itemText.hasObject(as);
Mark* mark = itemText.mark(as);
if (mark != NULL && (mark->isType(MARKAnchorType) || mark->isType(MARKIndexType)))
continue;
if (selecteds)
{
const CharStyle& charStyleS(itemText.charStyle(as));
if (((as > ls.firstItem) && (charStyleS != itemText.charStyle(as-1)))
|| ((!selectedFrame.isNull()) && HasObject)
|| previousWasObject)
{
sFList << selectedFrame;
selectedFrame = QRectF();
previousWasObject = false;
}
if ((m_isSelected || (NextBox != 0 || BackBox != 0))
&& (m_Doc->appMode == modeEdit || m_Doc->appMode == modeEditTable))
{
double xcoZli = selX + glyphs->xoffset;
// ugly hack to make selection correct, as xoffset is used to
// remove left-half of CJK lparen , which is blank.
if (glyphs->xoffset)
{
int attr = SpecialChars::getCJKAttr(itemText.text(as)) & SpecialChars::CJK_CHAR_MASK;
if (attr == SpecialChars::CJK_FENCE_BEGIN)
{
xcoZli -= glyphs->xoffset;
}
}
const ScFace font = charStyleS.font();
double fontSize = charStyleS.fontSize() / 10.0;
desc = - font.descent(fontSize);
asce = font.ascent(fontSize);
wide = glyphs->wide();
QRectF scr;
if (HasObject)
{
PageItem* obj = itemText.object(as);
double ww = (obj->width() + obj->lineWidth()) * glyphs->scaleH;
double hh = (obj->height() + obj->lineWidth()) * glyphs->scaleV;
scr = QRectF(xcoZli, ls.y - hh, ww , hh);
previousWasObject = true;
}
else
scr = QRectF(xcoZli, ls.y + glyphs->yoffset - asce * glyphs->scaleV, wide , (asce+desc) * (glyphs->scaleV));
selectedFrame |= scr;
}
}
// Unneeded now that glyph xadvance is set appropriately for inline objects by layout() - JG
/*if ((hls->ch == SpecialChars::OBJECT) && (hls->embedded.hasItem()))
selX += (hls->embedded.getItem()->gWidth + hls->embedded.getItem()->lineWidth()) * hls->glyph.scaleH;
else*/
selX += glyphs->wide();
}
if (!selectedFrame.isNull())
sFList << selectedFrame;
p->save();//SA3
p->setFillMode(1);
p->setBrush(qApp->palette().color(QPalette::Active, QPalette::Highlight));
p->setLineWidth(0);
// TODO - I dunno why but scpainter does not accept
// to actually set the pen to 0? As a wa,
// we set its color same as brush: "à malin, malin et demi!".
p->setPen(qApp->palette().color(QPalette::Active, QPalette::Highlight));
for(int sfc(0);sfc < sFList.count();++sfc)
p->drawRect(sFList[sfc].x(), sFList[sfc].y(), sFList[sfc].width(), sFList[sfc].height());
p->restore();//RE3
// End of selection
 
QColor tmp;
double CurXB = ls.x;
QRectF scrG;
QString oldBack;
double oldShade = 100;
for (int a = ls.firstItem; a <= last; ++a)
{
glyphs = itemText.getGlyphs(a);
const CharStyle& charStyle(itemText.charStyle(a));
if (charStyle.backColor() != CommonStrings::None)
{
SetQColor(&tmp, charStyle.backColor(), charStyle.backShade());
const ParagraphStyle& LineStyle = itemText.paragraphStyle(ls.firstItem);
double y1 = ls.y;
double hl = ls.height;
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
hl = doc()->guidesPrefs().valueBaselineGrid;
else if (LineStyle.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
hl = LineStyle.lineSpacing();
if (ls.isFirstLine)
{
if (textLayout.lines() == 1)
hl = ls.ascent + ls.descent;
if (LineStyle.hasDropCap() && (a == ls.firstItem))
hl *= LineStyle.dropCapLines();
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
y1 -= LineStyle.lineSpacing();
else if (firstLineOffset() == FLOPRealGlyphHeight || firstLineOffset() == FLOPFontAscent)
y1 -= ls.ascent;
else
y1 -= LineStyle.lineSpacing();
}
else
y1 -= ls.ascent + (hl - (ls.ascent + ls.descent)) / 2.0;
QRectF scr;
if (itemText.hasObject(a))
{
PageItem* obj = itemText.object(a);
double ww = (obj->width() + obj->lineWidth()) * glyphs->scaleH;
double hh = (obj->height() + obj->lineWidth()) * glyphs->scaleV;
scr = QRectF(CurXB, ls.y - hh, ww , hh);
}
else
scr = QRectF(CurXB, y1, glyphs->wide(), hl);
if ((oldBack.isEmpty()) || ((oldBack == charStyle.backColor()) && (oldShade == charStyle.backShade())))
scrG |= scr;
else if ((oldBack != charStyle.backColor()) || (oldShade != charStyle.backShade()))
{
p->save();
p->setFillMode(1);
p->setStrokeMode(0);
SetQColor(&tmp, oldBack, oldShade);
p->setBrush(tmp);
p->drawRect(scrG.x(), scrG.y(), scrG.width(), scrG.height());
p->restore();
scrG = scr;
}
oldBack = charStyle.backColor();
oldShade = charStyle.backShade();
}
else
{
oldBack.clear();
oldShade = 100;
if (!scrG.isNull())
{
p->save();
p->setFillMode(1);
p->setStrokeMode(0);
p->setBrush(tmp);
p->drawRect(scrG.x(), scrG.y(), scrG.width(), scrG.height());
p->restore();
}
scrG = QRectF();
}
CurXB += glyphs->wide();
}
if (!scrG.isNull())
{
p->save();
p->setFillMode(1);
p->setStrokeMode(0);
p->setBrush(tmp);
p->drawRect(scrG.x(), scrG.y(), scrG.width(), scrG.height());
p->restore();
}
for (int a = ls.firstItem; a <= last; ++a)
{
glyphs = itemText.getGlyphs(a);
const CharStyle& charStyle(itemText.charStyle(a));
bool selected = itemText.selected(a);
actFill = charStyle.fillColor();
actFillShade = charStyle.fillShade();
if (actFill != CommonStrings::None)
{
p->setFillMode(ScPainter::Solid);
if ((cachedFillShade != actFillShade) || (cachedFill != actFill))
{
SetQColor(&tmp, actFill, actFillShade);
p->setBrush(tmp);
cachedFillQ = tmp;
cachedFill = actFill;
cachedFillShade = actFillShade;
}
else
p->setBrush(cachedFillQ);
}
else
p->setFillMode(ScPainter::None);
 
const ScFace font = charStyle.font();
double fontSize = charStyle.fontSize() / 10.0;
desc = - font.descent(fontSize);
asce = font.ascent(fontSize);
if (((selected && m_isSelected) || ((NextBox != 0 || BackBox != 0) && selected)) && (m_Doc->appMode == modeEdit || m_Doc->appMode == modeEditTable))
{
// set text color to highlight if its selected
p->setBrush(qApp->palette().color(QPalette::Active, QPalette::HighlightedText));
}
 
actStroke = charStyle.strokeColor();
actStrokeShade = charStyle.strokeShade();
if (actStroke != CommonStrings::None)
{
if ((cachedStrokeShade != actStrokeShade) || (cachedStroke != actStroke))
{
SetQColor(&tmp, actStroke, actStrokeShade);
p->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
cachedStrokeQ = tmp;
cachedStroke = actStroke;
cachedStrokeShade = actStrokeShade;
}
else
p->setPen(cachedStrokeQ, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
}
// paint glyphs
QRectF scrGl;
if (itemText.hasObject(a))
{
PageItem* obj = itemText.object(a);
double ww = (obj->width() + obj->lineWidth()) * glyphs->scaleH;
double hh = (obj->height() + obj->lineWidth()) * glyphs->scaleV;
scrGl = QRectF(CurX, ls.y + glyphs->yoffset, ww , -hh).normalized();
previousWasObject = true;
}
else
scrGl = QRectF(CurX + glyphs->xoffset, ls.y + glyphs->yoffset - asce * glyphs->scaleV, glyphs->xadvance+1 , (asce+desc) * (glyphs->scaleV));
if (isEmbedded || cullingArea.intersects(pf2.mapRect(scrGl)))
{
p->save();//SA4
p->translate(CurX, ls.y);
if (itemText.hasObject(a))
DrawObj_Embedded(p, cullingArea, charStyle, itemText.object(a));
else
{
//control chars for marks
if (m_Doc->guidesPrefs().showControls && itemText.hasMark(a) && (glyphs->glyph != SpecialChars::OBJECT))
{
GlyphLayout markGlyph;
layoutGlyphs(charStyle, SpecialChars::OBJECT, ScLayout_None, markGlyph);
drawGlyphs(p, charStyle, ScLayout_None, markGlyph);
}
drawGlyphs(p, charStyle, itemText.flags(a), *glyphs);
}
p->restore();//RE4
}
// Unneeded now that glyph xadvance is set appropriately for inline objects by layout() - JG
/*if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem()))
CurX += (hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth()) * hl->glyph.scaleH;
else*/
CurX += glyphs->wide();
}
}
// else {
// // qDebug("skipping textframe: len=%d", itemText.count());
// }
// pf2.end();
int fm = p->fillMode();
int sm = p->strokeMode();
p->setFillMode(1);
p->setStrokeMode(1);
ScreenPainter painter(p, this);
textLayout.renderBackground(&painter);
textLayout.render(&painter, this);
p->setFillMode(fm);
p->setStrokeMode(sm);
}
m_textDistanceMargins=savedTextDistanceMargins;
p->restore();//RE1
4489,7 → 4129,7
ExpandSel(1, oldPos);
}
else
if ((textLayout.lines() > 0) && (oldPos >= textLayout.line(textLayout.lines()-1).firstItem) && (itemText.cursorPosition() >= lastInFrame()) && (NextBox != 0))
if ((textLayout.lines() > 0) && (oldPos >= textLayout.line(textLayout.lines()-1)->firstChar()) && (itemText.cursorPosition() >= lastInFrame()) && (NextBox != 0))
{
if (NextBox->frameDisplays(itemText.cursorPosition()))
{
4540,7 → 4180,7
ExpandSel(-1, oldPos);
}
else
if ((textLayout.lines() > 0) && (oldPos <= textLayout.line(0).lastItem) && (itemText.cursorPosition() == firstInFrame()) && (BackBox != 0))
if ((textLayout.lines() > 0) && (oldPos <= textLayout.line(0)->lastChar()) && (itemText.cursorPosition() == firstInFrame()) && (BackBox != 0))
{
view->Deselect(true);
// TODO position at the right place in previous frame
6254,59 → 5894,34
 
void PageItem_TextFrame::setTextFrameHeight()
{
//ugly hack increasing min frame`s haeight against strange glyph painting if it is too close of bottom
double hackValue = 0.5;
 
if (textLayout.lines() <= 0)
return;
const LineSpec& firstLine = textLayout.line(0);
const LineSpec& lastLine = textLayout.line(textLayout.lines() -1);
 
double y1 = firstLine.y /*- firstLine.ascent*/;
double y2 = lastLine.y + lastLine.descent;
 
const ParagraphStyle& firstLineStyle = itemText.paragraphStyle(firstLine.firstItem);
if (firstLineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
y1 -= firstLineStyle.lineSpacing();
else if (firstLineOffset() == FLOPRealGlyphHeight || firstLineOffset() == FLOPFontAscent)
y1 -= firstLine.ascent;
else
y1 -= firstLineStyle.lineSpacing();
 
double newHeight = ceil(y2) + m_textDistanceMargins.bottom() + hackValue;
if (NextBox == 0) // Vertical alignment is not used inside a text chain
{
if (verticalAlign == 1)
newHeight -= floor(y1);
else if (verticalAlign == 2)
newHeight = m_height - floor(y1);
}
textLayout.box()->moveTo(textLayout.box()->x(), 0);
double newHeight = textLayout.box()->naturalHeight();
 
UndoTransaction undoTransaction;
if (UndoManager::undoEnabled() && (verticalAlign != 0))
{
QString unitSuffix = unitGetStrFromIndex(m_Doc->unitIndex());
int unitPrecision = unitGetPrecisionFromIndex(m_Doc->unitIndex());
double unitRatio = m_Doc->unitRatio();
QString owString = QString::number(oldWidth * unitRatio, 'f', unitPrecision) + " " + unitSuffix;
QString ohString = QString::number(oldHeight * unitRatio, 'f', unitPrecision) + " " + unitSuffix;
QString nwString = QString::number(m_width * unitRatio, 'f', unitPrecision) + " " + unitSuffix;
QString nhString = QString::number(m_height * unitRatio, 'f', unitPrecision) + " " + unitSuffix;
QString tooltip = QString(Um::ResizeFromTo).arg(owString).arg(ohString).arg(nwString).arg(nhString);
undoTransaction = undoManager->beginTransaction(Um::Selection, Um::ITextFrame, Um::Resize, tooltip, Um::IResize);
}
UndoTransaction undoTransaction;
if (UndoManager::undoEnabled())
{
QString unitSuffix = unitGetStrFromIndex(m_Doc->unitIndex());
int unitPrecision = unitGetPrecisionFromIndex(m_Doc->unitIndex());
double unitRatio = m_Doc->unitRatio();
QString owString = QString::number(oldWidth * unitRatio, 'f', unitPrecision) + " " + unitSuffix;
QString ohString = QString::number(oldHeight * unitRatio, 'f', unitPrecision) + " " + unitSuffix;
QString nwString = QString::number(m_width * unitRatio, 'f', unitPrecision) + " " + unitSuffix;
QString nhString = QString::number(m_height * unitRatio, 'f', unitPrecision) + " " + unitSuffix;
QString tooltip = QString(Um::ResizeFromTo).arg(owString).arg(ohString).arg(nwString).arg(nhString);
undoTransaction = undoManager->beginTransaction(Um::Selection, Um::ITextFrame, Um::Resize, tooltip, Um::IResize);
}
 
if (verticalAlign != 0)
{
double newX = m_xPos + floor(y1) * cos(-m_rotation * M_PI / 180 - M_PI / 2);
double newY = m_yPos - floor(y1) * sin(-m_rotation * M_PI / 180 - M_PI / 2);
setXYPos(newX, newY);
setHeight(newHeight);
 
if (undoTransaction)
undoTransaction.commit();
}
setHeight(newHeight);
 
if (undoTransaction)
undoTransaction.commit();
 
updateClip();
invalid = true;
m_Doc->changed();
/trunk/Scribus/scribus/pageitem_textframe.h
159,6 → 159,9
 
public:
void setTextFrameHeight();
 
private:
QList<GlyphRun> shapeText();
};
 
#endif
/trunk/Scribus/scribus/pdflib_core.cpp
71,6 → 71,7
#include "sccolor.h"
#include "sccolorengine.h"
#include "scfonts.h"
#include "text/textlayoutpainter.h"
#include "fonts/cff.h"
#include "fonts/sfnt.h"
#include "scpage.h"
87,6 → 88,7
#include "util_formats.h"
#include "util_math.h"
#include "util_ghostscript.h"
#include "text/boxes.h"
 
#ifdef HAVE_OSG
#include "third_party/prc/exportPRC.h"
103,7 → 105,377
#undef GetObject
#endif
 
static inline QByteArray FToStr(double c)
{
double v = c;
if (fabs(c) < 0.0000001)
v = 0.0;
return QByteArray::number(v, 'f', 5);
}
 
class PdfPainter: public TextLayoutPainter
{
QByteArray m_glyphBuffer;
QByteArray m_pathBuffer;
PageItem* m_item;
QMap<QString, PdfFont> m_UsedFontsP;
PDFLibCore *m_pdf;
uint m_PNr;
const ScPage* m_page;
 
QByteArray transformToStr(QTransform tr)
{
return FToStr(tr.m11()) + " " + FToStr(-tr.m12()) + " " + FToStr(-tr.m21()) + " " + FToStr(tr.m22()) + " " + FToStr(tr.dx()) + " " + FToStr(-tr.dy());
}
 
public:
PdfPainter(PageItem *ite, PDFLibCore *pdf, uint num, const ScPage* pag) :
m_glyphBuffer(),
m_pathBuffer(),
m_item(ite),
m_pdf(pdf),
m_PNr(num),
m_page(pag)
{}
 
~PdfPainter() {}
 
void drawGlyph(const GlyphLayout gl)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
PdfFont pdfFont = m_pdf->UsedFontsP[font().replacementName()];
QByteArray StrokeColor;
QByteArray FillColor;
QTransform transform = matrix();
 
if (strokeColor().color != CommonStrings::None)
StrokeColor = m_pdf->putColor(strokeColor().color, strokeColor().shade, false);
if (fillColor().color != CommonStrings::None)
FillColor = m_pdf->putColor(fillColor().color, fillColor().shade, true);
 
if (pdfFont.method == Use_XForm)
{
if (!FillColor.isEmpty())
m_pathBuffer += FillColor;
 
m_pathBuffer += "q\n";
m_glyphBuffer += FToStr(fontSize()) + " 0 0 " + FToStr(fontSize()) + " " + FToStr(x()) + " " + FToStr(y()) + " cm\n";
 
if (gl.scaleV != 1.0)
m_pathBuffer += "1 0 0 1 0 " + FToStr(((fontSize() - fontSize() * gl.scaleV) / fontSize()) * -1) + " cm\n";
 
transform.scale(qMax(gl.scaleH, 0.1), qMax(gl.scaleV, 0.1));
m_glyphBuffer += transformToStr(transform) + " cm\n";
 
if (!FillColor.isEmpty())
m_pathBuffer += pdfFont.name + Pdf::toPdf(gl.glyph) + " Do\n";
m_pathBuffer += "Q\n";
}
else
{
uint gid = gl.glyph;
uint fontNr = 65535;
 
switch (pdfFont.encoding)
{
case Encode_256:
gid = pdfFont.glyphmap[gid];
fontNr = gid / 256;
gid = gid % 256;
break;
case Encode_224:
fontNr = gid / 224;
gid = gid % 224 + 32;
break;
case Encode_Subset:
gid = pdfFont.glyphmap[gid];
break;
case Encode_IdentityH:
break;
}
 
if (fontNr == 65535)
m_glyphBuffer += pdfFont.name + " " + FToStr(fontSize()) + " Tf\n";
else
m_glyphBuffer += pdfFont.name + "S" + Pdf::toPdf(fontNr) + " " + FToStr(fontSize()) + " Tf\n";
 
if (!StrokeColor.isEmpty())
m_glyphBuffer += StrokeColor;
 
if (!FillColor.isEmpty())
m_glyphBuffer += FillColor;
 
m_glyphBuffer += "0 Tr\n";
 
transform.translate(x(), y());
transform.scale(qMax(gl.scaleH, 0.1), qMax(gl.scaleV, 0.1));
m_glyphBuffer += transformToStr(transform) + " Tm\n";
 
 
if (pdfFont.method != Use_Type3 || !FillColor.isEmpty())
{
switch (pdfFont.encoding)
{
case Encode_224:
case Encode_256:
m_glyphBuffer += Pdf::toHexString8(gid) + " Tj\n";
break;
case Encode_IdentityH:
default:
m_glyphBuffer += Pdf::toHexString16(gid) + " Tj\n";
break;
}
}
}
}
 
void drawGlyphOutline(const GlyphLayout gl, bool fill)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
PdfFont pdfFont = m_pdf->UsedFontsP[font().replacementName()];
QByteArray StrokeColor;
QByteArray FillColor;
QTransform transform = matrix();
 
if (strokeColor().color != CommonStrings::None)
StrokeColor = m_pdf->putColor(strokeColor().color, strokeColor().shade, false);
if (fill && fillColor().color != CommonStrings::None)
FillColor = m_pdf->putColor(fillColor().color, fillColor().shade, true);
 
if (pdfFont.method == Use_XForm)
{
if (!StrokeColor.isEmpty())
{
m_pathBuffer += FToStr(strokeWidth()) + " w\n[] 0 d\n0 J\n0 j\n";
m_pathBuffer += StrokeColor;
}
 
if (!FillColor.isEmpty())
m_pathBuffer += FillColor;
 
m_pathBuffer += "q\n";
m_glyphBuffer += FToStr(fontSize()) + " 0 0 " + FToStr(fontSize()) + " " + FToStr(x()) + " " + FToStr(y()) + " cm\n";
 
if (gl.scaleV != 1.0)
m_pathBuffer += "1 0 0 1 0 " + FToStr(((fontSize() - fontSize() * (gl.scaleV)) / fontSize()) * -1) + " cm\n";
 
transform.scale(qMax(gl.scaleH, 0.1), qMax(gl.scaleV, 0.1));
m_pathBuffer += transformToStr(transform) + " cm\n";
 
if (!FillColor.isEmpty())
m_pathBuffer += pdfFont.name + Pdf::toPdf(gl.glyph) + " Do\n";
 
FPointArray outline = font().glyphOutline(gl.glyph);
QTransform mat;
mat.scale(0.1, 0.1);
outline.map(mat);
bool nPath = true;
FPoint np;
if (outline.size() > 3)
{
for (int poi = 0; poi < outline.size() - 3; poi += 4)
{
if (outline.isMarker(poi))
{
m_pathBuffer += "h\n";
nPath = true;
continue;
}
 
if (nPath)
{
np = outline.point(poi);
m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " m\n";
nPath = false;
}
 
np = outline.point(poi + 1);
m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " ";
np = outline.point(poi + 3);
m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " ";
np = outline.point(poi + 2);
m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " c\n";
}
}
m_pathBuffer += "h s\n";
m_pathBuffer += "Q\n";
}
else
{
if (!StrokeColor.isEmpty())
m_pathBuffer += StrokeColor;
 
uint gid = gl.glyph;
uint fontNr = 65535;
switch (pdfFont.encoding)
{
case Encode_256:
gid = pdfFont.glyphmap[gid];
fontNr = gid / 256;
gid = gid % 256;
break;
case Encode_224:
fontNr = gid / 224;
gid = gid % 224 + 32;
break;
case Encode_Subset:
gid = pdfFont.glyphmap[gid];
break;
case Encode_IdentityH:
break;
}
 
if (fontNr == 65535)
m_glyphBuffer += pdfFont.name + " " + FToStr(fontSize()) + " Tf\n";
else
m_glyphBuffer += pdfFont.name + "S" + Pdf::toPdf(fontNr) + " " + FToStr(fontSize()) + " Tf\n";
 
if (!StrokeColor.isEmpty())
m_glyphBuffer += StrokeColor;
 
if (!FillColor.isEmpty())
m_glyphBuffer += FillColor;
 
if (pdfFont.method == Use_Type3 && !StrokeColor.isEmpty())
{
m_pathBuffer += "q\n";
m_pathBuffer += FToStr(strokeWidth()) + " w\n[] 0 d\n0 J\n0 j\n";
 
transform.scale(fontSize(), fontSize());
transform.translate(x(), y());
if (gl.scaleV != 1.0)
transform.translate(0, ((fontSize() - fontSize() * gl.scaleV) / fontSize()) * -1);
transform.scale(qMax(gl.scaleH, 0.1), qMax(gl.scaleV, 0.1));
m_pathBuffer += transformToStr(transform) + " cm\n";
 
/* paint outline */
FPointArray outline = font().glyphOutline(gl.glyph);
QTransform mat;
mat.scale(0.1, 0.1);
outline.map(mat);
bool nPath = true;
FPoint np;
if (outline.size() > 3)
{
for (int poi = 0; poi < outline.size() - 3; poi += 4)
{
if (outline.isMarker(poi))
{
m_pathBuffer += "h\n";
nPath = true;
continue;
}
 
if (nPath)
{
np = outline.point(poi);
m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " m\n";
nPath = false;
}
 
np = outline.point(poi + 1);
m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " ";
np = outline.point(poi + 3);
m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " ";
np = outline.point(poi + 2);
m_pathBuffer += FToStr(np.x()) + " " + FToStr(-np.y()) + " c\n";
}
}
m_pathBuffer += "h s\n";
m_pathBuffer += "Q\n";
}
else
{
m_glyphBuffer += FToStr(strokeWidth()) + " w ";
if (fill)
m_glyphBuffer += "2 Tr\n";
else
m_glyphBuffer += "1 Tr\n";
}
 
transform.translate(x(), y());
transform.scale(qMax(gl.scaleH, 0.1), qMax(gl.scaleV, 0.1));
m_glyphBuffer += transformToStr(transform) + " Tm\n";
 
if (pdfFont.method != Use_Type3 || !FillColor.isEmpty())
{
switch (pdfFont.encoding)
{
case Encode_224:
case Encode_256:
m_glyphBuffer += Pdf::toHexString8(gid) + " Tj\n";
break;
case Encode_IdentityH:
default:
m_glyphBuffer += Pdf::toHexString16(gid) + " Tj\n";
break;
}
}
}
}
 
void drawLine(QPointF start, QPointF end)
{
QTransform transform = matrix();
transform.translate(x(), y());
m_pathBuffer += "q\n";
m_pathBuffer += transformToStr(transform) + " cm\n";
m_pathBuffer += m_pdf->putColor(strokeColor().color, strokeColor().shade, false);
m_pathBuffer += FToStr(strokeWidth())+" w\n";
m_pathBuffer += FToStr(start.x()) + " " + FToStr(-start.y()) + " m\n";
m_pathBuffer += FToStr(end.x()) + " " + FToStr(-end.y()) + " l\n";
m_pathBuffer += "S\n";
m_pathBuffer += "Q\n";
}
 
QByteArray getBuffer()
{
return "BT\n" + m_glyphBuffer + "ET\n" + m_pathBuffer;
}
 
void drawRect(QRectF rect)
{
QTransform transform = matrix();
// transform.translate(x(), y());
double rectX = x() + rect.x();
double rectY = -y() - rect.y();
m_glyphBuffer += "q\n";
m_glyphBuffer += transformToStr(transform) + " cm\n";
m_glyphBuffer += "n\n";
m_glyphBuffer += m_pdf->putColor(fillColor().color, fillColor().shade, true);
m_glyphBuffer += m_pdf->putColor(strokeColor().color, strokeColor().shade, false);
m_glyphBuffer += FToStr(rectX) + " " + FToStr(rectY) + " m\n";
m_glyphBuffer += FToStr(rectX + rect.width()) + " " + FToStr(rectY) + " l\n";
m_glyphBuffer += FToStr(rectX + rect.width()) + " " + FToStr(rectY - rect.height()) + " l\n";
m_glyphBuffer += FToStr(rectX) + " " + FToStr(rectY - rect.height()) + " l\n";
m_glyphBuffer += "h\nf\n";
m_glyphBuffer += "Q\n";
}
 
void drawObject(PageItem* embedded)
{
m_glyphBuffer += "ET\n"+m_pathBuffer;
m_pathBuffer = "";
 
m_pathBuffer += "q\n";
m_pathBuffer += FToStr(scaleH()) + " 0 0 " + FToStr(scaleV()) + " " + FToStr(x()) + " " + FToStr(-y()) + " cm\n";
 
QByteArray output;
if (!m_pdf->PDF_ProcessItem(output, embedded, m_page, m_PNr, true))
return;
m_pathBuffer += output;
m_pathBuffer += "Q\n";
m_glyphBuffer += m_pathBuffer+"\n";
m_pathBuffer = "";
 
m_glyphBuffer += "BT\n";
}
};
 
PDFLibCore::PDFLibCore(ScribusDoc & docu)
: QObject(&docu),
doc(docu),
170,13 → 542,6
delete progressDialog;
}
 
static inline QByteArray FToStr(double c)
{
double v = c;
if (fabs(c) < 0.0000001)
v = 0.0;
return QByteArray::number(v, 'f', 5);
};
 
bool PDFLibCore::PDF_IsPDFX()
{
5380,855 → 5745,12
// Return a PDF substring representing a PageItem's text
QByteArray PDFLibCore::setTextSt(PageItem *ite, uint PNr, const ScPage* pag)
{
int tabCc = 0;
int savedOwnPage = ite->OwnPage;
double tabDist = ite->textToFrameDistLeft();
QByteArray tmp(""), tmp2("");
QList<ParagraphStyle::TabRecord> tTabValues;
ite->OwnPage = PNr;
ite->layout();
ite->OwnPage = savedOwnPage;
if (ite->lineColor() != CommonStrings::None)
tabDist += ite->lineWidth() / 2.0;
// Loop over each character (!) in the pageItem...
if (ite->itemType() == PageItem::TextFrame)
{
PathData straightPath;
straightPath.PtransX = 0;
straightPath.PtransY = 0;
straightPath.PRot = 0;
straightPath.PDx = 0;
tmp += "BT\n";
uint llp = 0;
while (llp < ite->textLayout.lines())
{
LineSpec ls = ite->textLayout.line(llp++);
const ParagraphStyle& LineStyle = ite->itemText.paragraphStyle(ls.firstItem);
if (LineStyle.backgroundColor() != CommonStrings::None)
{
double y0 = ls.y;
double y2 = ls.y;
double ascent = ls.ascent;
double descent = ls.descent;
double rMarg = LineStyle.rightMargin();
double lMarg = ls.colLeft;
double adjX = 0;
if (LineStyle.firstIndent() <= 0)
adjX += LineStyle.leftMargin() + LineStyle.firstIndent();
while (llp < ite->textLayout.lines())
{
ls = ite->textLayout.line(llp);
if ((ls.colLeft > lMarg) || (ite->itemText.paragraphStyle(ls.firstItem) != LineStyle))
{
if (y2 == 0)
y2 = y0;
break;
}
if (ite->itemText.text(ls.lastItem) == SpecialChars::PARSEP)
{
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < ite->textLayout.lines())
{
if ((ite->textLayout.line(llp + 1).lastItem - ite->textLayout.line(llp + 1).firstItem) > 0)
descent += LineStyle.lineSpacing() - (ls.descent + ite->textLayout.line(llp + 1).ascent);
}
llp++;
break;
}
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < ite->textLayout.lines())
descent += LineStyle.lineSpacing() - (ls.descent + ite->textLayout.line(llp + 1).ascent);
llp++;
}
QRectF scr(lMarg + adjX, y0 - ascent, ite->asTextFrame()->columnWidth() - adjX - rMarg, y2 - y0 + descent + ascent);
tmp += "q\n";
tmp += "n\n";
tmp += SetPathAndClip(ite);
tmp += putColor(LineStyle.backgroundColor(), LineStyle.backgroundShade(), true);
tmp += FToStr(scr.x()) +" "+FToStr(-scr.y())+" m\n";
tmp += FToStr(scr.x() + scr.width())+" "+FToStr(-scr.y())+" l\n";
tmp += FToStr(scr.x() + scr.width())+" "+FToStr(-scr.y() - scr.height())+" l\n";
tmp += FToStr(scr.x())+" "+FToStr(-scr.y() - scr.height())+" l\n";
tmp += "h\nf\n";
tmp += "Q\n";
}
}
for (uint ll=0; ll < ite->textLayout.lines(); ++ll)
{
LineSpec ls = ite->textLayout.line(ll);
tabDist = ls.x;
double CurX = ls.x;
double CurXB = ls.x;
int last = qMin(ls.lastItem, ite->itemText.length() - 1);
QRectF scr;
QString oldBack = "";
double oldShade = 100;
QByteArray colorB = "";
for (int a = ls.firstItem; a <= last; ++a)
{
const GlyphLayout* glyphs(ite->itemText.getGlyphs(a));
const CharStyle& charStyle(ite->itemText.charStyle(a));
if (charStyle.backColor() != CommonStrings::None)
{
colorB = putColor(charStyle.backColor(), charStyle.backShade(), true);
// This code is for rendering character background color.
const ParagraphStyle& LineStyle = ite->itemText.paragraphStyle(ls.firstItem);
double y1 = ls.y;
double hl = ls.height;
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
hl = doc.guidesPrefs().valueBaselineGrid;
else if (LineStyle.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
hl = LineStyle.lineSpacing();
if (ls.isFirstLine)
{
if (ite->textLayout.lines() == 1)
hl = ls.ascent + ls.descent;
if (LineStyle.hasDropCap() && (a == ls.firstItem))
hl *= LineStyle.dropCapLines();
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
y1 -= LineStyle.lineSpacing();
else if (ite->firstLineOffset() == FLOPRealGlyphHeight || ite->firstLineOffset() == FLOPFontAscent)
y1 -= ls.ascent;
else
y1 -= LineStyle.lineSpacing();
}
else
y1 -= ls.ascent + (hl - (ls.ascent + ls.descent)) / 2.0;
QRectF scrG;
if (ite->itemText.hasObject(a))
{
PageItem* obj = ite->itemText.object(a);
double ww = (obj->width() + obj->lineWidth()) * glyphs->scaleH;
double hh = (obj->height() + obj->lineWidth()) * glyphs->scaleV;
scrG = QRectF(CurXB, ls.y - hh, ww , hh);
}
else
scrG = QRectF(CurXB, y1, glyphs->wide(), hl);
if ((oldBack == "") || ((oldBack == charStyle.backColor()) && (oldShade == charStyle.backShade())))
scr |= scrG;
else if ((oldBack != charStyle.backColor()) || (oldShade != charStyle.backShade()))
{
tmp += "q\n";
tmp += "n\n";
tmp += putColor(oldBack, oldShade, true);
tmp += FToStr(scr.x()) +" "+FToStr(-scr.y())+" m\n";
tmp += FToStr(scr.x() + scr.width())+" "+FToStr(-scr.y())+" l\n";
tmp += FToStr(scr.x() + scr.width())+" "+FToStr(-scr.y() - scr.height())+" l\n";
tmp += FToStr(scr.x())+" "+FToStr(-scr.y() - scr.height())+" l\n";
tmp += "h\nf\n";
tmp += "Q\n";
scr = scrG;
}
oldBack = charStyle.backColor();
oldShade = charStyle.backShade();
}
else
{
if (!scr.isNull())
{
tmp += "q\n";
tmp += colorB;
tmp += FToStr(scr.x()) +" "+FToStr(-scr.y())+" m\n";
tmp += FToStr(scr.x() + scr.width())+" "+FToStr(-scr.y())+" l\n";
tmp += FToStr(scr.x() + scr.width())+" "+FToStr(-scr.y() - scr.height())+" l\n";
tmp += FToStr(scr.x())+" "+FToStr(-scr.y() - scr.height())+" l\n";
tmp += "h\nf\n";
tmp += "Q\n";
}
oldBack = "";
oldShade = 100;
scr = QRectF();
}
CurXB += glyphs->wide();
}
if (!scr.isNull())
{
tmp += "q\n";
tmp += colorB;
tmp += FToStr(scr.x()) +" "+FToStr(-scr.y())+" m\n";
tmp += FToStr(scr.x() + scr.width())+" "+FToStr(-scr.y())+" l\n";
tmp += FToStr(scr.x() + scr.width())+" "+FToStr(-scr.y() - scr.height())+" l\n";
tmp += FToStr(scr.x())+" "+FToStr(-scr.y() - scr.height())+" l\n";
tmp += "h\nf\n";
tmp += "Q\n";
}
for (int d = ls.firstItem; d <= ls.lastItem; ++d)
{
GlyphLayout* glyphs = ite->itemText.getGlyphs(d);
PathData* pdata = &straightPath;
const QChar ch = ite->itemText.text(d);
const CharStyle& chstyle(ite->itemText.charStyle(d));
const ParagraphStyle& pstyle(ite->itemText.paragraphStyle(d));
if (SpecialChars::isBreak(ch, true) || (ch == QChar(10)))
continue;
if (ite->itemText.hasFlag(d, ScLayout_SuppressSpace))
continue;
tTabValues = pstyle.tabValues();
if (ite->itemText.hasFlag(d, ScLayout_StartOfLine))
tabCc = 0;
if ((ch == SpecialChars::TAB) && (tTabValues.count() != 0))
{
QChar tabFillChar;
const TabLayout* tabLayout = dynamic_cast<const TabLayout*>(glyphs->more);
if (tabLayout)
tabFillChar = tabLayout->fillChar;
if (!tabFillChar.isNull())
{
GlyphLayout gl2;
CharStyle cl2(chstyle);
const GlyphLayout * const gl = glyphs->more;
double scale = gl ? gl->scaleV : 1.0;
double wt = chstyle.font().charWidth(tabFillChar, chstyle.fontSize() * scale / 10.0);
double len = glyphs->xadvance;
int coun = static_cast<int>(len / wt);
// #6728 : update code according to fillInTabLeaders() and PageItem::layout() - JG
double sPos = 0.0 /*CurX - len + chstyle.fontSize() / 10.0 * 0.7 + 1*/;
//hl2.ch = tTabValues[tabCc].tabFillChar;
cl2.setTracking(0);
cl2.setScaleH(1000);
cl2.setScaleV(1000);
gl2.glyph = chstyle.font().char2CMap(tabFillChar);
gl2.yoffset = glyphs->yoffset;
for (int cx = 0; cx < coun; ++cx)
{
gl2.xoffset = sPos + wt * cx;
if ((chstyle.effects() & ScStyle_Shadowed) && (chstyle.strokeColor() != CommonStrings::None))
{
GlyphLayout gl3;
CharStyle cl3(cl2);
//<< HACK to fix Bug #8446
cl3.setEffects(cl3.effects() & (~(ScStyle_Outline)));
//>>
gl3.glyph = gl2.glyph;
cl3.setFillColor(cl2.strokeColor());
cl3.setFillShade(cl2.strokeShade());
gl3.yoffset = gl2.yoffset - (chstyle.fontSize() * chstyle.shadowYOffset() / 10000.0);
gl3.xoffset = gl2.xoffset + (chstyle.fontSize() * chstyle.shadowXOffset() / 10000.0);
setTextCh(ite, PNr, CurX, ls.y, d, tmp, tmp2, cl3, &gl3, pdata, pstyle, pag);
}
setTextCh(ite, PNr, CurX, ls.y, d, tmp, tmp2, cl2, &gl2, pdata, pstyle, pag);
}
}
tabCc++;
}
if (ch == SpecialChars::TAB)
{
CurX += glyphs->wide();
continue;
}
if ((chstyle.effects() & ScStyle_Shadowed) && (chstyle.strokeColor() != CommonStrings::None))
{
GlyphLayout gl2(*glyphs);
gl2.glyph = glyphs->glyph;
const GlyphLayout *gl1 = glyphs;
GlyphLayout* glx = &gl2;
while (gl1->more)
{
glx->more = new GlyphLayout(*gl1->more);
glx->more->yoffset -= (chstyle.fontSize() * chstyle.shadowYOffset() / 10000.0);
glx->more->xoffset += (chstyle.fontSize() * chstyle.shadowXOffset() / 10000.0);
glx->more->more = NULL;
gl1 = gl1->more;
glx = glx->more;
}
CharStyle cl2(chstyle);
//<< HACK to fix Bug #8446
cl2.setEffects(cl2.effects() & (~(ScStyle_Outline)));
//>>
cl2.setFillColor(chstyle.strokeColor());
cl2.setFillShade(chstyle.strokeShade());
gl2.xadvance = glyphs->xadvance;
gl2.yadvance = glyphs->yadvance;
gl2.yoffset = glyphs->yoffset - (chstyle.fontSize() * chstyle.shadowYOffset() / 10000.0);
gl2.xoffset = glyphs->xoffset + (chstyle.fontSize() * chstyle.shadowXOffset() / 10000.0);
gl2.scaleH = glyphs->scaleH;
gl2.scaleV = glyphs->scaleV;
setTextCh(ite, PNr, CurX, ls.y, d, tmp, tmp2, cl2, &gl2, pdata, pstyle, pag);
gl2.shrink();
}
setTextCh(ite, PNr, CurX, ls.y, d, tmp, tmp2, chstyle, glyphs, pdata, pstyle, pag);
// Unneeded now that glyph xadvance is set appropriately for inline objects by PageItem_TextFrame::layout() - JG
/*if (hl->ch == SpecialChars::OBJECT)
{
InlineFrame& embedded(const_cast<InlineFrame&>(hl->embedded));
CurX += (embedded.getItem()->gWidth + embedded.getItem()->lineWidth()) * hl->glyph.scaleH;
}
else*/
CurX += glyphs->wide();
tabDist = CurX;
}
}
}
else
{
ite->OwnPage = PNr;
ite->asPathText()->layout();
ite->OwnPage = savedOwnPage;
double CurX = 0;
for (int d = 0; d < ite->maxCharsInFrame(); ++d)
{
GlyphLayout* glyphs = ite->asPathText()->itemRenderText.getGlyphs(d);
PathData* pdata = &ite->textLayout.point(d);
const QChar ch = ite->asPathText()->itemRenderText.text(d);
const CharStyle& chstyle(ite->asPathText()->itemRenderText.charStyle(d));
const ParagraphStyle& pstyle(ite->asPathText()->itemRenderText.paragraphStyle(d));
if (SpecialChars::isBreak(ch, true) || (ch == QChar(10)))
continue;
if (ite->asPathText()->itemRenderText.hasFlag(d, ScLayout_SuppressSpace))
continue;
tTabValues = pstyle.tabValues();
if (ite->asPathText()->itemRenderText.hasFlag(d, ScLayout_StartOfLine))
tabCc = 0;
if ((ch == SpecialChars::TAB) && (tTabValues.count() != 0))
{
if ((tabCc < tTabValues.count()) && (!tTabValues[tabCc].tabFillChar.isNull()))
{
GlyphLayout gl2;
CharStyle cl2(chstyle);
double wt = chstyle.font().charWidth(tTabValues[tabCc].tabFillChar, chstyle.fontSize());
int coun = static_cast<int>((CurX+ glyphs->xoffset - tabDist) / wt);
// #6728 : update code according to fillInTabLeaders() and PageItem::layout() - JG
double sPos = 0.0 /* CurX+hl->glyph.xoffset - (CurX+hl->glyph.xoffset - tabDist) + 1 */;
gl2.glyph = chstyle.font().char2CMap(tTabValues[tabCc].tabFillChar);
cl2.setTracking(0);
cl2.setScaleH(1000);
cl2.setScaleV(1000);
gl2.yoffset = glyphs->yoffset;
for (int cx = 0; cx < coun; ++cx)
{
glyphs->xoffset = sPos + wt * cx;
if ((chstyle.effects() & ScStyle_Shadowed) && (chstyle.strokeColor() != CommonStrings::None))
{
GlyphLayout gl3;
CharStyle cl3(cl2);
//<< HACK to fix Bug #8446
cl3.setEffects(cl3.effects() & (~(ScStyle_Outline)));
//>>
gl3.glyph = gl2.glyph;
cl3.setFillColor(cl2.strokeColor());
cl3.setFillShade(cl2.strokeShade());
gl3.yoffset = gl2.yoffset - (chstyle.fontSize() * chstyle.shadowYOffset() / 10000.0);
gl3.xoffset = gl2.xoffset + (chstyle.fontSize() * chstyle.shadowXOffset() / 10000.0);
setTextCh(ite, PNr, 0, 0, d, tmp, tmp2, cl3, &gl3, pdata, pstyle, pag);
}
setTextCh(ite, PNr, 0, 0, d, tmp, tmp2, cl2, &gl2, pdata, pstyle, pag);
}
tabCc++;
}
else
{
tabCc++;
}
}
if (ch == SpecialChars::TAB)
{
CurX += glyphs->wide();
continue;
}
if ((chstyle.effects() & ScStyle_Shadowed) && (chstyle.strokeColor() != CommonStrings::None))
{
GlyphLayout gl2;
gl2.glyph = glyphs->glyph;
CharStyle cl2(chstyle);
//<< HACK to fix Bug #8446
cl2.setEffects(cl2.effects() & (~(ScStyle_Outline)));
//>>
cl2.setFillColor(chstyle.strokeColor());
cl2.setFillShade(chstyle.strokeShade());
gl2.yoffset = glyphs->yoffset - (chstyle.fontSize() * chstyle.shadowYOffset() / 10000.0);
gl2.xoffset = glyphs->xoffset + (chstyle.fontSize() * chstyle.shadowXOffset() / 10000.0);
gl2.scaleH = glyphs->scaleH;
gl2.scaleV = glyphs->scaleV;
setTextCh(ite, PNr, 0, 0, d, tmp, tmp2, cl2, &gl2, pdata, pstyle, pag);
}
setTextCh(ite, PNr, 0, 0, d, tmp, tmp2, chstyle, glyphs, pdata, pstyle, pag);
CurX += glyphs->wide();
tabDist = CurX;
}
}
if (ite->itemType() == PageItem::TextFrame)
tmp += "ET\n"+tmp2;
return tmp;
PdfPainter p(ite, this, PNr, pag);
ite->textLayout.renderBackground(&p);
ite->textLayout.render(&p);
return p.getBuffer();
}
 
bool PDFLibCore::setTextCh(PageItem *ite, uint PNr, double x, double y, uint d, QByteArray &tmp, QByteArray &tmp2, const CharStyle& style, GlyphLayout *glyphs, PathData* pdata, const ParagraphStyle& pstyle, const ScPage* pag)
{
QByteArray output;
QByteArray FillColor = "";
QByteArray StrokeColor = "";
if (ite->asPathText())
{
tmp += "q\n";
QPointF tangt = QPointF( cos(pdata->PRot), sin(pdata->PRot) );
QTransform trafo = QTransform( 1, 0, 0, -1, -pdata->PDx, 0 );
if (ite->textPathFlipped)
trafo *= QTransform(1, 0, 0, -1, 0, 0);
if (ite->textPathType == 0)
trafo *= QTransform( tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), pdata->PtransX, -pdata->PtransY );
else if (ite->textPathType == 1)
trafo *= QTransform(1, 0, 0, -1, pdata->PtransX, -pdata->PtransY );
else if (ite->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x() < 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
trafo *= QTransform( a, (tangt.y() / tangt.x()) * b, 0, -1, pdata->PtransX, -pdata->PtransY ); // ID's Skew mode
else
trafo *= QTransform( a, 6 * b, 0, -1, pdata->PtransX, -pdata->PtransY );
}
tmp += FToStr(trafo.m11())+" "+FToStr(trafo.m12())+" "+FToStr(trafo.m21())+" "+FToStr(trafo.m22())+" "+FToStr(trafo.dx())+" "+FToStr(trafo.dy())+" cm\n";
if (ite->BaseOffs != 0)
tmp += "1 0 0 1 0 "+ FToStr( -ite->BaseOffs)+" cm\n";
if (glyphs->xoffset != 0.0 || glyphs->yoffset != 0.0)
tmp += "1 0 0 1 " + FToStr( glyphs->xoffset)+ " " + FToStr( -glyphs->yoffset)+" cm\n";
if (ite->itemText.text(d) != SpecialChars::OBJECT)
tmp += "BT\n";
}
QChar chstr = ite->itemText.text(d);
double tsz = style.fontSize();
 
/* if (hl->effects() & ScStyle_DropCap)
{
if (pstyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
tsz = qRound(10 * ((doc.typographicSettings.valueBaseGrid * (pstyle.dropCapLines()-1)+(hl->font().ascent(pstyle.charStyle().fontSize() / 10.0))) / (hl->font().realCharHeight(chstr, 10))));
else
{
if (pstyle.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
tsz = qRound(10 * ((pstyle.lineSpacing() * (pstyle.dropCapLines()-1)+(hl->font().ascent(pstyle.charStyle().fontSize() / 10.0))) / (hl->font().realCharHeight(chstr, 10))));
else
{
double currasce = hl->font().height(pstyle.charStyle().fontSize());
tsz = qRound(10 * ((currasce * (pstyle.dropCapLines()-1)+(hl->font().ascent(pstyle.charStyle().fontSize() / 10.0))) / hl->font().realCharHeight(chstr, 10)));
}
}
}
*/
if (ite->itemText.hasObject(d))
{
if (!ite->asPathText())
{
tmp += "ET\n"+tmp2;
tmp2 = "";
}
PageItem* embedded = ite->itemText.object(d);
tmp2 += "q\n";
if (ite->asPathText())
tmp2 += FToStr(style.scaleH() / 1000.0)+" 0 0 "+FToStr(style.scaleV() / 1000.0)+" "+FToStr(embedded->gXpos * (style.scaleH() / 1000.0))+" "+FToStr((embedded->height() * (style.scaleV() / 1000.0)) - embedded->gYpos * (style.scaleV() / 1000.0)+embedded->gHeight * (style.baselineOffset() / 1000.0))+" cm\n";
else
{
if (d == 0 || ite->itemText.text(d-1) == SpecialChars::PARSEP)
{
if ((style.baselineOffset() != 0) && (!pstyle.hasDropCap()))
tmp2 += FToStr(style.scaleH() / 1000.0)+" 0 0 "+FToStr(style.scaleV() / 1000.0)+" "+FToStr(x + glyphs->xoffset + embedded->gXpos * (style.scaleH() / 1000.0))+" "+FToStr(-y- glyphs->yoffset + (embedded->height() * (style.scaleV() / 1000.0)) - embedded->gYpos * (style.scaleV() / 1000.0)+embedded->height() * (style.baselineOffset() / 1000.0))+" cm\n";
else
tmp2 += FToStr(style.scaleH() / 1000.0)+" 0 0 "+FToStr(style.scaleV() / 1000.0)+" "+FToStr(x+ glyphs->xoffset + embedded->gXpos * (style.scaleH() / 1000.0))+" "+FToStr(-y- glyphs->yoffset + (embedded->height() * (style.scaleV() / 1000.0)) - embedded->gYpos * (style.scaleV() / 1000.0))+" cm\n";
}
else
{
if (style.baselineOffset() != 0)
tmp2 += FToStr(style.scaleH() / 1000.0)+" 0 0 "+FToStr(style.scaleV() / 1000.0)+" "+FToStr(x+ glyphs->xoffset + embedded->gXpos * (style.scaleH() / 1000.0))+" "+FToStr(-y- glyphs->yoffset + (embedded->height() * (style.scaleV() / 1000.0)) - embedded->gYpos * (style.scaleV() / 1000.0)+embedded->height() * (style.baselineOffset() / 1000.0))+" cm\n";
else
tmp2 += FToStr(style.scaleH() / 1000.0)+" 0 0 "+FToStr(style.scaleV() / 1000.0)+" "+FToStr(x+ glyphs->xoffset + embedded->gXpos * (style.scaleH() / 1000.0))+" "+FToStr(-y- glyphs->yoffset + (embedded->height() * (style.scaleV() / 1000.0)) - embedded->gYpos * (style.scaleV() / 1000.0))+" cm\n";
}
}
if (!PDF_ProcessItem(output, embedded, pag, PNr, true))
return false;
tmp2 +=output;
tmp2 += "Q\n";
tmp += tmp2+"\n";
tmp2 = "";
if (ite->asPathText())
tmp += "Q\n";
else
tmp += "BT\n";
return true;
}
 
PdfFont pdfFont = UsedFontsP[style.font().replacementName()];
uint glyph = glyphs->glyph;
 
if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode()) ||
glyph == (ScFace::CONTROL_GLYPHS + 32))
{
glyph = style.font().char2CMap(QChar(' '));
chstr = ' ';
}
else if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode()))
{
glyph = style.font().char2CMap(QChar('-'));
chstr = '-';
}
 
if (glyph < ScFace::CONTROL_GLYPHS)
{
if (style.strokeColor() != CommonStrings::None)
{
StrokeColor = "";
StrokeColor += putColor(style.strokeColor(), style.strokeShade(), false);
}
if (style.fillColor() != CommonStrings::None)
{
FillColor = "";
FillColor += putColor(style.fillColor(), style.fillShade(), true);
}
if (((style.effects() & ScStyle_Underline) && (chstr != SpecialChars::PARSEP)) || ((style.effects() & ScStyle_UnderlineWords) && (!chstr.isSpace())))
{
// double Ulen = style.font().charWidth(chstr, style.fontSize()) * (hl->glyph.scaleH);
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
{
if (style.underlineOffset() != -1)
Upos = (style.underlineOffset() / 1000.0) * (style.font().descent(style.fontSize() / 10.0));
else
Upos = style.font().underlinePos(style.fontSize() / 10.0);
if (style.underlineWidth() != -1)
Uwid = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().underlinePos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
tmp2 += putColor(style.fillColor(), style.fillShade(), false);
tmp2 += FToStr(Uwid)+" w\n";
if (ite->itemType() == PageItem::PathText)
{
if (style.effects() & ScStyle_Subscript)
{
tmp2 += FToStr(x+ glyphs->xoffset) +" "+FToStr(-y+Upos)+" m\n";
tmp2 += FToStr(x+ glyphs->xoffset+Ulen)+" "+FToStr(-y+Upos)+" l\n";
}
else
{
tmp2 += FToStr(x+ glyphs->xoffset) +" "+FToStr(-y+ glyphs->yoffset+Upos)+" m\n";
tmp2 += FToStr(x+ glyphs->xoffset+Ulen)+" "+FToStr(-y+ glyphs->yoffset+Upos)+" l\n";
}
}
else
{
if (style.effects() & ScStyle_Subscript)
{
tmp2 += FToStr(x+ glyphs->xoffset) +" "+FToStr(-y- glyphs->yoffset+Upos)+" m\n";
tmp2 += FToStr(x+ glyphs->xoffset+Ulen)+" "+FToStr(-y- glyphs->yoffset+Upos)+" l\n";
}
else
{
tmp2 += FToStr(x+ glyphs->xoffset) +" "+FToStr(-y+Upos)+" m\n";
tmp2 += FToStr(x+ glyphs->xoffset+Ulen)+" "+FToStr(-y+Upos)+" l\n";
}
}
tmp2 += "S\n";
}
if (pdfFont.method == Use_XForm)
{
if (glyph != style.font().char2CMap(QChar(' ')))
{
if ((style.strokeColor() != CommonStrings::None) && (style.effects() & ScStyle_Outline))
{
tmp2 += FToStr((tsz * style.outlineWidth() / 1000.0) / tsz)+" w\n[] 0 d\n0 J\n0 j\n";
tmp2 += StrokeColor;
}
if (style.fillColor() != CommonStrings::None)
tmp2 += FillColor;
tmp2 += "q\n";
// #see 8257 : transform is already computed at beginning of the function
/*if (ite->itemType() == PageItem::PathText)
{
QPointF tangt = QPointF( cos(hl->PRot), sin(hl->PRot) );
QTransform trafo = QTransform( 1, 0, 0, -1, -hl->PDx, 0 );
if (ite->textPathFlipped)
trafo *= QTransform(1, 0, 0, -1, 0, 0);
if (ite->textPathType == 0)
trafo *= QTransform(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), hl->PtransX, -hl->PtransY);
else if (ite->textPathType == 1)
trafo *= QTransform(1, 0, 0, -1, hl->PtransX, -hl->PtransY );
tmp2 += FToStr(trafo.m11())+" "+FToStr(trafo.m12())+" "+FToStr(trafo.m21())+" "+FToStr(trafo.m22())+" "+FToStr(trafo.dx())+" "+FToStr(trafo.dy())+" cm\n";
}*/
if (!ite->asPathText())
{
if (ite->reversed())
{
double wid = style.font().charWidth(chstr, style.fontSize()) * (glyphs->scaleH);
tmp2 += "1 0 0 1 "+FToStr(x+ glyphs->xoffset)+" "+FToStr((y+ glyphs->yoffset - (tsz / 10.0)) * -1 + ((tsz / 10.0) * (style.baselineOffset() / 1000.0)))+" cm\n";
tmp2 += "-1 0 0 1 0 0 cm\n";
tmp2 += "1 0 0 1 "+FToStr(-wid)+" 0 cm\n";
tmp2 += FToStr(tsz / 10.0)+" 0 0 "+FToStr(tsz / 10.0)+" 0 0 cm\n";
}
else
{
tmp2 += FToStr(tsz / 10.0)+" 0 0 "+FToStr(tsz / 10.0)+" "+FToStr(x+ glyphs->xoffset)+" "+FToStr((y+ glyphs->yoffset - (tsz / 10.0)) * -1 + ((tsz / 10.0) * (style.baselineOffset() / 1000.0)))+" cm\n";
}
}
else
{
// if (ite->BaseOffs != 0)
// tmp2 += "1 0 0 1 0 "+FToStr( -ite->BaseOffs)+" cm\n";
tmp2 += FToStr(tsz / 10.0)+" 0 0 "+FToStr(tsz / 10.0)+" 0 "+FToStr(tsz / 10.0)+" cm\n";
}
if (glyphs->scaleV != 1.0)
tmp2 += "1 0 0 1 0 "+FToStr( (((tsz / 10.0) - (tsz / 10.0) * (glyphs->scaleV)) / (tsz / 10.0)) * -1)+" cm\n";
tmp2 += FToStr(qMax(glyphs->scaleH, 0.1))+" 0 0 "+FToStr(qMax(glyphs->scaleV, 0.1))+" 0 0 cm\n";
if (style.fillColor() != CommonStrings::None)
tmp2 += pdfFont.name + Pdf::toPdf(glyph)+" Do\n";
if (style.effects() & ScStyle_Outline)
{
FPointArray gly = style.font().glyphOutline(glyph);
QTransform mat;
mat.scale(0.1, 0.1);
gly.map(mat);
bool nPath = true;
FPoint np;
if (gly.size() > 3)
{
for (int poi=0; poi<gly.size()-3; poi += 4)
{
if (gly.isMarker(poi))
{
tmp2 += "h\n";
nPath = true;
continue;
}
if (nPath)
{
np = gly.point(poi);
tmp2 += FToStr(np.x())+" "+FToStr(-np.y())+" m\n";
nPath = false;
}
np = gly.point(poi+1);
tmp2 += FToStr(np.x())+" "+FToStr(-np.y())+" ";
np = gly.point(poi+3);
tmp2 += FToStr(np.x())+" "+FToStr(-np.y())+" ";
np = gly.point(poi+2);
tmp2 += FToStr(np.x())+" "+FToStr(-np.y())+" c\n";
}
}
tmp2 += "h s\n";
}
tmp2 += "Q\n";
}
}
else
{
if (style.strokeColor() != CommonStrings::None)
{
if ((style.effects() & ScStyle_Underline) || (style.effects() & ScStyle_Strikethrough) || (style.effects() & ScStyle_Outline))
tmp2 += StrokeColor;
}
if (style.fillColor() != CommonStrings::None)
{
if ((style.effects() & ScStyle_Underline) || (style.effects() & ScStyle_Strikethrough))
tmp2 += FillColor;
}
if (glyph != style.font().char2CMap(QChar(' ')))
{
uint gid = glyphs->glyph;
uint fontNr = 65535;
switch (pdfFont.encoding)
{
case Encode_256:
gid = pdfFont.glyphmap[gid];
fontNr = gid / 256;
gid = gid % 256;
break;
case Encode_224:
fontNr = gid / 224;
gid = gid % 224 + 32;
break;
case Encode_Subset:
gid = pdfFont.glyphmap[gid];
break;
case Encode_IdentityH:
break;
}
if (fontNr == 65535)
tmp+= pdfFont.name + " " + FToStr(tsz / 10.0)+" Tf\n";
else
tmp += pdfFont.name+"S"+Pdf::toPdf(fontNr) + " "+FToStr(tsz / 10.0)+" Tf\n";
if (style.strokeColor() != CommonStrings::None)
tmp += StrokeColor;
if (style.fillColor() != CommonStrings::None)
tmp += FillColor;
if (pdfFont.method == Use_Type3 && (style.effects() & ScStyle_Outline) && (style.strokeColor() != CommonStrings::None))
{
tmp2 += "q\n";
tmp2 += FToStr((tsz * style.outlineWidth() / 1000.0) / tsz)+" w\n[] 0 d\n0 J\n0 j\n";
// #see 8257 : transform is already computed at beginning of the function
/*if (ite->itemType() == PageItem::PathText)
{
QPointF tangt = QPointF( cos(hl->PRot), sin(hl->PRot) );
QTransform trafo = QTransform( 1, 0, 0, -1, -hl->PDx, 0 );
if (ite->textPathFlipped)
trafo *= QTransform(1, 0, 0, -1, 0, 0);
if (ite->textPathType == 0)
trafo *= QTransform(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), hl->PtransX, -hl->PtransY);
else if (ite->textPathType == 1)
trafo *= QTransform(1, 0, 0, -1, hl->PtransX, -hl->PtransY );
tmp2 += FToStr(trafo.m11())+" "+FToStr(trafo.m12())+" "+FToStr(trafo.m21())+" "+FToStr(trafo.m22())+" "+FToStr(trafo.dx())+" "+FToStr(trafo.dy())+" cm\n";
}*/
if (!ite->asPathText())
{
if (ite->reversed())
{
double wid = style.font().charWidth(chstr, style.fontSize()) * (glyphs->scaleH);
tmp2 += "1 0 0 1 "+FToStr(x+ glyphs->xoffset)+" "+FToStr((y+ glyphs->yoffset - (tsz / 10.0)) * -1 + ((tsz / 10.0) * (style.baselineOffset() / 1000.0)))+" cm\n";
tmp2 += "-1 0 0 1 0 0 cm\n";
tmp2 += "1 0 0 1 "+FToStr(-wid)+" 0 cm\n";
tmp2 += FToStr(tsz / 10.0)+" 0 0 "+FToStr(tsz / 10.0)+" 0 0 cm\n";
}
else
{
tmp2 += FToStr(tsz / 10.0)+" 0 0 "+FToStr(tsz / 10.0)+" "+FToStr(x+ glyphs->xoffset)+" "+FToStr((y+ glyphs->yoffset - (tsz / 10.0)) * -1 + ((tsz / 10.0) * (style.baselineOffset() / 1000.0)))+" cm\n";
}
}
else
{
tmp2 += FToStr(tsz / 10.0)+" 0 0 "+FToStr(tsz / 10.0)+" 0 "+FToStr(tsz / 10.0)+" cm\n";
}
if (glyphs->scaleV != 1.0)
tmp2 += "1 0 0 1 0 "+FToStr( (((tsz / 10.0) - (tsz / 10.0) * (glyphs->scaleV)) / (tsz / 10.0)) * -1)+" cm\n";
tmp2 += FToStr(qMax(glyphs->scaleH, 0.1))+" 0 0 "+FToStr(qMax(glyphs->scaleV, 0.1))+" 0 0 cm\n";
/* paint outline */
FPointArray gly = style.font().glyphOutline(glyph);
QTransform mat;
mat.scale(0.1, 0.1);
gly.map(mat);
bool nPath = true;
FPoint np;
if (gly.size() > 3)
{
for (int poi=0; poi<gly.size()-3; poi += 4)
{
if (gly.isMarker(poi))
{
tmp2 += "h\n";
nPath = true;
continue;
}
if (nPath)
{
np = gly.point(poi);
tmp2 += FToStr(np.x())+" "+FToStr(-np.y())+" m\n";
nPath = false;
}
np = gly.point(poi+1);
tmp2 += FToStr(np.x())+" "+FToStr(-np.y())+" ";
np = gly.point(poi+3);
tmp2 += FToStr(np.x())+" "+FToStr(-np.y())+" ";
np = gly.point(poi+2);
tmp2 += FToStr(np.x())+" "+FToStr(-np.y())+" c\n";
}
}
tmp2 += "h s\n";
tmp2 += "Q\n";
}
else
{
if (style.effects() & ScStyle_Outline)
tmp += FToStr(tsz * style.outlineWidth() / 10000.0) + (style.fillColor() != CommonStrings::None ? " w 2 Tr\n" : " w 1 Tr\n");
else
tmp += "0 Tr\n";
}
if (!ite->asPathText())
{
if (ite->reversed())
{
double wtr = glyphs->xadvance;
tmp += FToStr(-qMax(glyphs->scaleH, 0.1))+" 0 0 "+FToStr(qMax(glyphs->scaleV, 0.1)) +" "+FToStr(x+ glyphs->xoffset+wtr)+" "+FToStr(-y- glyphs->yoffset+(style.fontSize() / 10.0) * (style.baselineOffset() / 1000.0))+" Tm\n";
}
else
tmp += FToStr(qMax(glyphs->scaleH, 0.1))+" 0 0 "+FToStr(qMax(glyphs->scaleV, 0.1))+" "+FToStr(x+ glyphs->xoffset)+" "+FToStr(-y- glyphs->yoffset+(style.fontSize() / 10.0) * (style.baselineOffset() / 1000.0))+" Tm\n";
}
else
{
tmp += FToStr(qMax(glyphs->scaleH, 0.1))+" 0 0 "+FToStr(qMax(glyphs->scaleV, 0.1))+" 0 0 Tm\n";
}
if (pdfFont.method != Use_Type3 || style.fillColor() != CommonStrings::None)
{
switch (pdfFont.encoding)
{
case Encode_224:
case Encode_256:
tmp += Pdf::toHexString8(gid) + " Tj\n";
break;
case Encode_IdentityH:
default:
tmp += Pdf::toHexString16(gid) + " Tj\n";
break;
}
}
}
}
if ((style.effects() & ScStyle_Strikethrough) && (chstr != SpecialChars::PARSEP))
{
// double Ulen = style.font().charWidth(chstr, style.fontSize()) * (hl->glyph.scaleH);
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
{
if (style.strikethruOffset() != -1)
Upos = (style.strikethruOffset() / 1000.0) * (style.font().ascent(style.fontSize() / 10.0));
else
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
if (style.strikethruWidth() != -1)
Uwid = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
tmp2 += putColor(style.fillColor(), style.fillShade(), false);
tmp2 += FToStr(Uwid)+" w\n";
if (ite->itemType() == PageItem::PathText)
{
tmp2 += FToStr(x+ glyphs->xoffset) +" "+FToStr(-y+Upos)+" m\n";
tmp2 += FToStr(x+ glyphs->xoffset+Ulen)+" "+FToStr(-y+Upos)+" l\n";
}
else
{
tmp2 += FToStr(x+ glyphs->xoffset) +" "+FToStr(-y- glyphs->yoffset+Upos)+" m\n";
tmp2 += FToStr(x+ glyphs->xoffset+Ulen)+" "+FToStr(-y- glyphs->yoffset+Upos)+" l\n";
}
tmp2 += "S\n";
}
if (ite->asPathText())
{
tmp += "ET\n"+tmp2+"Q\n";
tmp2 = "";
}
}
if (glyphs->more) {
// // ugly hack until setTextCh interface is changed
// ScText hl2(*hl);
// hl2.glyph = *(hl->glyph.more);
if (!setTextCh(ite, PNr, x + glyphs->xadvance, y, d, tmp, tmp2, style, glyphs->more, pdata, pstyle, pag))
return false;
// // don't let hl2's destructor delete these!
// hl2.glyph.more = 0;
}
return true;
}
 
QByteArray PDFLibCore::SetColor(const QString& farbe, double Shade)
{
const ScColor& col = doc.PageColors[farbe];
/trunk/Scribus/scribus/pdflib_core.h
43,6 → 43,8
 
#include "pdfwriter.h"
 
class PdfPainter;
 
/**
* PDFLibCore provides Scribus's implementation of PDF export functionality.
*
59,6 → 61,8
{
Q_OBJECT
 
friend class PdfPainter;
 
public:
explicit PDFLibCore(ScribusDoc & docu);
~PDFLibCore();
171,7 → 175,6
QByteArray Write_FormXObject(QByteArray &data, PageItem *controlItem = 0);
QByteArray Write_TransparencyGroup(double trans, int blend, QByteArray &data, PageItem *controlItem = 0);
QByteArray setTextSt(PageItem *ite, uint PNr, const ScPage* pag);
bool setTextCh(PageItem *ite, uint PNr, double x, double y, uint d, QByteArray &tmp, QByteArray &tmp2, const CharStyle& cstyle, GlyphLayout *glyphs, PathData* pdata, const ParagraphStyle& pstyle, const ScPage* pag);
void getBleeds(const ScPage* page, double &left, double &right);
void getBleeds(const ScPage* page, double &left, double &right, double &bottom, double& top);
 
/trunk/Scribus/scribus/plugins/export/svgexplugin/svgexplugin.cpp
55,6 → 55,9
#include "sccolorengine.h"
#include "util_formats.h"
#include "util_math.h"
#include "text/textlayout.h"
#include "text/textlayoutpainter.h"
#include "text/boxes.h"
 
int svgexplugin_getPluginAPIVersion()
{
368,11 → 371,9
ob = processImageItem(Item, trans, fill, stroke);
break;
case PageItem::TextFrame:
case PageItem::PathText:
ob = processTextItem(Item, trans, fill, stroke);
break;
case PageItem::PathText:
ob = processPathTextItem(Item, trans, stroke);
break;
case PageItem::Symbol:
ob = processSymbolItem(Item, trans);
break;
1144,6 → 1145,97
return ob;
}
 
class SvgPainter: public TextLayoutPainter
{
QDomElement m_elem;
SVGExPlug *m_svg;
QString m_trans;
 
public:
SvgPainter(QString trans, SVGExPlug *svg, QDomElement &elem)
: m_elem(elem)
, m_svg(svg)
, m_trans(trans)
{}
 
void drawGlyph(const GlyphLayout gl)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
QTransform transform = matrix();
transform.translate(x(), y() - (fontSize() * gl.scaleV));
transform.scale(gl.scaleH * fontSize() / 10.0, gl.scaleV * fontSize() / 10.0);
 
QDomElement glyph = m_svg->docu.createElement("use");
glyph.setAttribute("xlink:href", "#" + m_svg->handleGlyph(gl.glyph, font()));
glyph.setAttribute("transform", m_svg->MatrixToStr(transform));
QString fill = "fill:" + m_svg->SetColor(fillColor().color, fillColor().shade) + ";";
QString stroke = "stroke:none;";
glyph.setAttribute("style", fill + stroke);
m_elem.appendChild(glyph);
}
 
void drawGlyphOutline(const GlyphLayout gl, bool hasFill)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
QTransform transform = matrix();
transform.translate(x(), y() - (fontSize() * gl.scaleV));
transform.scale(gl.scaleH * fontSize() / 10.0, gl.scaleV * fontSize() / 10.0);
QDomElement glyph = m_svg->docu.createElement("use");
glyph.setAttribute("xlink:href", "#" + m_svg->handleGlyph(gl.glyph, font()));
glyph.setAttribute("transform", m_svg->MatrixToStr(transform));
QString fill = "fill:none;";
if (hasFill)
fill = "fill:" + m_svg->SetColor(fillColor().color, fillColor().shade) + ";";
QString stroke ="stroke:" + m_svg->SetColor(strokeColor().color, strokeColor().shade) + ";";
stroke += " stroke-width:" + m_svg->FToStr(strokeWidth()) + ";";
glyph.setAttribute("style", fill + stroke);
m_elem.appendChild(glyph);
}
 
void drawLine(QPointF start, QPointF end)
{
QTransform transform = matrix();
transform.translate(x(), y());
QDomElement path = m_svg-> docu.createElement("path");
path.setAttribute("d", QString("M %1 %2 L%3 %4").arg(start.x()).arg(start.y()).arg(end.x()).arg(end.y()));
QString stroke = "stroke:none;";
if (fillColor().color != CommonStrings::None)
{
stroke = "stroke:" + m_svg->SetColor(fillColor().color, fillColor().shade) + ";";
stroke += " stroke-width:" + m_svg->FToStr(strokeWidth()) + ";";
}
path.setAttribute("style", "fill:none;" + stroke);
path.setAttribute("transform", m_svg->MatrixToStr(transform));
m_elem.appendChild(path);
}
 
void drawRect(QRectF rect)
{
QTransform transform = matrix();
transform.translate(x(), y());
QString paS = QString("M %1 %2 ").arg(rect.x()).arg(rect.y());
paS += QString("L %1 %2 ").arg(rect.x() + rect.width()).arg(rect.y());
paS += QString("L %1 %2 ").arg(rect.x() + rect.width()).arg(rect.y() + rect.height());
paS += QString("L %1 %2 ").arg(rect.x()).arg(rect.y() + rect.height());
paS += "Z";
QDomElement path = m_svg-> docu.createElement("path");
path.setAttribute("d", paS);
path.setAttribute("transform", m_svg->MatrixToStr(transform));
path.setAttribute("style", "fill:" + m_svg->SetColor(fillColor().color, fillColor().shade) + ";" + "stroke:none;");
m_elem.appendChild(path);
}
 
void drawObject(PageItem* item)
{
QDomElement layerGroup = m_svg->processInlineItem(item, m_trans, scaleH(), scaleV());
m_elem.appendChild(layerGroup);
}
};
 
QDomElement SVGExPlug::processTextItem(PageItem *Item, QString trans, QString fill, QString stroke)
{
QDomElement ob;
1168,14 → 1260,6
}
}
bool bFound = false;
for (uint ll=0; ll < Item->textLayout.lines(); ++ll)
{
if (Item->itemText.paragraphStyle(Item->textLayout.line(ll).firstItem).backgroundColor() != CommonStrings::None)
{
bFound = true;
break;
}
}
if (bFound)
{
QDomElement cl;
1188,634 → 1272,14
if (!ob2.isNull())
ob.setAttribute("clip-path", "url(#" + ob2.attribute("id") + ")");
}
double x, y, wide;
QString chstr;
uint llp = 0;
while (llp < Item->textLayout.lines())
{
LineSpec ls = Item->textLayout.line(llp++);
const ParagraphStyle& LineStyle = Item->itemText.paragraphStyle(ls.firstItem);
if (LineStyle.backgroundColor() != CommonStrings::None)
{
double y0 = ls.y;
double y2 = 0;
double ascent = ls.ascent;
double descent = ls.descent;
double rMarg = LineStyle.rightMargin();
double lMarg = ls.colLeft;
double adjX = 0;
if (LineStyle.firstIndent() <= 0)
adjX += LineStyle.leftMargin() + LineStyle.firstIndent();
while (llp < Item->textLayout.lines())
{
ls = Item->textLayout.line(llp);
if ((ls.colLeft > lMarg) || (Item->itemText.paragraphStyle(ls.firstItem) != LineStyle))
{
if (y2 == 0)
y2 = y0;
break;
}
if (Item->itemText.text(ls.lastItem) == SpecialChars::PARSEP)
{
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < Item->textLayout.lines())
{
if ((Item->textLayout.line(llp + 1).lastItem - Item->textLayout.line(llp + 1).firstItem) > 0)
descent += LineStyle.lineSpacing() - (ls.descent + Item->textLayout.line(llp + 1).ascent);
}
llp++;
break;
}
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < Item->textLayout.lines())
descent += LineStyle.lineSpacing() - (ls.descent + Item->textLayout.line(llp + 1).ascent);
llp++;
}
QRectF scr(lMarg + adjX, y0 - ascent, Item->asTextFrame()->columnWidth() - adjX - rMarg, y2 - y0 + descent + ascent);
QString paS = QString("M %1 %2 ").arg(scr.x()).arg(scr.y());
paS += QString("L %1 %2 ").arg(scr.x() + scr.width()).arg(scr.y());
paS += QString("L %1 %2 ").arg(scr.x() + scr.width()).arg(scr.y() + scr.height());
paS += QString("L %1 %2 ").arg(scr.x()).arg(scr.y() + scr.height());
paS += "Z";
QDomElement glyS = docu.createElement("path");
glyS.setAttribute("d", paS);
glyS.setAttribute("style", "fill:"+SetColor(LineStyle.backgroundColor(), LineStyle.backgroundShade())+";" + "stroke:none;");
ob.appendChild(glyS);
}
}
for (uint ll=0; ll < Item->textLayout.lines(); ++ll)
{
LineSpec ls = Item->textLayout.line(ll);
double CurX = ls.x;
 
double CurXB = ls.x;
int last = qMin(ls.lastItem, Item->itemText.length() - 1);
QRectF scr;
QString oldBack = "";
double oldShade = 100;
QString colorB = "";
for (int a = ls.firstItem; a <= last; ++a)
{
const GlyphLayout* glyphs(Item->itemText.getGlyphs(a));
const CharStyle& charStyle(Item->itemText.charStyle(a));
if (charStyle.backColor() != CommonStrings::None)
{
// This code is for rendering character background color.
colorB = SetColor(charStyle.backColor(), charStyle.backShade());
const ParagraphStyle& LineStyle = Item->itemText.paragraphStyle(ls.firstItem);
double y1 = ls.y;
double hl = ls.height;
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
hl = m_Doc->guidesPrefs().valueBaselineGrid;
else if (LineStyle.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
hl = LineStyle.lineSpacing();
if (ls.isFirstLine)
{
if (Item->textLayout.lines() == 1)
hl = ls.ascent + ls.descent;
if (LineStyle.hasDropCap() && (a == ls.firstItem))
hl *= LineStyle.dropCapLines();
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
y1 -= LineStyle.lineSpacing();
else if (Item->firstLineOffset() == FLOPRealGlyphHeight || Item->firstLineOffset() == FLOPFontAscent)
y1 -= ls.ascent;
else
y1 -= LineStyle.lineSpacing();
}
else
y1 -= ls.ascent + (hl - (ls.ascent + ls.descent)) / 2.0;
QRectF scrG;
if (Item->itemText.hasObject(a))
{
PageItem* obj = Item->itemText.object(a);
double ww = (obj->width() + obj->lineWidth()) * glyphs->scaleH;
double hh = (obj->height() + obj->lineWidth()) * glyphs->scaleV;
scrG = QRectF(CurXB, ls.y - hh, ww , hh);
}
else
scrG = QRectF(CurXB, y1, glyphs->wide(), hl);
if ((oldBack == "") || ((oldBack == charStyle.backColor()) && (oldShade == charStyle.backShade())))
scr |= scrG;
else if ((oldBack != charStyle.backColor()) || (oldShade != charStyle.backShade()))
{
QString paS = QString("M %1 %2 ").arg(scr.x()).arg(scr.y());
paS += QString("L %1 %2 ").arg(scr.x() + scr.width()).arg(scr.y());
paS += QString("L %1 %2 ").arg(scr.x() + scr.width()).arg(scr.y() + scr.height());
paS += QString("L %1 %2 ").arg(scr.x()).arg(scr.y() + scr.height());
paS += "Z";
QDomElement glyS = docu.createElement("path");
glyS.setAttribute("d", paS);
glyS.setAttribute("style", "fill:"+SetColor(oldBack, oldShade)+";" + "stroke:none;");
ob.appendChild(glyS);
scr = scrG;
}
oldBack = charStyle.backColor();
oldShade = charStyle.backShade();
// end background code
}
else
{
if (!scr.isNull())
{
QString paS = QString("M %1 %2 ").arg(scr.x()).arg(scr.y());
paS += QString("L %1 %2 ").arg(scr.x() + scr.width()).arg(scr.y());
paS += QString("L %1 %2 ").arg(scr.x() + scr.width()).arg(scr.y() + scr.height());
paS += QString("L %1 %2 ").arg(scr.x()).arg(scr.y() + scr.height());
paS += "Z";
QDomElement glyS = docu.createElement("path");
glyS.setAttribute("d", paS);
glyS.setAttribute("style", "fill:"+colorB+";" + "stroke:none;");
ob.appendChild(glyS);
}
oldBack = "";
oldShade = 100;
scr = QRectF();
}
CurXB += glyphs->wide();
}
if (!scr.isNull())
{
QString paS = QString("M %1 %2 ").arg(scr.x()).arg(scr.y());
paS += QString("L %1 %2 ").arg(scr.x() + scr.width()).arg(scr.y());
paS += QString("L %1 %2 ").arg(scr.x() + scr.width()).arg(scr.y() + scr.height());
paS += QString("L %1 %2 ").arg(scr.x()).arg(scr.y() + scr.height());
paS += "Z";
QDomElement glyS = docu.createElement("path");
glyS.setAttribute("d", paS);
glyS.setAttribute("style", "fill:"+colorB+";" + "stroke:none;");
ob.appendChild(glyS);
}
 
for (int a = ls.firstItem; a <= ls.lastItem; ++a)
{
x = 0.0;
y = 0.0;
//ScText * hl = Item->itemText.item_p(a);
const CharStyle& charStyle(Item->itemText.charStyle(a));
const GlyphLayout* glyphs = Item->itemText.getGlyphs(a);
PageItem* embItem = Item->itemText.hasObject(a)? Item->itemText.object(a) : NULL;
LayoutFlags flags = Item->itemText.flags(a);
chstr = Item->itemText.text(a,1);
if ((chstr == QChar(13)) || (chstr == QChar(29)))
{
if (chstr == QChar(29))
CurX += glyphs->wide();
continue;
}
if (chstr == QChar(30))
{
chstr = Item->ExpandToken(a);
if (chstr == QChar(32))
{
CurX += glyphs->wide();
continue;
}
}
double chs = charStyle.fontSize();
if (charStyle.effects() & ScStyle_SmallCaps)
{
if (chstr.toUpper() != chstr)
{
chs = qMax(static_cast<int>(charStyle.fontSize() * m_Doc->typographicPrefs().valueSmallCaps / 100), 1);
chstr = chstr.toUpper();
}
}
else if (charStyle.effects() & ScStyle_AllCaps)
chstr = chstr.toUpper();
uint chr = chstr[0].unicode();
QTransform chma, chma2, chma3, chma4, chma6;
QTransform trafo = QTransform( 1, 0, 0, 1, CurX, ls.y );
if (Item->rotation() != 0)
{
QTransform sca;
sca.translate(-Item->xPos(), -Item->yPos());
trafo *= sca;
}
chma.scale(glyphs->scaleH * charStyle.fontSize() / 100.00, glyphs->scaleV * charStyle.fontSize() / 100.0);
if (Item->reversed())
{
if (a < Item->itemText.length()-1)
wide = charStyle.font().charWidth(chstr[0], charStyle.fontSize(), Item->itemText.text(a+1));
else
wide = charStyle.font().charWidth(chstr[0], charStyle.fontSize());
chma3.scale(-1, 1);
chma3.translate(-wide, 0);
}
chma4.translate(0, Item->BaseOffs - (charStyle.fontSize() / 10.0) * glyphs->scaleV);
if (charStyle.effects() & (ScStyle_Subscript | ScStyle_Superscript | ScLayout_DropCap))
chma6.translate(0, glyphs->yoffset);
if (charStyle.baselineOffset() != 0)
chma6.translate(0, (-charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0));
QTransform finalMat = chma * chma2 * chma3 * chma4 * chma6 * trafo;
if (Item->rotation() != 0)
{
QTransform sca;
sca.translate(Item->xPos(), Item->yPos());
finalMat *= sca;
}
if (embItem != NULL)
{
ob.appendChild(processInlineItem(CurX + glyphs->xoffset, ls.y + glyphs->yoffset, finalMat, embItem, charStyle, false, trans));
CurX += (embItem->width() + embItem->lineWidth()) * glyphs->scaleH;
}
else
{
QString glName;
if (chstr > QChar(32))
glName = handleGlyph(chr, charStyle);
if ((charStyle.effects() & ScStyle_Shadowed) && (charStyle.strokeColor() != CommonStrings::None) && (chstr > QChar(32)))
{
QTransform sha = finalMat;
QTransform shad;
shad.translate(charStyle.fontSize() * charStyle.shadowXOffset() / 10000.0, -charStyle.fontSize() * charStyle.shadowYOffset() / 10000.0);
sha *= shad;
QDomElement ob2 = docu.createElement("use");
ob2.setAttribute("xlink:href", "#" + glName);
ob2.setAttribute("transform", MatrixToStr(sha));
ob2.setAttribute("style", "fill:"+SetColor(charStyle.strokeColor(), charStyle.strokeShade())+";" + "stroke:none;");
ob.appendChild(ob2);
}
if (((charStyle.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr[0]))
|| ((charStyle.effects() & ScStyle_UnderlineWords) && !chstr[0].isSpace() && !SpecialChars::isBreak(chstr[0])))
{
x = CurX;
y = ls.y;
double Ulen = glyphs->xadvance;
double Upos, lw, kern;
if (flags & ScLayout_StartOfLine)
kern = 0;
else
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
if ((charStyle.underlineOffset() != -1) || (charStyle.underlineWidth() != -1))
{
if (charStyle.underlineOffset() != -1)
Upos = (charStyle.underlineOffset() / 1000.0) * (charStyle.font().descent(charStyle.fontSize() / 10.0));
else
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
if (charStyle.underlineWidth() != -1)
lw = (charStyle.underlineWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
else
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
else
{
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
if (charStyle.baselineOffset() != 0)
Upos += (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
QDomElement ob6 = docu.createElement("path");
if (charStyle.effects() & ScStyle_Subscript)
ob6.setAttribute("d", QString("M %1 %2 L%3 %4").arg(x + glyphs->xoffset-kern).arg(y + glyphs->yoffset - Upos).arg(x + glyphs->xoffset+Ulen).arg(y + glyphs->yoffset - Upos));
else
ob6.setAttribute("d", QString("M %1 %2 L%3 %4").arg(x + glyphs->xoffset-kern).arg(y - Upos).arg(x + glyphs->xoffset+Ulen).arg(y - Upos));
QString sT = "stroke:none;";
if (charStyle.fillColor() != CommonStrings::None)
{
sT = "stroke:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
sT += " stroke-width:"+FToStr(lw)+";";
}
ob6.setAttribute("style", "fill:none;" + sT);
ob.appendChild(ob6);
}
if (chstr > QChar(32))
{
QDomElement ob3 = docu.createElement("use");
ob3.setAttribute("xlink:href", "#" + glName);
ob3.setAttribute("transform", MatrixToStr(finalMat));
QString fT = "fill:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
QString sT = "stroke:none;";
if (charStyle.effects() & ScStyle_Outline)
{
sT = "stroke:"+SetColor(charStyle.strokeColor(), charStyle.strokeShade())+";";
sT += " stroke-width:"+FToStr(chs * charStyle.outlineWidth() / 10000.0)+";";
}
ob3.setAttribute("style", fT + sT);
ob.appendChild(ob3);
}
if (charStyle.effects() & ScStyle_Strikethrough)
{
x = CurX;
y = ls.y;
double Ulen = glyphs->xadvance;
double Upos, lw, kern;
if (flags & ScLayout_StartOfLine)
kern = 0;
else
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
if ((charStyle.strikethruOffset() != -1) || (charStyle.strikethruWidth() != -1))
{
if (charStyle.strikethruOffset() != -1)
Upos = (charStyle.strikethruOffset() / 1000.0) * (charStyle.font().ascent(charStyle.fontSize() / 10.0));
else
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
if (charStyle.strikethruWidth() != -1)
lw = (charStyle.strikethruWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
else
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
else
{
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
if (charStyle.baselineOffset() != 0)
Upos += (charStyle.fontSize() / 10.0) * glyphs->scaleV * (charStyle.baselineOffset() / 1000.0);
QDomElement ob7 = docu.createElement("path");
ob7.setAttribute("d", QString("M %1 %2 L%3 %4").arg(x + glyphs->xoffset-kern).arg(y + glyphs->yoffset - Upos).arg(x + glyphs->xoffset+Ulen).arg(y + glyphs->yoffset - Upos));
QString sT = "stroke:none;";
if (charStyle.fillColor() != CommonStrings::None)
{
sT = "stroke:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
sT += " stroke-width:"+FToStr(lw)+";";
}
ob7.setAttribute("style", "fill:none;" + sT);
ob.appendChild(ob7);
}
CurX += glyphs->wide();
}
}
}
if (Item->NamedLStyle.isEmpty())
{
QDomElement ob4 = docu.createElement("path");
ob4.setAttribute("d", SetClipPath(&Item->PoLine, true));
ob4.setAttribute("style", "fill:none; "+stroke);
if ((!Item->strokePattern().isEmpty()) && (Item->patternStrokePath))
ob4.appendChild(processSymbolStroke(Item, trans));
ob.appendChild(ob4);
}
else
{
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
for (int it = ml.size()-1; it > -1; it--)
{
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
{
QDomElement ob5 = docu.createElement("path");
ob5.setAttribute("d", SetClipPath(&Item->PoLine, true));
ob5.setAttribute("style", "fill:none; "+GetMultiStroke(&ml[it], Item));
ob.appendChild(ob5);
}
}
}
SvgPainter p(trans, this, ob);
Item->textLayout.renderBackground(&p);
Item->textLayout.render(&p);
return ob;
}
 
QDomElement SVGExPlug::processPathTextItem(PageItem *Item, QString trans, QString stroke)
QDomElement SVGExPlug::processInlineItem(PageItem* embItem, QString trans, double scaleH, double scaleV)
{
QDomElement ob;
ob = docu.createElement("g");
ob.setAttribute("transform", trans);
if (Item->PoShow)
{
if (Item->NamedLStyle.isEmpty())
{
QDomElement ob4 = docu.createElement("path");
ob4.setAttribute("d", SetClipPath(&Item->PoLine, false));
ob4.setAttribute("style", "fill:none; "+stroke);
ob.appendChild(ob4);
}
else
{
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
for (int it = ml.size()-1; it > -1; it--)
{
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
{
QDomElement ob5 = docu.createElement("path");
ob5.setAttribute("d", SetClipPath(&Item->PoLine, false));
ob5.setAttribute("style", "fill:none; "+GetMultiStroke(&ml[it], Item));
ob.appendChild(ob5);
}
}
}
}
double wide;
QString chstr;
for (int a = 0; a < Item->asPathText()->itemRenderText.length(); ++a)
{
//ScText *hl = Item->asPathText()->itemRenderText.item_p(a);
const CharStyle& charStyle(Item->asPathText()->itemRenderText.charStyle(a));
const GlyphLayout* glyphs = Item->asPathText()->itemRenderText.getGlyphs(a);
const PathData* pdata = &(Item->textLayout.point(a));
PageItem* embItem = Item->itemText.hasObject(a)? Item->itemText.object(a) : NULL;
LayoutFlags flags = Item->itemText.flags(a);
chstr = Item->asPathText()->itemRenderText.text(a,1);
if ((chstr == QChar(13)) || (chstr == QChar(29)))
continue;
if (chstr == QChar(30))
{
chstr = Item->ExpandToken(a);
if (chstr == QChar(32))
continue;
}
double chs = charStyle.fontSize();
if (charStyle.effects() & ScStyle_SmallCaps)
{
if (chstr.toUpper() != chstr)
{
chs = qMax(static_cast<int>(charStyle.fontSize() * m_Doc->typographicPrefs().valueSmallCaps / 100), 1);
chstr = chstr.toUpper();
}
}
else if (charStyle.effects() & ScStyle_AllCaps)
chstr = chstr.toUpper();
uint chr = chstr[0].unicode();
QPointF tangt = QPointF( cos(pdata->PRot), sin(pdata->PRot) );
QTransform chma, chma2, chma3, chma4, chma6;
QTransform trafo = QTransform( 1, 0, 0, -1, -pdata->PDx, 0 );
if (Item->textPathFlipped)
trafo *= QTransform(1, 0, 0, -1, 0, 0);
if (Item->textPathType == 0)
trafo *= QTransform( tangt.x(), tangt.y(), tangt.y(), -tangt.x(), pdata->PtransX, pdata->PtransY );
else if (Item->textPathType == 1)
trafo *= QTransform(1, 0, 0, -1, pdata->PtransX, pdata->PtransY );
else if (Item->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x() < 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
trafo *= QTransform( a, (tangt.y() / tangt.x()) * b, 0, -1, pdata->PtransX, pdata->PtransY ); // ID's Skew mode
else
trafo *= QTransform( a, 6 * b, 0, -1, pdata->PtransX, pdata->PtransY );
}
if (embItem != NULL)
{
QTransform finalMat = chma * chma2 * chma3 * chma4 * chma6 * trafo;
ob.appendChild(processInlineItem(0, 0, finalMat, embItem, charStyle, true, trans));
}
else
{
if (Item->rotation() != 0)
{
QTransform sca;
sca.translate(-Item->xPos(), -Item->yPos());
trafo *= sca;
}
chma.scale(glyphs->scaleH * charStyle.fontSize() / 100.00, glyphs->scaleV * charStyle.fontSize() / 100.0);
if (Item->reversed())
{
if (a < Item->itemText.length()-1)
wide = charStyle.font().charWidth(chstr[0], charStyle.fontSize(), Item->itemText.text(a+1));
else
wide = charStyle.font().charWidth(chstr[0], charStyle.fontSize());
chma3.scale(-1, 1);
chma3.translate(-wide, 0);
}
chma4.translate(0, Item->BaseOffs - (charStyle.fontSize() / 10.0) * glyphs->scaleV);
if (charStyle.effects() & (ScStyle_Subscript | ScStyle_Superscript | ScLayout_DropCap))
chma6.translate(0, glyphs->yoffset);
if (charStyle.baselineOffset() != 0)
chma6.translate(0, (-charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0));
QTransform finalMat = chma * chma2 * chma3 * chma4 * chma6 * trafo;
if (Item->rotation() != 0)
{
QTransform sca;
sca.translate(Item->xPos(), Item->yPos());
finalMat *= sca;
}
 
if (((charStyle.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr[0]))
|| ((charStyle.effects() & ScStyle_UnderlineWords) && !chstr[0].isSpace() && !SpecialChars::isBreak(chstr[0])))
{
QTransform stro = chma2 * chma3 * chma6 * trafo;
if (Item->rotation() != 0)
{
QTransform sca;
sca.translate(Item->xPos(), Item->yPos());
stro *= sca;
}
double Ulen = glyphs->xadvance;
double Upos, Uwid, kern;
if (flags & ScLayout_StartOfLine)
kern = 0;
else
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
if ((charStyle.underlineOffset() != -1) || (charStyle.underlineWidth() != -1))
{
if (charStyle.underlineOffset() != -1)
Upos = (charStyle.underlineOffset() / 1000.0) * (charStyle.font().descent(charStyle.fontSize() / 10.0));
else
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
if (charStyle.underlineWidth() != -1)
Uwid = (charStyle.underlineWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
else
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
else
{
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
if (charStyle.baselineOffset() != 0)
Upos += (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
QDomElement ob8 = docu.createElement("path");
ob8.setAttribute("transform", MatrixToStr(stro));
if (charStyle.effects() & ScStyle_Subscript)
ob8.setAttribute("d", QString("M %1 %2 L%3 %4").arg(glyphs->xoffset-kern).arg(-Upos).arg(glyphs->xoffset+Ulen).arg(-Upos));
else
ob8.setAttribute("d", QString("M %1 %2 L%3 %4").arg(glyphs->xoffset-kern).arg(-(Upos + glyphs->yoffset)).arg(glyphs->xoffset+Ulen).arg(-(Upos + glyphs->yoffset)));
QString sT = "stroke:none;";
if (charStyle.fillColor() != CommonStrings::None)
{
sT = "stroke:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
sT += " stroke-width:"+FToStr(Uwid)+";";
}
ob8.setAttribute("style", "fill:none;" + sT);
ob.appendChild(ob8);
}
if (chstr > QChar(32))
{
QString glName = handleGlyph(chr, charStyle);
if ((charStyle.effects() & ScStyle_Shadowed) && (charStyle.strokeColor() != CommonStrings::None))
{
QTransform sha = finalMat;
QTransform shad;
shad.translate(charStyle.fontSize() * charStyle.shadowXOffset() / 10000.0, -charStyle.fontSize() * charStyle.shadowYOffset() / 10000.0);
sha *= shad;
QDomElement ob2 = docu.createElement("use");
ob2.setAttribute("xlink:href", "#" + glName);
ob2.setAttribute("transform", MatrixToStr(sha));
ob2.setAttribute("style", "fill:"+SetColor(charStyle.strokeColor(), charStyle.strokeShade())+";" + "stroke:none;");
ob.appendChild(ob2);
}
QDomElement ob1 = docu.createElement("use");
ob1.setAttribute("xlink:href", "#" + glName);
ob1.setAttribute("transform", MatrixToStr(finalMat));
QString fT = "fill:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
QString sT = "stroke:none;";
if (charStyle.effects() & ScStyle_Outline)
{
sT = "stroke:"+SetColor(charStyle.strokeColor(), charStyle.strokeShade())+";";
sT += " stroke-width:"+FToStr(chs * charStyle.outlineWidth() / 10000.0)+";";
}
ob1.setAttribute("style", fT + sT);
ob.appendChild(ob1);
}
if (charStyle.effects() & ScStyle_Strikethrough)
{
QTransform stro = chma2 * chma3 * chma6 * trafo;
if (Item->rotation() != 0)
{
QTransform sca;
sca.translate(Item->xPos(), Item->yPos());
stro *= sca;
}
double Ulen = glyphs->xadvance;
double Upos, Uwid, kern;
if (flags & ScLayout_StartOfLine)
kern = 0;
else
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
if ((charStyle.strikethruOffset() != -1) || (charStyle.strikethruWidth() != -1))
{
if (charStyle.strikethruOffset() != -1)
Upos = (charStyle.strikethruOffset() / 1000.0) * (charStyle.font().ascent(charStyle.fontSize() / 10.0));
else
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
if (charStyle.strikethruWidth() != -1)
Uwid = (charStyle.strikethruWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
else
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
else
{
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
if (charStyle.baselineOffset() != 0)
Upos += (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
QDomElement ob7 = docu.createElement("path");
ob7.setAttribute("transform", MatrixToStr(stro));
ob7.setAttribute("d", QString("M %1 %2 L%3 %4").arg(glyphs->xoffset-kern).arg(-Upos).arg(glyphs->xoffset+Ulen).arg(-Upos));
QString sT = "stroke:none;";
if (charStyle.fillColor() != CommonStrings::None)
{
sT = "stroke:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
sT += " stroke-width:"+FToStr(Uwid)+";";
}
ob7.setAttribute("style", "fill:none;" + sT);
ob.appendChild(ob7);
}
}
}
return ob;
}
 
QDomElement SVGExPlug::processInlineItem(double xpos, double ypos, QTransform &finalMat, PageItem* embItem, const CharStyle & charStyle, bool pathT, QString trans)
{
QList<PageItem*> emG;
if (embItem->isGroup())
emG = embItem->getItemList();
1823,8 → 1287,6
emG.append(embItem);
 
QDomElement layerGroup = docu.createElement("g");
if (pathT)
layerGroup.setAttribute("transform", MatrixToStr(finalMat));
for (int em = 0; em < emG.count(); ++em)
{
PageItem* embedded = emG.at(em);
1853,11 → 1315,9
obE = processImageItem(embedded, trans, fill, stroke);
break;
case PageItem::TextFrame:
case PageItem::PathText:
obE = processTextItem(embedded, trans, fill, stroke);
break;
case PageItem::PathText:
obE = processPathTextItem(embedded, trans, stroke);
break;
case PageItem::Symbol:
obE = processSymbolItem(embedded, trans);
break;
1865,13 → 1325,10
break;
}
QTransform mm;
mm.translate(xpos + embedded->gXpos * (charStyle.scaleH() / 1000.0), (ypos - (embedded->gHeight * (charStyle.scaleV() / 1000.0)) + embedded->gYpos * (charStyle.scaleV() / 1000.0)));
if (charStyle.baselineOffset() != 0)
mm.translate(0, embedded->gHeight * (charStyle.baselineOffset() / 1000.0));
if (charStyle.scaleH() != 1000)
mm.scale(charStyle.scaleH() / 1000.0, 1);
if (charStyle.scaleV() != 1000)
mm.scale(1, charStyle.scaleV() / 1000.0);
if (scaleH != 1.0)
mm.scale(scaleH, 1);
if (scaleV != 1.0)
mm.scale(1, scaleV);
mm.rotate(embedded->rotation());
obE.setAttribute("transform", MatrixToStr(mm));
layerGroup.appendChild(obE);
1879,15 → 1336,12
return layerGroup;
}
 
QString SVGExPlug::handleGlyph(uint chr, const CharStyle& cStyle)
QString SVGExPlug::handleGlyph(uint gid, const ScFace font)
{
if (chr == 32)
return "SPACE";
QString glName = QString("Gl%1%2").arg(cStyle.font().psName().simplified().replace(QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" )).arg(chr);
QString glName = QString("Gl%1%2").arg(font.psName().simplified().replace(QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" )).arg(gid);
if (glyphNames.contains(glName))
return glName;
uint gl = cStyle.font().char2CMap(chr);
FPointArray pts = cStyle.font().glyphOutline(gl);
FPointArray pts = font.glyphOutline(gid);
QDomElement ob = docu.createElement("path");
ob.setAttribute("d", SetClipPath(&pts, true));
ob.setAttribute("id", glName);
/trunk/Scribus/scribus/plugins/export/svgexplugin/svgexplugin.h
58,7 → 58,8
 
class SVGExPlug : public QObject
{
Q_OBJECT
Q_OBJECT
friend class SvgPainter;
 
public:
/*!
90,9 → 91,8
QDomElement processLineItem(PageItem *Item, QString trans, QString stroke);
QDomElement processImageItem(PageItem *Item, QString trans, QString fill, QString stroke);
QDomElement processTextItem(PageItem *Item, QString trans, QString fill, QString stroke);
QDomElement processPathTextItem(PageItem *Item, QString trans, QString stroke);
QDomElement processInlineItem(double xpos, double ypos, QTransform &finalMat, PageItem* embItem, const CharStyle& cStyle, bool pathT, QString trans);
QString handleGlyph(uint chr, const CharStyle& cStyle);
QDomElement processInlineItem(PageItem* embItem, QString trans, double scaleH, double scaleV);
QString handleGlyph(uint gid, const ScFace font);
QDomElement processArrows(PageItem *Item, QDomElement line, QString trans);
QString handleMask(PageItem *Item, double xOffset, double yOffset);
QString getFillStyle(PageItem *Item);
/trunk/Scribus/scribus/plugins/export/xpsexport/xpsexplugin.cpp
51,6 → 51,7
#include "scribusview.h"
#include "sctextstruct.h"
#include "tableutils.h"
#include "text/textlayoutpainter.h"
#include "util.h"
#include "ui/customfdialog.h"
#include "ui/guidemanager.h"
59,6 → 60,7
#include "util_formats.h"
#include "util_math.h"
#include "third_party/zip/scribus_zip.h"
#include "text/boxes.h"
 
int xpsexplugin_getPluginAPIVersion()
{
435,6 → 437,7
else
processImageItem(xOffset, yOffset, Item, parentElem, rel_root);
break;
case PageItem::PathText:
case PageItem::TextFrame:
if (checkForFallback(Item))
handleImageFallBack(Item, parentElem, rel_root);
441,12 → 444,6
else
processTextItem(xOffset, yOffset, Item, parentElem, rel_root);
break;
case PageItem::PathText:
if (checkForFallback(Item))
handleImageFallBack(Item, parentElem, rel_root);
else
processPathTextItem(xOffset, yOffset, Item, parentElem, rel_root);
break;
case PageItem::Table:
if (checkForFallback(Item))
handleImageFallBack(Item, parentElem, rel_root);
804,6 → 801,121
return;
}
 
class XPSPainter: public TextLayoutPainter
{
PageItem *m_item;
QDomElement m_group;
XPSExPlug *m_xps;
QMap<QString, QString> &m_fontMap;
QDomElement &m_relRoot;
 
public:
XPSPainter(PageItem *item, QDomElement &group, XPSExPlug *xps, QMap<QString, QString> &XPSfontMap, QDomElement &rel_root):
m_item(item),
m_group(group),
m_xps(xps),
m_fontMap(XPSfontMap),
m_relRoot(rel_root)
{ }
 
void drawGlyph(const GlyphLayout gl)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
if (!m_fontMap.contains(font().replacementName()))
m_fontMap.insert(font().replacementName(), m_xps->embedFont(font(), m_relRoot));
 
QTransform transform = matrix();
QDomElement glyph = m_xps->p_docu.createElement("Glyphs");
double size = fontSize() * qMax(gl.scaleV, gl.scaleH) * m_xps->conversionFactor;
glyph.setAttribute("RenderTransform", m_xps->MatrixToStr(transform, m_xps->conversionFactor));
glyph.setAttribute("BidiLevel", "0");
glyph.setAttribute("StyleSimulations", "None");
glyph.setAttribute("FontRenderingEmSize", m_xps->FToStr(size));
glyph.setAttribute("FontUri", m_fontMap[font().replacementName()]);
glyph.setAttribute("Fill", m_xps->SetColor(fillColor().color,fillColor().shade, 0));
glyph.setAttribute("OriginX", m_xps->FToStr(x() * m_xps->conversionFactor));
glyph.setAttribute("OriginY", m_xps->FToStr(y() * m_xps->conversionFactor));
glyph.setAttribute("Indices", QString::number(gl.glyph));
 
m_group.appendChild(glyph);
}
 
void drawGlyphOutline(const GlyphLayout gl, bool fill)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
FPointArray outline = font().glyphOutline(gl.glyph);
if (outline.size() >= 4)
{
QTransform transform = matrix();
transform.scale((fontSize() * gl.scaleH) / 10.0, (fontSize() * gl.scaleV) / 10.0);
outline.map(transform);
outline.translate(0, -fontSize() * gl.scaleV);
outline.translate(x(), y());
outline.scale(m_xps->conversionFactor, m_xps->conversionFactor);
QString pathData = m_xps->SetClipPath(&outline, true);
QDomElement glyph = m_xps->p_docu.createElement("Path");
glyph.setAttribute("Data", pathData);
if (!fill)
glyph.setAttribute("Fill", m_xps->SetColor("None", fillColor().shade, 0));
else
glyph.setAttribute("Fill", m_xps->SetColor(fillColor().color, fillColor().shade, 0));
glyph.setAttribute("StrokeThickness", m_xps->FToStr(strokeWidth() * m_xps->conversionFactor));
glyph.setAttribute("Stroke", m_xps->SetColor(strokeColor().color, strokeColor().shade, 0));
m_group.appendChild(glyph);
}
}
 
void drawLine(QPointF start, QPointF end)
{
QTransform transform = matrix();
QDomElement path = m_xps->p_docu.createElement("Path");
path.setAttribute("RenderTransform", m_xps->MatrixToStr(transform, m_xps->conversionFactor));
path.setAttribute("Data", QString("M%1,%2 L%3,%4").arg((x() + start.x()) * m_xps->conversionFactor).arg((y() + end.y()) * m_xps->conversionFactor).arg((x() + start.x() + end.x()) * m_xps->conversionFactor).arg((y() + end.y()) * m_xps->conversionFactor));
path.setAttribute("Stroke", m_xps->SetColor(strokeColor().color, strokeColor().shade, 0));
path.setAttribute("StrokeThickness", m_xps->FToStr(strokeWidth() * m_xps->conversionFactor));
m_group.appendChild(path);
}
 
void drawRect(QRectF rect)
{
QTransform transform = matrix();
double rx = (x() + rect.x()) * m_xps->conversionFactor;
double ry = (y() + rect.y()) * m_xps->conversionFactor;
double rw = rx + rect.width() * m_xps->conversionFactor;
double rh = ry + rect.height() * m_xps->conversionFactor;
QString paS = QString("M%1,%2 ").arg(rx).arg(ry);
paS += QString("L%1,%2 ").arg(rw).arg(ry);
paS += QString("L%1,%2 ").arg(rw).arg(rh);
paS += QString("L%1,%2 ").arg(rx).arg(rh);
paS += "Z";
QDomElement path = m_xps->p_docu.createElement("Path");
path.setAttribute("RenderTransform", m_xps->MatrixToStr(transform, m_xps->conversionFactor));
path.setAttribute("Data", paS);
path.setAttribute("Fill", m_xps->SetColor(fillColor().color, fillColor().shade, 0));
path.setAttribute("StrokeThickness", m_xps->FToStr(strokeWidth() * m_xps->conversionFactor));
path.setAttribute("Stroke", m_xps->SetColor(strokeColor().color, strokeColor().shade, 0));
m_group.appendChild(path);
}
 
void drawObject(PageItem* item)
{
QDomElement canvas = m_xps->p_docu.createElement("Canvas");
QTransform matrix = QTransform();
matrix.translate(x() * m_xps->conversionFactor, (y() - (item->height() * (scaleV() / 1000.0))) * m_xps->conversionFactor);
if (scaleH() != 1.0)
matrix.scale(scaleH(), 1);
if (scaleV() != 1.0)
matrix.scale(1, scaleV());
canvas.setAttribute("RenderTransform", m_xps->MatrixToStr(matrix));
m_xps->writeItemOnPage(item->gXpos, item->gYpos, item, canvas, m_relRoot);
m_group.appendChild(canvas);
}
};
 
void XPSExPlug::processTextItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root)
{
if (Item->isAnnotation())
879,758 → 991,13
grp.appendChild(ob);
}
}
bool bFound = false;
for (uint ll=0; ll < Item->textLayout.lines(); ++ll)
{
if (Item->itemText.paragraphStyle(Item->textLayout.line(ll).firstItem).backgroundColor() != CommonStrings::None)
{
bFound = true;
break;
}
}
if (bFound)
{
FPointArray path = Item->PoLine.copy();
path.scale(conversionFactor, conversionFactor);
SetClipAttr(grp, &path, Item->fillRule);
}
uint llp = 0;
while (llp < Item->textLayout.lines())
{
LineSpec ls = Item->textLayout.line(llp++);
const ParagraphStyle& LineStyle = Item->itemText.paragraphStyle(ls.firstItem);
if (LineStyle.backgroundColor() != CommonStrings::None)
{
double y0 = ls.y;
double y2 = ls.y;
double ascent = ls.ascent;
double descent = ls.descent;
double rMarg = LineStyle.rightMargin();
double lMarg = ls.colLeft;
double adjX = 0;
if (LineStyle.firstIndent() <= 0)
adjX += LineStyle.leftMargin() + LineStyle.firstIndent();
while (llp < Item->textLayout.lines())
{
ls = Item->textLayout.line(llp);
if ((ls.colLeft > lMarg) || (Item->itemText.paragraphStyle(ls.firstItem) != LineStyle))
{
if (y2 == 0)
y2 = y0;
break;
}
if (Item->itemText.text(ls.lastItem) == SpecialChars::PARSEP)
{
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < Item->textLayout.lines())
{
if ((Item->textLayout.line(llp + 1).lastItem - Item->textLayout.line(llp + 1).firstItem) > 0)
descent += LineStyle.lineSpacing() - (ls.descent + Item->textLayout.line(llp + 1).ascent);
}
llp++;
break;
}
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < Item->textLayout.lines())
descent += LineStyle.lineSpacing() - (ls.descent + Item->textLayout.line(llp + 1).ascent);
llp++;
}
QRectF scr(lMarg + adjX, y0 - ascent, Item->asTextFrame()->columnWidth() - adjX - rMarg, y2 - y0 + descent + ascent);
QString paS = QString("M%1,%2 ").arg(scr.x() * conversionFactor).arg(scr.y() * conversionFactor);
paS += QString("L%1,%2 ").arg((scr.x() + scr.width()) * conversionFactor).arg(scr.y() * conversionFactor);
paS += QString("L%1,%2 ").arg((scr.x() + scr.width()) * conversionFactor).arg((scr.y() + scr.height()) * conversionFactor);
paS += QString("L%1,%2 ").arg(scr.x() * conversionFactor).arg((scr.y() + scr.height()) * conversionFactor);
paS += "Z";
QDomElement glyS = p_docu.createElement("Path");
glyS.setAttribute("Data", paS);
glyS.setAttribute("Fill", SetColor(LineStyle.backgroundColor(), LineStyle.backgroundShade(), 0));
grp.appendChild(glyS);
}
}
for (uint ll=0; ll < Item->textLayout.lines(); ++ll)
{
LineSpec ls = Item->textLayout.line(ll);
QList<txtRunItem> current_run;
QList<QList<txtRunItem> > textRuns;
QList<txtRunItem> specialText;
double CurX = ls.x;
 
double CurXB = ls.x;
int last = qMin(ls.lastItem, Item->itemText.length() - 1);
QRectF scr;
QString oldBack = "";
double oldShade = 100;
QString colorB = "";
for (int a = ls.firstItem; a <= last; ++a)
{
const GlyphLayout* glyphs(Item->itemText.getGlyphs(a));
const CharStyle& charStyle(Item->itemText.charStyle(a));
if (charStyle.backColor() != CommonStrings::None)
{
// This code is for rendering character background color.
colorB = SetColor(charStyle.backColor(), charStyle.backShade(), 0);
const ParagraphStyle& LineStyle = Item->itemText.paragraphStyle(ls.firstItem);
double y1 = ls.y;
double hl = ls.height;
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
hl = m_Doc->guidesPrefs().valueBaselineGrid;
else if (LineStyle.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
hl = LineStyle.lineSpacing();
if (ls.isFirstLine)
{
if (Item->textLayout.lines() == 1)
hl = ls.ascent + ls.descent;
if (LineStyle.hasDropCap() && (a == ls.firstItem))
hl *= LineStyle.dropCapLines();
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
y1 -= LineStyle.lineSpacing();
else if (Item->firstLineOffset() == FLOPRealGlyphHeight || Item->firstLineOffset() == FLOPFontAscent)
y1 -= ls.ascent;
else
y1 -= LineStyle.lineSpacing();
}
else
y1 -= ls.ascent + (hl - (ls.ascent + ls.descent)) / 2.0;
QRectF scrG;
if (Item->itemText.hasObject(a))
{
PageItem* obj = Item->itemText.object(a);
double ww = (obj->width() + obj->lineWidth()) * glyphs->scaleH;
double hh = (obj->height() + obj->lineWidth()) * glyphs->scaleV;
scrG = QRectF(CurXB, ls.y - hh, ww , hh);
}
else
scrG = QRectF(CurXB, y1, glyphs->wide(), hl);
if ((oldBack == "") || ((oldBack == charStyle.backColor()) && (oldShade == charStyle.backShade())))
scr |= scrG;
else if ((oldBack != charStyle.backColor()) || (oldShade != charStyle.backShade()))
{
QString paS = QString("M%1,%2 ").arg(scr.x() * conversionFactor).arg(scr.y() * conversionFactor);
paS += QString("L%1,%2 ").arg((scr.x() + scr.width()) * conversionFactor).arg(scr.y() * conversionFactor);
paS += QString("L%1,%2 ").arg((scr.x() + scr.width()) * conversionFactor).arg((scr.y() + scr.height()) * conversionFactor);
paS += QString("L%1,%2 ").arg(scr.x() * conversionFactor).arg((scr.y() + scr.height()) * conversionFactor);
paS += "Z";
QDomElement glyS = p_docu.createElement("Path");
glyS.setAttribute("Data", paS);
glyS.setAttribute("Fill", SetColor(oldBack, oldShade, 0));
grp.appendChild(glyS);
scr = scrG;
}
oldBack = charStyle.backColor();
oldShade = charStyle.backShade();
}
else
{
if (!scr.isNull())
{
QString paS = QString("M%1,%2 ").arg(scr.x() * conversionFactor).arg(scr.y() * conversionFactor);
paS += QString("L%1,%2 ").arg((scr.x() + scr.width()) * conversionFactor).arg(scr.y() * conversionFactor);
paS += QString("L%1,%2 ").arg((scr.x() + scr.width()) * conversionFactor).arg((scr.y() + scr.height()) * conversionFactor);
paS += QString("L%1,%2 ").arg(scr.x() * conversionFactor).arg((scr.y() + scr.height()) * conversionFactor);
paS += "Z";
QDomElement glyS = p_docu.createElement("Path");
glyS.setAttribute("Data", paS);
glyS.setAttribute("Fill", colorB);
grp.appendChild(glyS);
}
oldBack = "";
oldShade = 100;
scr = QRectF();
}
CurXB += glyphs->wide();
}
if (!scr.isNull())
{
QString paS = QString("M%1,%2 ").arg(scr.x() * conversionFactor).arg(scr.y() * conversionFactor);
paS += QString("L%1,%2 ").arg((scr.x() + scr.width()) * conversionFactor).arg(scr.y() * conversionFactor);
paS += QString("L%1,%2 ").arg((scr.x() + scr.width()) * conversionFactor).arg((scr.y() + scr.height()) * conversionFactor);
paS += QString("L%1,%2 ").arg(scr.x() * conversionFactor).arg((scr.y() + scr.height()) * conversionFactor);
paS += "Z";
QDomElement glyS = p_docu.createElement("Path");
glyS.setAttribute("Data", paS);
glyS.setAttribute("Fill", colorB);
grp.appendChild(glyS);
}
 
for (int a = ls.firstItem; a <= ls.lastItem; ++a)
{
//ScText *hl = Item->itemText.item_p(a);
QChar chr = Item->itemText.text(a);
CharStyle charStyle = Item->itemText.charStyle(a);
GlyphLayout* glyphs = Item->itemText.getGlyphs(a);
LayoutFlags flags = Item->itemText.flags(a);
const ScFace* font = &charStyle.font();
txtRunItem txItem;
txItem.chr = chr;
txItem.glyphs = glyphs;
txItem.style = charStyle;
txItem.index = a;
txItem.CurX = CurX;
txItem.embItem = Item->itemText.hasObject(a)? Item->itemText.object(a) : NULL;
if (!((font->type() == ScFace::TTF) || (font->type() == ScFace::OTF)))
{
specialText.append(txItem);
textRuns.append(current_run);
current_run.clear();
CurX += txItem.glyphs->wide();
continue;
}
if (SpecialChars::isBreak(chr, true) || (chr == QChar(10)))
{
continue;
}
if (flags & ScLayout_SuppressSpace)
{
continue;
}
if ((chr == SpecialChars::OLD_NBSPACE) || (chr == SpecialChars::OBJECT) || (charStyle.effects() & ScStyle_UserStyles))
{
specialText.append(txItem);
textRuns.append(current_run);
current_run.clear();
CurX += txItem.glyphs->wide();
continue;
}
QString guidFont;
if (!xps_fontMap.contains(font->replacementName()))
{
guidFont = embedFont(font, rel_root);
xps_fontMap.insert(font->replacementName(), guidFont);
}
else
guidFont = xps_fontMap[font->replacementName()];
if (current_run.isEmpty())
current_run.append(txItem);
else
{
txtRunItem txItemL = current_run.last();
double chl = (txItemL.style.fontSize() / 10.0) * qMax(txItemL.glyphs->scaleV, txItemL.glyphs->scaleH) * conversionFactor;
const ScFace* fontL = &txItemL.style.font();
QString guidFontL = xps_fontMap[fontL->replacementName()];
StyleFlag old_sty = txItemL.style.effects();
int old_shade = txItemL.style.fillShade();
QString old_fill = txItemL.style.fillColor();
double chs = (charStyle.fontSize() / 10.0) * qMax(glyphs->scaleV, glyphs->scaleH) * conversionFactor;
if ((chs != chl) || (guidFont != guidFontL) || (charStyle.effects() != old_sty) || (charStyle.fillColor() != old_fill) || (charStyle.fillShade() != old_shade))
{
textRuns.append(current_run);
current_run.clear();
}
current_run.append(txItem);
}
CurX += txItem.glyphs->wide();
}
textRuns.append(current_run);
for (int txr = 0; txr < textRuns.count(); txr++)
{
QString uniString = "";
QString indString = "";
current_run = textRuns[txr];
if (current_run.isEmpty())
continue;
double StartX = current_run[0].CurX;
CurX = current_run[0].CurX;
double chs = (current_run[0].style.fontSize() / 10.0) * qMax(current_run[0].glyphs->scaleV, current_run[0].glyphs->scaleH) * conversionFactor;
for (int cr = 0; cr < current_run.count(); cr++)
{
txtRunItem txItem = current_run[cr];
if ((txItem.chr == SpecialChars::PAGENUMBER) || (txItem.chr == SpecialChars::PAGECOUNT))
{
QString exString = Item->ExpandToken(txItem.index);
for (int ex = 0; ex < exString.count(); ex++)
{
indString += ";";
}
uniString += exString;
}
else if ((SpecialChars::isBreakingSpace(txItem.chr)) || (SpecialChars::isExpandingSpace(txItem.chr)) || (txItem.chr.isSpace()))
{
indString += QString(",%1;").arg((txItem.glyphs->wide() * conversionFactor) / chs * 100);
uniString += " ";
}
else
{
uniString += txItem.chr;
if ((txItem.glyphs->xoffset != 0) || (txItem.glyphs->yoffset != 0))
indString += QString(",%1,%2,%3;").arg((txItem.glyphs->wide() * conversionFactor) / chs * 100).arg((txItem.glyphs->xoffset * conversionFactor) / chs * 100).arg((-txItem.glyphs->yoffset * conversionFactor) / chs * 100);
else
indString += QString(",%1;").arg((txItem.glyphs->wide() * conversionFactor) / chs * 100);
}
CurX += txItem.glyphs->wide();
}
if (!indString.isEmpty())
indString.chop(1);
QDomElement gly = p_docu.createElement("Glyphs");
gly.setAttribute("BidiLevel", "0");
gly.setAttribute("StyleSimulations", "None");
gly.setAttribute("FontRenderingEmSize", FToStr(chs));
const ScFace* fontL = &current_run[0].style.font();
gly.setAttribute("FontUri", xps_fontMap[fontL->replacementName()]);
gly.setAttribute("Fill", SetColor(current_run[0].style.fillColor(), current_run[0].style.fillShade(), 0));
gly.setAttribute("UnicodeString", uniString);
if (current_run.count() == 1)
{
gly.setAttribute("OriginX", FToStr((StartX + current_run[0].glyphs->xoffset) * conversionFactor));
gly.setAttribute("OriginY", FToStr((ls.y + current_run[0].glyphs->yoffset) * conversionFactor));
}
else
{
gly.setAttribute("OriginX", FToStr(StartX * conversionFactor));
gly.setAttribute("OriginY", FToStr(ls.y * conversionFactor));
gly.setAttribute("Indices", indString);
}
grp.appendChild(gly);
}
for (int cr = 0; cr < specialText.count(); cr++)
{
txtRunItem txItem = specialText[cr];
CurX = txItem.CurX;
if (txItem.chr == SpecialChars::OBJECT)
{
if (txItem.embItem != NULL)
{
QDomElement obO = p_docu.createElement("Canvas");
QTransform mm;
mm.translate(CurX * conversionFactor, (ls.y - (txItem.embItem->height() * (txItem.style.scaleV() / 1000.0))) * conversionFactor);
if (txItem.style.baselineOffset() != 0)
mm.translate(0, (txItem.style.baselineOffset() / 1000.0) * conversionFactor);
if (txItem.style.scaleH() != 1000)
mm.scale(txItem.style.scaleH() / 1000.0, 1);
if (txItem.style.scaleV() != 1000)
mm.scale(1, txItem.style.scaleV() / 1000.0);
obO.setAttribute("RenderTransform", MatrixToStr(mm));
QList<PageItem*> emG;
if (txItem.embItem->isGroup())
emG = txItem.embItem->getItemList();
else
emG.append(txItem.embItem);
for (int em = 0; em < emG.count(); ++em)
{
PageItem* embed = emG.at(em);
writeItemOnPage(embed->gXpos, embed->gYpos, embed, obO, rel_root);
}
grp.appendChild(obO);
}
continue;
}
QString chstr = txItem.chr;
if ((txItem.chr == SpecialChars::PAGENUMBER) || (txItem.chr == SpecialChars::PAGECOUNT))
chstr = Item->ExpandToken(txItem.index);
double chs = txItem.style.fontSize();
if (txItem.style.effects() & ScStyle_SmallCaps)
{
if (chstr.toUpper() != chstr)
{
chs = qMax(static_cast<int>(txItem.style.fontSize() * m_Doc->typographicPrefs().valueSmallCaps / 100), 1);
chstr = chstr.toUpper();
}
}
else if (txItem.style.effects() & ScStyle_AllCaps)
chstr = chstr.toUpper();
for (int cx = 0; cx < chstr.count(); cx++)
{
FPointArray pts;
QChar chstrex = chstr[cx];
uint chr = chstrex.unicode();
QTransform chma;
uint gl = txItem.style.font().char2CMap(chr);
if (!chstrex.isSpace())
{
pts = txItem.style.font().glyphOutline(gl);
if (pts.size() < 4)
continue;
chma = QTransform();
chma.scale(txItem.glyphs->scaleH * txItem.style.fontSize() / 100.00, txItem.glyphs->scaleV * txItem.style.fontSize() / 100.0);
pts.map(chma);
if (txItem.style.effects() & (ScStyle_Subscript | ScStyle_Superscript))
pts.translate(0, -(chs / 10.0 * txItem.glyphs->scaleV));
else
pts.translate(0, -(chs / 10.0));
pts.translate(CurX, ls.y);
// Fix for drop caps ???
if (ls.isFirstLine && Item->itemText.paragraphStyle(ls.firstItem).hasDropCap() && (txItem.index == ls.firstItem))
pts.translate(0, -ls.ascent);
if (txItem.style.effects() & (ScStyle_Subscript | ScStyle_Superscript))
pts.translate(0, txItem.glyphs->yoffset);
if ((txItem.style.effects() & ScStyle_Shadowed) && (txItem.style.strokeColor() != CommonStrings::None))
{
FPointArray ptsS = pts.copy();
ptsS.translate(txItem.style.fontSize() * txItem.style.shadowXOffset() / 10000.0, -txItem.style.fontSize() * txItem.style.shadowYOffset() / 10000.0);
ptsS.scale(conversionFactor, conversionFactor);
QString paS = SetClipPath(&ptsS, true);
QDomElement glyS = p_docu.createElement("Path");
glyS.setAttribute("Data", paS);
glyS.setAttribute("Fill", SetColor(txItem.style.strokeColor(), txItem.style.strokeShade(), 0));
grp.appendChild(glyS);
}
pts.scale(conversionFactor, conversionFactor);
QString pa = SetClipPath(&pts, true);
QDomElement gly = p_docu.createElement("Path");
gly.setAttribute("Data", pa);
gly.setAttribute("Fill", SetColor(txItem.style.fillColor(), txItem.style.fillShade(), 0));
if (txItem.style.effects() & ScStyle_Outline)
{
gly.setAttribute("StrokeThickness", FToStr((chs * txItem.style.outlineWidth() / 10000.0) * conversionFactor));
gly.setAttribute("Stroke", SetColor(txItem.style.strokeColor(), txItem.style.strokeShade(), 0));
}
grp.appendChild(gly);
}
if ((txItem.style.effects() & ScStyle_Underline) || ((txItem.style.effects() & ScStyle_UnderlineWords) && chstr.toUInt() != txItem.style.font().char2CMap(QChar(' '))))
{
double st, lw;
if ((txItem.style.underlineOffset() != -1) || (txItem.style.underlineWidth() != -1))
{
if (txItem.style.underlineOffset() != -1)
st = (txItem.style.underlineOffset() / 1000.0) * (txItem.style.font().descent(txItem.style.fontSize() / 10.0));
else
st = txItem.style.font().underlinePos(txItem.style.fontSize() / 10.0);
if (txItem.style.underlineWidth() != -1)
lw = (txItem.style.underlineWidth() / 1000.0) * (txItem.style.fontSize() / 10.0);
else
lw = qMax(txItem.style.font().strokeWidth(txItem.style.fontSize() / 10.0), 1.0);
}
else
{
st = txItem.style.font().underlinePos(txItem.style.fontSize() / 10.0);
lw = qMax(txItem.style.font().strokeWidth(txItem.style.fontSize() / 10.0), 1.0);
}
if (txItem.style.baselineOffset() != 0)
st += (txItem.style.fontSize() / 10.0) * txItem.glyphs->scaleV * (txItem.style.baselineOffset() / 1000.0);
QDomElement gly = p_docu.createElement("Path");
if (txItem.style.effects() & ScStyle_Subscript)
gly.setAttribute("Data", QString("M%1,%2 L%3,%4").arg((CurX + txItem.glyphs->xoffset) * conversionFactor).arg((ls.y + txItem.glyphs->yoffset - st) * conversionFactor).arg((CurX + txItem.glyphs->xoffset + txItem.glyphs->xadvance) * conversionFactor).arg((ls.y + txItem.glyphs->yoffset - st) * conversionFactor));
else
gly.setAttribute("Data", QString("M%1,%2 L%3,%4").arg((CurX + txItem.glyphs->xoffset) * conversionFactor).arg((ls.y - st) * conversionFactor).arg((CurX + txItem.glyphs->xoffset + txItem.glyphs->xadvance) * conversionFactor).arg((ls.y - st) * conversionFactor));
gly.setAttribute("Stroke", SetColor(txItem.style.fillColor(), txItem.style.fillShade(), 0));
gly.setAttribute("StrokeThickness", FToStr(lw * conversionFactor));
grp.appendChild(gly);
}
if (txItem.style.effects() & ScStyle_Strikethrough)
{
double st, lw;
if ((txItem.style.strikethruOffset() != -1) || (txItem.style.strikethruWidth() != -1))
{
if (txItem.style.strikethruOffset() != -1)
st = (txItem.style.strikethruOffset() / 1000.0) * (txItem.style.font().ascent(txItem.style.fontSize() / 10.0));
else
st = txItem.style.font().strikeoutPos(txItem.style.fontSize() / 10.0);
if (txItem.style.strikethruWidth() != -1)
lw = (txItem.style.strikethruWidth() / 1000.0) * (txItem.style.fontSize() / 10.0);
else
lw = qMax(txItem.style.font().strokeWidth(txItem.style.fontSize() / 10.0), 1.0);
}
else
{
st = txItem.style.font().strikeoutPos(txItem.style.fontSize() / 10.0);
lw = qMax(txItem.style.font().strokeWidth(txItem.style.fontSize() / 10.0), 1.0);
}
if (txItem.style.baselineOffset() != 0)
st += (txItem.style.fontSize() / 10.0) * txItem.glyphs->scaleV * (txItem.style.baselineOffset() / 1000.0);
QDomElement gly = p_docu.createElement("Path");
gly.setAttribute("Data", QString("M%1,%2 L%3,%4").arg((CurX + txItem.glyphs->xoffset) * conversionFactor).arg((ls.y - st) * conversionFactor).arg((CurX + txItem.glyphs->xoffset + txItem.glyphs->xadvance) * conversionFactor).arg((ls.y - st) * conversionFactor));
gly.setAttribute("Stroke", SetColor(txItem.style.fillColor(), txItem.style.fillShade(), 0));
gly.setAttribute("StrokeThickness", FToStr(lw * conversionFactor));
grp.appendChild(gly);
}
}
}
}
parentElem.appendChild(grp);
if ((Item->GrTypeStroke != 0) || (Item->lineColor() != CommonStrings::None) || !Item->NamedLStyle.isEmpty())
{
if (Item->NamedLStyle.isEmpty())
{
if ((!Item->strokePattern().isEmpty()) && (Item->patternStrokePath))
{
processSymbolStroke(xOffset, yOffset, Item, parentElem, rel_root);
}
else
{
QDomElement ob3 = p_docu.createElement("Path");
ob3.setAttribute("Data", pa);
getStrokeStyle(Item, ob3, rel_root, xOffset, yOffset);
ob3.setAttribute("RenderTransform", MatrixToStr(mpl));
parentElem.appendChild(ob3);
}
}
else
{
QDomElement grp2 = p_docu.createElement("Canvas");
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
for (int it = ml.size()-1; it > -1; it--)
{
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
{
QDomElement ob3 = p_docu.createElement("Path");
ob3.setAttribute("Data", pa);
GetMultiStroke(&ml[it], ob3);
grp2.appendChild(ob3);
}
}
if (Item->lineTransparency() != 0)
grp2.setAttribute("Opacity", FToStr(1.0 - Item->lineTransparency()));
grp2.setAttribute("RenderTransform", MatrixToStr(mpl));
parentElem.appendChild(grp2);
}
}
XPSPainter p(Item, grp, this, xps_fontMap, rel_root);
Item->textLayout.renderBackground(&p);
Item->textLayout.render(&p);
}
 
void XPSExPlug::processPathTextItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root)
{
QDomElement grp = p_docu.createElement("Canvas");
QTransform mpx;
mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
if ((Item->rotation() != 0.0) || Item->imageFlippedH() || Item->imageFlippedV())
{
mpx.rotate(Item->rotation());
if (Item->imageFlippedH())
{
mpx.translate(Item->width() * conversionFactor, 0);
mpx.scale(-1, 1);
}
if (Item->imageFlippedV())
{
mpx.translate(0, Item->height() * conversionFactor);
mpx.scale(1, -1);
}
}
grp.setAttribute("RenderTransform", MatrixToStr(mpx));
if ((Item->PoShow) && (Item->lineColor() != CommonStrings::None))
{
QDomElement ob = p_docu.createElement("Path");
FPointArray path = Item->PoLine.copy();
path.scale(conversionFactor, conversionFactor);
QString pa = SetClipPath(&path, false);
ob.setAttribute("Data", pa);
if (Item->NamedLStyle.isEmpty())
{
if ((!Item->strokePattern().isEmpty()) && (Item->patternStrokePath))
{
processSymbolStroke(xOffset, yOffset, Item, parentElem, rel_root);
}
else
{
getStrokeStyle(Item, ob, rel_root, xOffset, yOffset);
grp.appendChild(ob);
}
}
else
{
QDomElement grp2 = p_docu.createElement("Canvas");
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
for (int it = ml.size()-1; it > -1; it--)
{
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
{
QDomElement ob3 = p_docu.createElement("Path");
ob3.setAttribute("Data", pa);
GetMultiStroke(&ml[it], ob3);
grp2.appendChild(ob3);
}
}
if (Item->lineTransparency() != 0)
grp2.setAttribute("Opacity", FToStr(1.0 - Item->lineTransparency()));
grp.appendChild(grp2);
}
}
QString chstr;
for (int a = 0; a < Item->asPathText()->itemRenderText.length(); ++a)
{
//ScText *hl = Item->asPathText()->itemRenderText.item_p(a);
const CharStyle& charStyle(Item->asPathText()->itemRenderText.charStyle(a));
const PathData* pdata = &(Item->asPathText()->textLayout.point(a));
const GlyphLayout* glyphs = Item->asPathText()->itemRenderText.getGlyphs(a);
PageItem* embItem = Item->asPathText()->itemRenderText.hasObject(a)?
Item->asPathText()->itemRenderText.object(a) : NULL;
chstr = Item->asPathText()->itemRenderText.text(a,1);
if ((chstr == QChar(13)) || (chstr == QChar(29)))
continue;
if (chstr == QChar(30))
{
chstr = Item->ExpandToken(a);
if (chstr == QChar(32))
continue;
}
double chs = charStyle.fontSize();
if (charStyle.effects() & ScStyle_SmallCaps)
{
if (chstr.toUpper() != chstr)
{
chs = qMax(static_cast<int>(charStyle.fontSize() * m_Doc->typographicPrefs().valueSmallCaps / 100), 1);
chstr = chstr.toUpper();
}
}
else if (charStyle.effects() & ScStyle_AllCaps)
chstr = chstr.toUpper();
uint chr = chstr[0].unicode();
QPointF tangt = QPointF( cos(pdata->PRot), sin(pdata->PRot) );
QTransform trafo = QTransform( 1, 0, 0, -1, -pdata->PDx * conversionFactor, 0 );
if (Item->textPathFlipped)
trafo *= QTransform(1, 0, 0, -1, 0, 0);
if (Item->textPathType == 0)
trafo *= QTransform( tangt.x(), tangt.y(), tangt.y(), -tangt.x(), pdata->PtransX * conversionFactor, pdata->PtransY * conversionFactor );
else if (Item->textPathType == 1)
trafo *= QTransform(1, 0, 0, -1, pdata->PtransX * conversionFactor, pdata->PtransY * conversionFactor );
else if (Item->textPathType == 2)
{
double a = 1;
if (tangt.x() < 0)
a = -1;
if (fabs(tangt.x()) > 0.1)
trafo *= QTransform( a, (tangt.y() / tangt.x()) * a, 0, -1, pdata->PtransX * conversionFactor, pdata->PtransY * conversionFactor ); // ID's Skew mode
else
trafo *= QTransform( a, 4 * a, 0, -1, pdata->PtransX * conversionFactor, pdata->PtransY * conversionFactor );
}
if (charStyle.baselineOffset() != 0)
trafo.translate(0, (-charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0));
trafo.translate(0, Item->BaseOffs);
QTransform finalMat = trafo;
if (chr == SpecialChars::OBJECT)
{
if (embItem != NULL)
{
QDomElement obO = p_docu.createElement("Canvas");
QTransform mm = finalMat;
mm.translate(0, (-(embItem->height() * (charStyle.scaleV() / 1000.0))) * conversionFactor);
if (charStyle.scaleH() != 1000)
mm.scale(charStyle.scaleH() / 1000.0, 1);
if (charStyle.scaleV() != 1000)
mm.scale(1, charStyle.scaleV() / 1000.0);
obO.setAttribute("RenderTransform", MatrixToStr(mm));
QList<PageItem*> emG;
if (embItem->isGroup())
emG = embItem->getItemList();
else
emG.append(embItem);
for (int em = 0; em < emG.count(); ++em)
{
PageItem* embed = emG.at(em);
writeItemOnPage(embed->gXpos, embed->gYpos, embed, obO, rel_root);
}
grp.appendChild(obO);
}
continue;
}
finalMat.scale(conversionFactor, conversionFactor);
FPointArray pts;
QTransform chma;
uint gl = charStyle.font().char2CMap(chr);
pts = charStyle.font().glyphOutline(gl);
if (pts.size() < 4)
continue;
chma = QTransform();
chma.scale(glyphs->scaleH * charStyle.fontSize() / 100.00, glyphs->scaleV * charStyle.fontSize() / 100.0);
pts.map(chma);
if (charStyle.effects() & (ScStyle_Subscript | ScStyle_Superscript))
pts.translate(0, -(chs / 10.0 * glyphs->scaleV));
else
pts.translate(0, -(chs / 10.0));
if (charStyle.effects() & (ScStyle_Subscript | ScStyle_Superscript))
pts.translate(0, glyphs->yoffset);
if ((charStyle.effects() & ScStyle_Shadowed) && (charStyle.strokeColor() != CommonStrings::None))
{
FPointArray ptsS = pts.copy();
ptsS.translate(charStyle.fontSize() * charStyle.shadowXOffset() / 10000.0, -charStyle.fontSize() * charStyle.shadowYOffset() / 10000.0);
ptsS.map(finalMat);
QString paS = SetClipPath(&ptsS, true);
QDomElement glyS = p_docu.createElement("Path");
glyS.setAttribute("Data", paS);
glyS.setAttribute("Fill", SetColor(charStyle.strokeColor(), charStyle.strokeShade(), 0));
grp.appendChild(glyS);
}
pts.map(finalMat);
QString pa = SetClipPath(&pts, true);
QDomElement gly = p_docu.createElement("Path");
gly.setAttribute("Data", pa);
gly.setAttribute("Fill", SetColor(charStyle.fillColor(), charStyle.fillShade(), 0));
if (charStyle.effects() & ScStyle_Outline)
{
gly.setAttribute("StrokeThickness", FToStr((chs * charStyle.outlineWidth() / 10000.0) * conversionFactor));
gly.setAttribute("Stroke", SetColor(charStyle.strokeColor(), charStyle.strokeShade(), 0));
}
grp.appendChild(gly);
if ((charStyle.effects() & ScStyle_Underline) || ((charStyle.effects() & ScStyle_UnderlineWords) && chstr.toUInt() != charStyle.font().char2CMap(QChar(' '))))
{
double st, lw;
if ((charStyle.underlineOffset() != -1) || (charStyle.underlineWidth() != -1))
{
if (charStyle.underlineOffset() != -1)
st = (charStyle.underlineOffset() / 1000.0) * (charStyle.font().descent(charStyle.fontSize() / 10.0));
else
st = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
if (charStyle.underlineWidth() != -1)
lw = (charStyle.underlineWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
else
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
else
{
st = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
if (charStyle.baselineOffset() != 0)
st += (charStyle.fontSize() / 10.0) * glyphs->scaleV * (charStyle.baselineOffset() / 1000.0);
FPointArray ptsS;
ptsS.svgInit();
if (charStyle.effects() & ScStyle_Subscript)
{
ptsS.svgMoveTo(glyphs->xoffset, glyphs->yoffset - st);
ptsS.svgLineTo(glyphs->xoffset + glyphs->xadvance, glyphs->yoffset - st);
}
else
{
ptsS.svgMoveTo(glyphs->xoffset, -st);
ptsS.svgLineTo(glyphs->xoffset + glyphs->xadvance, -st);
}
ptsS.map(finalMat);
QString paS = SetClipPath(&ptsS, true);
QDomElement gly = p_docu.createElement("Path");
gly.setAttribute("Data", paS);
gly.setAttribute("Stroke", SetColor(charStyle.fillColor(), charStyle.fillShade(), 0));
gly.setAttribute("StrokeThickness", FToStr(lw * conversionFactor));
grp.appendChild(gly);
}
if (charStyle.effects() & ScStyle_Strikethrough)
{
double st, lw;
if ((charStyle.strikethruOffset() != -1) || (charStyle.strikethruWidth() != -1))
{
if (charStyle.strikethruOffset() != -1)
st = (charStyle.strikethruOffset() / 1000.0) * (charStyle.font().ascent(charStyle.fontSize() / 10.0));
else
st = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
if (charStyle.strikethruWidth() != -1)
lw = (charStyle.strikethruWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
else
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
else
{
st = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
if (charStyle.baselineOffset() != 0)
st += (charStyle.fontSize() / 10.0) * glyphs->scaleV * (charStyle.baselineOffset() / 1000.0);
FPointArray ptsS;
ptsS.svgInit();
ptsS.svgMoveTo(glyphs->xoffset, -st);
ptsS.svgLineTo(glyphs->xoffset + glyphs->xadvance, -st);
ptsS.map(finalMat);
QString paS = SetClipPath(&ptsS, true);
QDomElement gly = p_docu.createElement("Path");
gly.setAttribute("Data", paS);
gly.setAttribute("Stroke", SetColor(charStyle.fillColor(), charStyle.fillShade(), 0));
gly.setAttribute("StrokeThickness", FToStr(lw * conversionFactor));
grp.appendChild(gly);
}
}
parentElem.appendChild(grp);
return;
}
 
void XPSExPlug::processSymbolItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root)
{
QDomElement ob = p_docu.createElement("Canvas");
2274,10 → 1641,10
}
}
 
QString XPSExPlug::embedFont(const ScFace *font, QDomElement &rel_root)
QString XPSExPlug::embedFont(const ScFace font, QDomElement &rel_root)
{
QByteArray fontData;
loadRawText(font->fontFilePath(), fontData);
loadRawText(font.fontFilePath(), fontData);
QUuid id = QUuid::createUuid();
QString guidString = id.toString();
guidString = guidString.toUpper();
3084,6 → 2451,12
return cc.setNum(c);
}
 
QString XPSExPlug::MatrixToStr(QTransform &mat, double factor)
{
QString cc("%1, %2, %3, %4, %5, %6");
return cc.arg(mat.m11()).arg(mat.m12()).arg(mat.m21()).arg(mat.m22()).arg(mat.dx() * factor).arg(mat.dy() * factor);
}
 
QString XPSExPlug::MatrixToStr(QTransform &mat)
{
QString cc("%1, %2, %3, %4, %5, %6");
/trunk/Scribus/scribus/plugins/export/xpsexport/xpsexplugin.h
58,8 → 58,9
 
class XPSExPlug : public QObject
{
Q_OBJECT
Q_OBJECT
 
friend class XPSPainter;
public:
/*!
\author Franz Schmid
81,7 → 82,6
void processLineItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void processImageItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void processTextItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void processPathTextItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void processSymbolItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void processTableItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void paintBorder(const TableBorder &border, const QPointF &start, const QPointF &end, const QPointF &startOffsetFactors, const QPointF &endOffsetFactors, QDomElement &ob);
89,7 → 89,7
void processSymbolStroke(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void processArrows(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void drawArrow(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root, FPointArray &arrow);
QString embedFont(const ScFace *font, QDomElement &rel_root);
QString embedFont(const ScFace font, QDomElement &rel_root);
void GetMultiStroke(struct SingleLine *sl, QDomElement &parentElem);
void getStrokeStyle(PageItem *Item, QDomElement &parentElem, QDomElement &rel_root, double xOffset, double yOffset, bool forArrow = false);
void getFillStyle(PageItem *Item, QDomElement &parentElem, QDomElement &rel_root, double xOffset, double yOffset, bool withTransparency = true);
104,6 → 104,7
QString FToStr(double c);
QString IToStr(int c);
QString MatrixToStr(QTransform &mat);
QString MatrixToStr(QTransform &mat, double factor);
int hex2int(char hex);
bool checkForFallback(PageItem *Item);
ScribusDoc* m_Doc;
/trunk/Scribus/scribus/pslib.cpp
55,13 → 55,158
#include "scstreamfilter_ascii85.h"
#include "scstreamfilter_flate.h"
#include "tableutils.h"
#include "text/textlayoutpainter.h"
#include "ui/multiprogressdialog.h"
#include "util.h"
#include "util_formats.h"
#include "util_math.h"
#include "text/boxes.h"
 
using namespace TableUtils;
 
class PSPainter:public TextLayoutPainter
{
ScribusDoc* m_Doc;
uint m_argh;
ScPage* m_page;
bool m_sep;
bool m_farb;
bool m_master;
PSLib* m_ps;
 
void applyTransform()
{
if (matrix() != QTransform())
{
m_ps->PutStream(m_ps->MatrixToStr(1.0, 0.0, 0.0, -1.0, x(), 0.0) + "\n");
m_ps->PutStream(m_ps->MatrixToStr(matrix().m11(), -matrix().m12(), matrix().m21(), -matrix().m22(), matrix().dx(), -matrix().dy()) + "\n");
m_ps->PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
}
}
 
public:
PSPainter(ScribusDoc* Doc, uint argh, ScPage* page, bool sep, bool farb, bool master, PSLib* ps):
m_Doc(Doc),
m_argh(argh),
m_page(page),
m_sep(sep),
m_farb(farb),
m_master(master),
m_ps(ps)
{}
 
void drawGlyph(const GlyphLayout gl);
void drawGlyphOutline(const GlyphLayout gl, bool fill);
void drawLine(QPointF start, QPointF end);
void drawRect(QRectF rect);
void drawObject(PageItem* item);
};
 
void PSPainter::drawGlyph(const GlyphLayout gl)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
m_ps->PS_save();
applyTransform();
m_ps->PS_translate(x(), -(y() - fontSize()));
if (gl.scaleH != 1.0)
m_ps->PS_scale(gl.scaleH, 1);
if (gl.scaleV != 1.0)
{
m_ps->PS_translate(0, -(fontSize() - fontSize() * gl.scaleV));
m_ps->PS_scale(1, gl.scaleV);
}
if (fillColor().color != CommonStrings::None)
m_ps->putColorNoDraw(fillColor().color, fillColor().shade);
m_ps->PS_showSub(gl.glyph, m_ps->FontSubsetMap[font().scName()], fontSize(), false);
m_ps->PS_restore();
}
 
void PSPainter::drawGlyphOutline(const GlyphLayout gl, bool fill)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
int h, s, v, k;
QVector<double> dum;
dum.clear();
m_ps->PS_save();
applyTransform();
if (strokeColor().color != CommonStrings::None)
{
m_ps->PS_setlinewidth(strokeWidth());
m_ps->PS_setcapjoin(Qt::FlatCap, Qt::MiterJoin);
m_ps->PS_setdash(Qt::SolidLine, 0, dum);
m_ps->PS_translate(x(), -(y() - fontSize()));
FPointArray gly = font().glyphOutline(gl.glyph);
QTransform chma;
chma.scale((fontSize() * gl.scaleH) / 10.0, (fontSize() * gl.scaleV) / 10.0);
gly.map(chma);
m_ps->PS_translate(0, -(fontSize() - fontSize() * gl.scaleV));
m_ps->SetColor(strokeColor().color, strokeColor().shade, &h, &s, &v, &k);
m_ps->PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
m_ps->SetClipPath(&gly, true);
m_ps->PS_closepath();
m_ps->putColor(strokeColor().color, strokeColor().shade, false);
 
if (gl.scaleH != 1.0 || gl.scaleV != 1.0)
m_ps->PS_scale(gl.scaleH, gl.scaleV);
if (fill)
m_ps->putColorNoDraw(fillColor().color, fillColor().shade);
m_ps->PS_showSub(gl.glyph, m_ps->FontSubsetMap[font().scName()], fontSize(), false);
}
m_ps->PS_restore();
}
 
void PSPainter::drawRect(QRectF rect)
{
int h, s, v, k;
m_ps->PS_save();
applyTransform();
m_ps->PS_moveto(x() + rect.x(), -y() - rect.y());
m_ps->PS_lineto(x() + rect.x() + rect.width(), -y() - rect.y());
m_ps->PS_lineto(x() + rect.x() + rect.width(), -y() - rect.y() - rect.height());
m_ps->PS_lineto(x() + rect.x(), -y() - rect.y() - rect.height());
m_ps->PS_closepath();
m_ps->SetColor(fillColor().color, fillColor().shade, &h, &s, &v, &k);
m_ps->PS_setcmykcolor_fill(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
m_ps->putColor(fillColor().color, fillColor().shade, true);
m_ps->PS_restore();
}
 
void PSPainter::drawLine(QPointF start, QPointF end)
{
int h, s, v, k ;
QVector<double> dum;
dum.clear();
m_ps->PS_save();
applyTransform();
if (fillColor().color != CommonStrings::None)
{
m_ps->PS_setcapjoin(Qt::FlatCap, Qt::MiterJoin);
m_ps->PS_setdash(Qt::SolidLine, 0, dum);
m_ps->SetColor(fillColor().color,fillColor().shade, &h, &s, &v, &k);
m_ps->PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
m_ps->PS_setlinewidth(strokeWidth());
m_ps->PS_moveto(x() + start.x(), -y() - start.y());
m_ps->PS_lineto(x() + end.x(), -y() - end.y());
m_ps->putColor(fillColor().color, fillColor().shade, false);
m_ps->PS_restore();
}
 
void PSPainter::drawObject(PageItem* item)
{
m_ps->PS_save();
m_ps->PS_translate(x(), -y());
applyTransform();
if (scaleH() != 1 || scaleV() != 1)
m_ps->PS_scale(scaleH(), scaleV());
m_ps->ProcessItem(m_Doc, m_page, item, m_argh, m_sep, m_farb, m_master, true);
m_ps->PS_restore();
}
 
PSLib::PSLib(PrintOptions &options, bool psart, SCFonts &AllFonts, QMap<QString, QMap<uint, FPointArray> > DocFonts, ColorList DocColors, bool pdf, bool spot)
{
Options = options;
555,7 → 700,7
PutStream("%%Page: " + IToStr(Seiten) + " " + IToStr(Seiten) + "\n");
PutStream("%%PageOrientation: ");
// when creating EPS files determine the orientation from the bounding box
if (!psExport)
if (!psExport)
{
if ((pg->width() - Ma->left() - Ma->right()) <= (pg->height() - Ma->bottom() - Ma->top()))
PutStream("Portrait\n");
1665,14 → 1810,8
 
bool PSLib::ProcessItem(ScribusDoc* Doc, ScPage* a, PageItem* c, uint PNr, bool sep, bool farb, bool master, bool embedded, bool useTemplate)
{
double tsz;
int h, s, v, k;
int d;
int savedOwnPage;
//ScText *hl;
QVector<double> dum;
QChar chstr;
QString tmps;
if (c->printEnabled())
{
fillRule = true;
2156,401 → 2295,7
PS_restore();
}
}
savedOwnPage = c->OwnPage;
c->OwnPage = PNr-1;
c->asPathText()->layout();
c->OwnPage = savedOwnPage;
for (d = 0; d < c->maxCharsInFrame(); ++d)
{
// hl = c->asPathText()->itemRenderText.item_p(d);
chstr = c->asPathText()->itemRenderText.text(d);
if ((chstr == QChar(13)) || (chstr == QChar(30)) || (chstr == QChar(9)) || (chstr == QChar(28)))
continue;
const CharStyle & style(c->asPathText()->itemRenderText.charStyle(d));
const PathData& pdata(c->textLayout.point(d));
const GlyphLayout* glyphs(c->asPathText()->itemRenderText.getGlyphs(d));
PageItem* embItem = c->asPathText()->itemRenderText.hasObject(d)?
c->asPathText()->itemRenderText.object(d) : NULL;
QPointF tangt = QPointF( cos(pdata.PRot), sin(pdata.PRot) );
tsz = style.fontSize();
if (chstr == QChar(29))
chstr = ' ';
if (chstr == QChar(0xA0))
chstr = ' ';
if (style.effects() & ScStyle_AllCaps)
{
if (chstr.toUpper() != chstr)
chstr = chstr.toUpper();
}
if (style.effects() & ScStyle_SmallCaps)
{
if (chstr.toUpper() != chstr)
{
tsz = style.fontSize() * Doc->typographicPrefs().valueSmallCaps / 100;
chstr = chstr.toUpper();
}
}
if (style.effects() & ScStyle_Superscript)
tsz = style.fontSize() * Doc->typographicPrefs().scalingSuperScript / 100;
if (style.effects() & ScStyle_Subscript)
tsz = style.fontSize() * Doc->typographicPrefs().scalingSubScript / 100;
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
if (embItem != NULL)
{
PS_save();
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -pdata.PDx, 0.0) + "\n");
if (c->textPathFlipped)
{
PutStream("[1 0 0 -1 0 0]\n");
PutStream("[0 0 0 0 0 0] concatmatrix\n"); //???????
}
if (c->textPathType == 0)
PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), pdata.PtransX, -pdata.PtransY) + "\n");
else if (c->textPathType == 1)
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else if (c->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x()< 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else
PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
}
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
// PS_translate(0, (tsz / 10.0));
if (c->BaseOffs != 0)
PS_translate(0, -c->BaseOffs);
if (style.scaleH() != 1000)
PS_scale(style.scaleH() / 1000.0, 1);
QList<PageItem*> emG;
if (embItem->isGroup())
emG = embItem->getItemList();
else
emG.append(embItem);
for (int em = 0; em < emG.count(); ++em)
{
PageItem* embedded = emG.at(em);
PS_save();
PS_translate(embedded->gXpos * (style.scaleH() / 1000.0), ((embedded->gHeight * (style.scaleV() / 1000.0)) - embedded->gYpos * (style.scaleV() / 1000.0)));
if (style.baselineOffset() != 0)
PS_translate(0, embedded->gHeight * (style.baselineOffset() / 1000.0));
if (style.scaleH() != 1000)
PS_scale(style.scaleH() / 1000.0, 1);
if (style.scaleV() != 1000)
PS_scale(1, style.scaleV() / 1000.0);
ProcessItem(Doc, a, embedded, PNr, sep, farb, master, true);
PS_restore();
}
PS_restore();
continue;
}
/* Subset all TTF Fonts until the bug in the TTF-Embedding Code is fixed */
if (FontSubsetMap.contains(style.font().scName()))
{
// uint chr = chstr.unicode();
uint chr = style.font().char2CMap(chstr);
if (style.font().canRender(chstr))
{
PS_save();
if (style.fillColor() != CommonStrings::None)
{
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -pdata.PDx, 0.0) + "\n");
if (c->textPathFlipped)
{
PutStream("[1.0 0.0 0.0 -1.0 0.0 0.0]\n");
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\n");
}
if (c->textPathType == 0)
PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), pdata.PtransX, -pdata.PtransY) + "\n");
else if (c->textPathType == 1)
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else if (c->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x() < 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else
PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
}
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
PS_translate(0, (tsz / 10.0));
if (c->BaseOffs != 0)
PS_translate(0, -c->BaseOffs);
if (glyphs->xoffset !=0 || glyphs->yoffset != 0)
PS_translate(glyphs->xoffset, -glyphs->yoffset);
if (style.scaleH() != 1000)
PS_scale(style.scaleH() / 1000.0, 1);
if (((style.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr)) //FIXME && (chstr != QChar(13)))
|| ((style.effects() & ScStyle_UnderlineWords) && !chstr.isSpace() && !SpecialChars::isBreak(chstr)))
{
PS_save();
PS_translate(0, -(tsz / 10.0));
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
{
if (style.underlineOffset() != -1)
Upos = (style.underlineOffset() / 1000.0) * (style.font().descent(style.fontSize() / 10.0));
else
Upos = style.font().underlinePos(style.fontSize() / 10.0);
if (style.underlineWidth() != -1)
Uwid = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().underlinePos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(Uwid);
if (style.effects() & ScStyle_Subscript)
{
PS_moveto(glyphs->xoffset , Upos);
PS_lineto(glyphs->xoffset+Ulen, Upos);
}
else
{
PS_moveto(glyphs->xoffset , glyphs->yoffset+Upos);
PS_lineto(glyphs->xoffset+Ulen, glyphs->yoffset+Upos);
}
putColor(style.fillColor(), style.fillShade(), false);
PS_restore();
}
if (chstr != ' ')
{
if ((style.effects() & ScStyle_Shadowed) && (style.strokeColor() != CommonStrings::None))
{
PS_save();
PS_translate(style.fontSize() * style.shadowXOffset() / 10000.0, style.fontSize() * style.shadowYOffset() / 10000.0);
putColorNoDraw(style.strokeColor(), style.strokeShade());
PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, false);
PS_restore();
}
putColorNoDraw(style.fillColor(), style.fillShade());
PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, false);
if ((style.effects() & ScStyle_Outline))
{
if ((style.strokeColor() != CommonStrings::None) && ((tsz * style.outlineWidth() / 10000.0) != 0))
{
PS_save();
PS_setlinewidth(tsz * style.outlineWidth() / 10000.0);
putColorNoDraw(style.strokeColor(), style.strokeShade());
PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, true);
PS_restore();
}
}
}
if ((style.effects() & ScStyle_Strikethrough) && (chstr != SpecialChars::PARSEP))
{
PS_save();
PS_translate(0, -(tsz / 10.0));
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
{
if (style.strikethruOffset() != -1)
Upos = (style.strikethruOffset() / 1000.0) * (style.font().ascent(style.fontSize() / 10.0));
else
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
if (style.strikethruWidth() != -1)
Uwid = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(Uwid);
PS_moveto(glyphs->xoffset , Upos);
PS_lineto(glyphs->xoffset+Ulen, Upos);
putColor(style.fillColor(), style.fillShade(), false);
PS_restore();
}
}
PS_restore();
}
}
else
{
uint glyph = glyphs->glyph;
PS_selectfont(style.font().replacementName(), tsz / 10.0);
PS_save();
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -pdata.PDx, 0.0) + "\n");
if (c->textPathFlipped)
{
PutStream("[1.0 0.0 0.0 -1.0 0.0 0.0]\n");
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\n");
}
if (c->textPathType == 0)
PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), pdata.PtransX, -pdata.PtransY) + "\n");
else if (c->textPathType == 1)
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else if (c->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x() < 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else
PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
}
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
if (c->BaseOffs != 0)
PS_translate(0, -c->BaseOffs);
if (glyphs->xoffset !=0 || glyphs->yoffset != 0)
PS_translate(glyphs->xoffset, -glyphs->yoffset);
if (((style.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr)) //FIXME && (chstr != QChar(13)))
|| ((style.effects() & ScStyle_UnderlineWords) && !chstr.isSpace() && !SpecialChars::isBreak(chstr)))
{
PS_save();
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
{
if (style.underlineOffset() != -1)
Upos = (style.underlineOffset() / 1000.0) * (style.font().descent(style.fontSize() / 10.0));
else
Upos = style.font().underlinePos(style.fontSize() / 10.0);
if (style.underlineWidth() != -1)
Uwid = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().underlinePos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(Uwid);
if (style.effects() & ScStyle_Subscript)
{
PS_moveto(glyphs->xoffset , Upos);
PS_lineto(glyphs->xoffset+Ulen, Upos);
}
else
{
PS_moveto(glyphs->xoffset , glyphs->yoffset+Upos);
PS_lineto(glyphs->xoffset+Ulen, glyphs->yoffset+Upos);
}
putColor(style.fillColor(), style.fillShade(), false);
PS_restore();
}
if (chstr != ' ')
{
if ((style.effects() & ScStyle_Shadowed) && (style.strokeColor() != CommonStrings::None))
{
PS_save();
PS_translate(style.fontSize() * style.shadowXOffset() / 10000.0, style.fontSize() * style.shadowYOffset() / 10000.0);
PS_show_xyG(style.font().replacementName(), glyph, 0, 0, style.strokeColor(), style.strokeShade());
PS_restore();
}
PS_show_xyG(style.font().replacementName(), glyph, 0, 0, style.fillColor(), style.fillShade());
if ((style.effects() & ScStyle_Outline))
{
if ((style.strokeColor() != CommonStrings::None) && ((tsz * style.outlineWidth() / 10000.0) != 0))
{
uint gl = style.font().char2CMap(chstr);
FPointArray gly = style.font().glyphOutline(gl);
QTransform chma;
chma.scale(tsz / 100.0, tsz / 100.0);
gly.map(chma);
PS_save();
PS_setlinewidth(tsz * style.outlineWidth() / 10000.0);
PS_translate(0, tsz / 10.0);
SetColor(style.strokeColor(), style.strokeShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
SetClipPath(&gly);
PS_closepath();
putColor(style.strokeColor(), style.strokeShade(), false);
PS_restore();
}
}
}
if ((style.effects() & ScStyle_Strikethrough) && (chstr != SpecialChars::PARSEP))
{
PS_save();
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
{
if (style.strikethruOffset() != -1)
Upos = (style.strikethruOffset() / 1000.0) * (style.font().ascent(style.fontSize() / 10.0));
else
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
if (style.strikethruWidth() != -1)
Uwid = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(Uwid);
PS_moveto(glyphs->xoffset , Upos);
PS_lineto(glyphs->xoffset+Ulen, Upos);
putColor(style.fillColor(), style.fillShade(), false);
PS_restore();
}
PS_restore();
}
}
setTextSt(Doc, c, PNr-1, a, sep, farb, master);
break;
case PageItem::Symbol:
if (m_Doc->docPatterns.contains(c->pattern()))
3221,10 → 2966,6
}
else if (ite->asPathText())
{
double tsz;
int d;
//ScText *hl;
QChar chstr;
PS_save();
PS_translate(ite->xPos() - mPage->xOffset(), mPage->height() - (ite->yPos() - mPage->yOffset()));
if (ite->PoShow)
3270,400 → 3011,7
PS_restore();
}
}
int savedOwnPage = ite->OwnPage;
ite->OwnPage = PNr;
ite->asPathText()->layout();
ite->OwnPage = savedOwnPage;
for (d = 0; d < ite->maxCharsInFrame(); ++d)
{
//hl = ite->asPathText()->itemRenderText.item_p(d);
chstr = ite->asPathText()->itemRenderText.text(d);
const CharStyle & style(ite->asPathText()->itemRenderText.charStyle(d));
if ((chstr == QChar(13)) || (chstr == QChar(30)) || (chstr == QChar(9)) || (chstr == QChar(28)))
continue;
const PathData& pdata(ite->textLayout.point(d));
const GlyphLayout* glyphs(ite->asPathText()->itemRenderText.getGlyphs(d));
PageItem* embItem = ite->asPathText()->itemRenderText.hasObject(d)?
ite->asPathText()->itemRenderText.object(d) : NULL;
QPointF tangt = QPointF( cos(pdata.PRot), sin(pdata.PRot) );
tsz = style.fontSize();
if (chstr == QChar(29))
chstr = ' ';
if (chstr == QChar(0xA0))
chstr = ' ';
if (style.effects() & ScStyle_AllCaps)
{
if (chstr.toUpper() != chstr)
chstr = chstr.toUpper();
}
if (style.effects() & ScStyle_SmallCaps)
{
if (chstr.toUpper() != chstr)
{
tsz = style.fontSize() * Doc->typographicPrefs().valueSmallCaps / 100;
chstr = chstr.toUpper();
}
}
if (style.effects() & ScStyle_Superscript)
tsz = style.fontSize() * Doc->typographicPrefs().scalingSuperScript / 100;
if (style.effects() & ScStyle_Subscript)
tsz = style.fontSize() * Doc->typographicPrefs().scalingSubScript / 100;
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
if (embItem != NULL)
{
PS_save();
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -pdata.PDx, 0.0) + "\n");
if (ite->textPathFlipped)
{
PutStream("[1 0 0 -1 0 0]\n");
PutStream("[0 0 0 0 0 0] concatmatrix\n"); //???????
}
if (ite->textPathType == 0)
PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), pdata.PtransX, -pdata.PtransY) + "\n");
else if (ite->textPathType == 1)
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else if (ite->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x()< 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else
PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
}
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
// PS_translate(0, (tsz / 10.0));
if (ite->BaseOffs != 0)
PS_translate(0, -ite->BaseOffs);
if (style.scaleH() != 1000)
PS_scale(style.scaleH() / 1000.0, 1);
QList<PageItem*> emG;
if (embItem->isGroup())
emG = embItem->getItemList();
else
emG.append(embItem);
for (int em = 0; em < emG.count(); ++em)
{
PageItem* embedded = emG.at(em);
PS_save();
PS_translate(embedded->gXpos * (style.scaleH() / 1000.0), ((embedded->gHeight * (style.scaleV() / 1000.0)) - embedded->gYpos * (style.scaleV() / 1000.0)));
if (style.baselineOffset() != 0)
PS_translate(0, embedded->gHeight * (style.baselineOffset() / 1000.0));
if (style.scaleH() != 1000)
PS_scale(style.scaleH() / 1000.0, 1);
if (style.scaleV() != 1000)
PS_scale(1, style.scaleV() / 1000.0);
ProcessItem(Doc, mPage, embedded, PNr, sep, farb, true, true);
PS_restore();
}
PS_restore();
continue;
}
/* Subset all TTF Fonts until the bug in the TTF-Embedding Code is fixed */
if (FontSubsetMap.contains(style.font().scName()))
{
// uint chr = chstr.unicode();
uint chr = style.font().char2CMap(chstr);
if (style.font().canRender(chstr))
{
PS_save();
if (style.fillColor() != CommonStrings::None)
{
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -pdata.PDx, 0.0) + "\n");
if (ite->textPathFlipped)
{
PutStream("[1.0 0.0 0.0 -1.0 0.0 0.0]\n");
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\n");
}
if (ite->textPathType == 0)
PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), pdata.PtransX, -pdata.PtransY) + "\n");
else if (ite->textPathType == 1)
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else if (ite->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x() < 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else
PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
}
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
PS_translate(0, (tsz / 10.0));
if (ite->BaseOffs != 0)
PS_translate(0, -ite->BaseOffs);
if (glyphs->xoffset !=0 || glyphs->yoffset != 0)
PS_translate(glyphs->xoffset, -glyphs->yoffset);
if (style.scaleH() != 1000)
PS_scale(style.scaleH() / 1000.0, 1);
if (((style.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr)) //FIXME && (chstr != QChar(13)))
|| ((style.effects() & ScStyle_UnderlineWords) && !chstr.isSpace() && !SpecialChars::isBreak(chstr)))
{
PS_save();
PS_translate(0, -(tsz / 10.0));
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
{
if (style.underlineOffset() != -1)
Upos = (style.underlineOffset() / 1000.0) * (style.font().descent(style.fontSize() / 10.0));
else
Upos = style.font().underlinePos(style.fontSize() / 10.0);
if (style.underlineWidth() != -1)
Uwid = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().underlinePos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(Uwid);
if (style.effects() & ScStyle_Subscript)
{
PS_moveto(glyphs->xoffset , Upos);
PS_lineto(glyphs->xoffset+Ulen, Upos);
}
else
{
PS_moveto(glyphs->xoffset , glyphs->yoffset+Upos);
PS_lineto(glyphs->xoffset+Ulen, glyphs->yoffset+Upos);
}
putColor(style.fillColor(), style.fillShade(), false);
PS_restore();
}
if (chstr != ' ')
{
if ((style.effects() & ScStyle_Shadowed) && (style.strokeColor() != CommonStrings::None))
{
PS_save();
PS_translate(style.fontSize() * style.shadowXOffset() / 10000.0, style.fontSize() * style.shadowYOffset() / 10000.0);
putColorNoDraw(style.strokeColor(), style.strokeShade());
PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, false);
PS_restore();
}
putColorNoDraw(style.fillColor(), style.fillShade());
PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, false);
if ((style.effects() & ScStyle_Outline))
{
if ((style.strokeColor() != CommonStrings::None) && ((tsz * style.outlineWidth() / 10000.0) != 0))
{
PS_save();
PS_setlinewidth(tsz * style.outlineWidth() / 10000.0);
putColorNoDraw(style.strokeColor(), style.strokeShade());
PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, true);
PS_restore();
}
}
}
if ((style.effects() & ScStyle_Strikethrough) && (chstr != SpecialChars::PARSEP))
{
PS_save();
PS_translate(0, -(tsz / 10.0));
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
{
if (style.strikethruOffset() != -1)
Upos = (style.strikethruOffset() / 1000.0) * (style.font().ascent(style.fontSize() / 10.0));
else
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
if (style.strikethruWidth() != -1)
Uwid = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(Uwid);
PS_moveto(glyphs->xoffset , Upos);
PS_lineto(glyphs->xoffset+Ulen, Upos);
putColor(style.fillColor(), style.fillShade(), false);
PS_restore();
}
}
PS_restore();
}
}
else
{
uint glyph = glyphs->glyph;
PS_selectfont(style.font().replacementName(), tsz / 10.0);
PS_save();
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -pdata.PDx, 0.0) + "\n");
if (ite->textPathFlipped)
{
PutStream("[1.0 0.0 0.0 -1.0 0.0 0.0]\n");
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\n");
}
if (ite->textPathType == 0)
PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), pdata.PtransX, -pdata.PtransY) + "\n");
else if (ite->textPathType == 1)
PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else if (ite->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x() < 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
else
PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, pdata.PtransX, -pdata.PtransY) + "\n");
}
PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
if (ite->BaseOffs != 0)
PS_translate(0, -ite->BaseOffs);
if (glyphs->xoffset !=0 || glyphs->yoffset != 0)
PS_translate(glyphs->xoffset, -glyphs->yoffset);
if (((style.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr)) //FIXME && (chstr != QChar(13)))
|| ((style.effects() & ScStyle_UnderlineWords) && !chstr.isSpace() && !SpecialChars::isBreak(chstr)))
{
PS_save();
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
{
if (style.underlineOffset() != -1)
Upos = (style.underlineOffset() / 1000.0) * (style.font().descent(style.fontSize() / 10.0));
else
Upos = style.font().underlinePos(style.fontSize() / 10.0);
if (style.underlineWidth() != -1)
Uwid = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().underlinePos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(Uwid);
if (style.effects() & ScStyle_Subscript)
{
PS_moveto(glyphs->xoffset , Upos);
PS_lineto(glyphs->xoffset+Ulen, Upos);
}
else
{
PS_moveto(glyphs->xoffset , glyphs->yoffset+Upos);
PS_lineto(glyphs->xoffset+Ulen, glyphs->yoffset+Upos);
}
putColor(style.fillColor(), style.fillShade(), false);
PS_restore();
}
if (chstr != ' ')
{
if ((style.effects() & ScStyle_Shadowed) && (style.strokeColor() != CommonStrings::None))
{
PS_save();
PS_translate(style.fontSize() * style.shadowXOffset() / 10000.0, style.fontSize() * style.shadowYOffset() / 10000.0);
PS_show_xyG(style.font().replacementName(), glyph, 0, 0, style.strokeColor(), style.strokeShade());
PS_restore();
}
PS_show_xyG(style.font().replacementName(), glyph, 0, 0, style.fillColor(), style.fillShade());
if ((style.effects() & ScStyle_Outline))
{
if ((style.strokeColor() != CommonStrings::None) && ((tsz * style.outlineWidth() / 10000.0) != 0))
{
uint gl = style.font().char2CMap(chstr);
FPointArray gly = style.font().glyphOutline(gl);
QTransform chma;
chma.scale(tsz / 100.0, tsz / 100.0);
gly.map(chma);
PS_save();
PS_setlinewidth(tsz * style.outlineWidth() / 10000.0);
PS_translate(0, tsz / 10.0);
SetColor(style.strokeColor(), style.strokeShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
SetClipPath(&gly);
PS_closepath();
putColor(style.strokeColor(), style.strokeShade(), false);
PS_restore();
}
}
}
if ((style.effects() & ScStyle_Strikethrough) && (chstr != SpecialChars::PARSEP))
{
PS_save();
double Ulen = glyphs->xadvance;
double Upos, Uwid;
if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
{
if (style.strikethruOffset() != -1)
Upos = (style.strikethruOffset() / 1000.0) * (style.font().ascent(style.fontSize() / 10.0));
else
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
if (style.strikethruWidth() != -1)
Uwid = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
else
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
Upos += (style.fontSize() / 10.0) * glyphs->scaleV * (style.baselineOffset() / 1000.0);
if (style.fillColor() != CommonStrings::None)
if (style.fillColor() != CommonStrings::None)
{
SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(Uwid);
PS_moveto(glyphs->xoffset , Upos);
PS_lineto(glyphs->xoffset+Ulen, Upos);
putColor(style.fillColor(), style.fillShade(), false);
PS_restore();
}
PS_restore();
}
}
setTextSt(Doc, ite, PNr, mPage, sep, farb, true);
PS_restore();
}
if (!success)
5056,573 → 4404,11
*/
void PSLib::setTextSt(ScribusDoc* Doc, PageItem* ite, uint argh, ScPage* pg, bool sep, bool farb, bool master)
{
// qDebug() << QString("pslib setTextSt: ownPage=%1 pageNr=%2 OnMasterPage=%3;").arg(ite->OwnPage).arg(pg->pageNr()).arg(ite->OnMasterPage);
int tabCc = 0;
int savedOwnPage = ite->OwnPage;
double tabDist = ite->textToFrameDistLeft();
QList<ParagraphStyle::TabRecord> tTabValues;
 
ite->OwnPage = argh;
ite->layout();
ite->OwnPage = savedOwnPage;
if (ite->lineColor() != CommonStrings::None)
tabDist += ite->lineWidth() / 2.0;
 
uint llp = 0;
while (llp < ite->textLayout.lines())
{
LineSpec ls = ite->textLayout.line(llp++);
const ParagraphStyle& LineStyle = ite->itemText.paragraphStyle(ls.firstItem);
if (LineStyle.backgroundColor() != CommonStrings::None)
{
double y0 = ls.y;
double y2 = ls.y;
double ascent = ls.ascent;
double descent = ls.descent;
double rMarg = LineStyle.rightMargin();
double lMarg = ls.colLeft;
double adjX = 0;
if (LineStyle.firstIndent() <= 0)
adjX += LineStyle.leftMargin() + LineStyle.firstIndent();
while (llp < ite->textLayout.lines())
{
ls = ite->textLayout.line(llp);
if ((ls.colLeft > lMarg) || (ite->itemText.paragraphStyle(ls.firstItem) != LineStyle))
{
if (y2 == 0)
y2 = y0;
break;
}
if (ite->itemText.text(ls.lastItem) == SpecialChars::PARSEP)
{
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < ite->textLayout.lines())
{
if ((ite->textLayout.line(llp + 1).lastItem - ite->textLayout.line(llp + 1).firstItem) > 0)
descent += LineStyle.lineSpacing() - (ls.descent + ite->textLayout.line(llp + 1).ascent);
}
llp++;
break;
}
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < ite->textLayout.lines())
descent += LineStyle.lineSpacing() - (ls.descent + ite->textLayout.line(llp + 1).ascent);
llp++;
}
QRectF scr(lMarg + adjX, y0 - ascent, ite->asTextFrame()->columnWidth() - adjX - rMarg, y2 - y0 + descent + ascent);
PS_save();
SetPathAndClip(ite->PoLine, true);
int h, s, v, k;
SetColor(LineStyle.backgroundColor(), LineStyle.backgroundShade(), &h, &s, &v, &k);
PS_setcmykcolor_fill(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
PS_moveto(scr.x(), -scr.y());
PS_lineto(scr.x() + scr.width(), -scr.y());
PS_lineto(scr.x() + scr.width(), -scr.y() - scr.height());
PS_lineto(scr.x(), -scr.y() - scr.height());
PS_closepath();
putColor(LineStyle.backgroundColor(), LineStyle.backgroundShade(), true);
PS_restore();
}
}
 
for (uint ll=0; ll < ite->textLayout.lines(); ++ll)
{
LineSpec ls = ite->textLayout.line(ll);
tabDist = ls.x;
double CurX = ls.x;
double CurXB = ls.x;
QRectF scrG;
QString oldBack = "";
double oldShade = 100;
int last = qMin(ls.lastItem, ite->itemText.length() - 1);
for (int a = ls.firstItem; a <= last; ++a)
{
const GlyphLayout* glyphs(ite->itemText.getGlyphs(a));
const CharStyle& charStyle(ite->itemText.charStyle(a));
if (charStyle.backColor() != CommonStrings::None)
{
// This code is for rendering character background color.
int h, s, v, k;
SetColor(charStyle.backColor(), charStyle.backShade(), &h, &s, &v, &k);
PS_setcmykcolor_fill(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
const ParagraphStyle& LineStyle = ite->itemText.paragraphStyle(ls.firstItem);
double y1 = ls.y;
double hl = ls.height;
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
hl = Doc->guidesPrefs().valueBaselineGrid;
else if (LineStyle.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
hl = LineStyle.lineSpacing();
if (ls.isFirstLine)
{
if (ite->textLayout.lines() == 1)
hl = ls.ascent + ls.descent;
if (LineStyle.hasDropCap() && (a == ls.firstItem))
hl *= LineStyle.dropCapLines();
if (LineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
y1 -= LineStyle.lineSpacing();
else if (ite->firstLineOffset() == FLOPRealGlyphHeight || ite->firstLineOffset() == FLOPFontAscent)
y1 -= ls.ascent;
else
y1 -= LineStyle.lineSpacing();
}
else
y1 -= ls.ascent + (hl - (ls.ascent + ls.descent)) / 2.0;
QRectF scr;
if (ite->itemText.hasObject(a))
{
PageItem* obj = ite->itemText.object(a);
double ww = (obj->width() + obj->lineWidth()) * glyphs->scaleH;
double hh = (obj->height() + obj->lineWidth()) * glyphs->scaleV;
scr = QRectF(CurXB, ls.y - hh, ww , hh);
}
else
scr = QRectF(CurXB, y1, glyphs->wide(), hl);
if ((oldBack == "") || ((oldBack == charStyle.backColor()) && (oldShade == charStyle.backShade())))
scrG |= scr;
else if ((oldBack != charStyle.backColor()) || (oldShade != charStyle.backShade()))
{
PS_save();
PS_moveto(scrG.x(), -scrG.y());
PS_lineto(scrG.x() + scrG.width(), -scrG.y());
PS_lineto(scrG.x() + scrG.width(), -scrG.y() - scrG.height());
PS_lineto(scrG.x(), -scrG.y() - scrG.height());
PS_closepath();
SetColor(oldBack, oldShade, &h, &s, &v, &k);
PS_setcmykcolor_fill(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
putColor(oldBack, oldShade, true);
PS_restore();
scrG = scr;
}
oldBack = charStyle.backColor();
oldShade = charStyle.backShade();
}
else
{
if (!scrG.isNull())
{
PS_save();
PS_moveto(scrG.x(), -scrG.y());
PS_lineto(scrG.x() + scrG.width(), -scrG.y());
PS_lineto(scrG.x() + scrG.width(), -scrG.y() - scrG.height());
PS_lineto(scrG.x(), -scrG.y() - scrG.height());
PS_closepath();
putColor(oldBack, oldShade, true);
PS_restore();
}
oldBack = "";
oldShade = 100;
scrG = QRectF();
}
CurXB += glyphs->wide();
}
if (!scrG.isNull())
{
PS_save();
PS_moveto(scrG.x(), -scrG.y());
PS_lineto(scrG.x() + scrG.width(), -scrG.y());
PS_lineto(scrG.x() + scrG.width(), -scrG.y() - scrG.height());
PS_lineto(scrG.x(), -scrG.y() - scrG.height());
PS_closepath();
putColor(oldBack, oldShade, true);
PS_restore();
}
 
for (int d = ls.firstItem; d <= ls.lastItem; ++d)
{
//ScText *hl = ite->itemText.item_p(d);
QChar chr = ite->itemText.text(d);
const CharStyle & cstyle(ite->itemText.charStyle(d));
const ParagraphStyle& pstyle(ite->itemText.paragraphStyle(d));
const GlyphLayout* glyphs(ite->itemText.getGlyphs(d));
LayoutFlags flags = ite->itemText.flags(d);
// if ((hl->ch == QChar(13)) || (hl->ch == QChar(10)) || (hl->ch == QChar(28)) || (hl->ch == QChar(27)) || (hl->ch == QChar(26)))
// continue;
if (flags & ScLayout_SuppressSpace)
continue;
tTabValues = pstyle.tabValues();
if (flags & ScLayout_StartOfLine)
tabCc = 0;
if ((chr == SpecialChars::TAB) && (tTabValues.count() != 0))
{
QChar tabFillChar;
const TabLayout* tabLayout = dynamic_cast<const TabLayout*>(glyphs->more);
if (tabLayout)
tabFillChar = tabLayout->fillChar;
if (!tabFillChar.isNull())
{
//ScText hl2;
//static_cast<CharStyle&>(hl2) = static_cast<const CharStyle&>(*hl);
const GlyphLayout * const gl = glyphs->more;
double scale = gl ? gl->scaleV : 1.0;
double wt = cstyle.font().charWidth(tabFillChar, cstyle.fontSize() * scale / 10.0);
double len = glyphs->xadvance;
int coun = static_cast<int>(len / wt);
// JG - #6728 : update code according to fillInTabLeaders() and PageItem::layout()
double sPos = 0.0 /*CurX - len + cstyle.fontSize() / 10.0 * 0.7 + 1*/;
//hl2.ch = tabFillChar;
//hl2.setTracking(0);
//hl2.setScaleH(1000);
//hl2.setScaleV(1000);
//hl2.glyph.glyph = cstyle.font().char2CMap(tabFillChar);
//hl2.glyph.yoffset = glyphs->yoffset;
GlyphLayout gl2 = *gl;
gl2.glyph = cstyle.font().char2CMap(tabFillChar);
gl2.yoffset = glyphs->yoffset;
CharStyle shadow(cstyle);
shadow.setFillColor(cstyle.strokeColor());
for (int cx = 0; cx < coun; ++cx)
{
gl2.xoffset = sPos + wt * cx;
if ((cstyle.effects() & ScStyle_Shadowed) && (cstyle.strokeColor() != CommonStrings::None))
{
//ScText hl3;
//static_cast<CharStyle&>(hl3) = static_cast<const CharStyle&>(hl2);
//hl3.ch = hl2.ch;
//hl3.glyph.glyph = hl2.glyph.glyph;
//hl3.setFillColor(hl2.strokeColor());
//hl3.glyph.yoffset = hl2.glyph.yoffset - (hl2.fontSize() * hl2.shadowYOffset() / 10000.0);
//hl3.glyph.xoffset = hl2.glyph.xoffset + (hl2.fontSize() * hl2.shadowXOffset() / 10000.0);
GlyphLayout gl3 = gl2;
gl3.yoffset = gl2.yoffset - (cstyle.fontSize() * cstyle.shadowYOffset() / 10000.0);
gl3.xoffset = gl2.xoffset + (cstyle.fontSize() * cstyle.shadowXOffset() / 10000.0);
setTextCh(Doc, ite, CurX, ls.y, argh, d, tabFillChar, &gl3, shadow, pstyle, pg, sep, farb, master);
}
setTextCh(Doc, ite, CurX, ls.y, argh, d, tabFillChar, &gl2, cstyle, pstyle, pg, sep, farb, master);
}
}
tabCc++;
}
if (chr == SpecialChars::TAB) {
CurX += glyphs->wide();
continue;
}
if ((cstyle.effects() & ScStyle_Shadowed) && (cstyle.strokeColor() != CommonStrings::None))
{
const GlyphLayout *gl1 = glyphs;
GlyphLayout* gl2 = new GlyphLayout(*gl1);
GlyphLayout* gl3 = gl2;
while (gl1->more)
{
gl2->more = new GlyphLayout(*gl1->more);
gl2->more->yoffset -= (cstyle.fontSize() * cstyle.shadowYOffset() / 10000.0);
gl2->more->xoffset += (cstyle.fontSize() * cstyle.shadowXOffset() / 10000.0);
gl2->more->more = NULL;
gl1 = gl1->more;
gl2 = gl2->more;
}
CharStyle shadowed(cstyle);
shadowed.setFillColor(cstyle.strokeColor());
shadowed.setFillShade(cstyle.strokeShade());
gl2->xadvance = glyphs->xadvance;
gl2->yadvance = glyphs->yadvance;
gl2->yoffset = glyphs->yoffset - (cstyle.fontSize() * cstyle.shadowYOffset() / 10000.0);
gl2->xoffset = glyphs->xoffset + (cstyle.fontSize() * cstyle.shadowXOffset() / 10000.0);
gl2->scaleH = glyphs->scaleH;
gl2->scaleV = glyphs->scaleV;
setTextCh(Doc, ite, CurX, ls.y, argh, d, chr, gl2, shadowed, pstyle, pg, sep, farb, master);
while (gl3->more) {
GlyphLayout* more = gl3->more;
gl3->more = gl3->more->more;
delete more;
}
delete gl3;
}
setTextCh(Doc, ite, CurX, ls.y, argh, d, chr, glyphs, cstyle, pstyle, pg, sep, farb, master);
// Unneeded now that glyph xadvance is set appropriately for inline objects by PageItem_TextFrame::layout() - JG
/*if (hl->ch == SpecialChars::OBJECT)
{
InlineFrame& embedded(const_cast<InlineFrame&>(hl->embedded));
CurX += (embedded.getItem()->gWidth + embedded.getItem()->lineWidth()) * glyphs->scaleH;
}
else*/
CurX += glyphs->wide();
tabDist = CurX;
}
}
PSPainter p(Doc, argh, pg, sep, farb, master, this);
ite->textLayout.renderBackground(&p);
ite->textLayout.render(&p);
}
 
void PSLib::setTextCh(ScribusDoc* Doc, PageItem* ite, double x, double y, uint argh, uint doh, QChar chstr, const GlyphLayout* glyphs, const CharStyle& cstyle, const ParagraphStyle& pstyle, ScPage* pg, bool sep, bool farb, bool master)
{
//QChar chstr = hl->ch;
//const CharStyle & cstyle(*hl);
//const GlyphLayout* glyphs(&(hl->glyph));
uint glyph = glyphs->glyph;
 
int h, s, v, k;
double tsz;
double wideR = 0.0;
QVector<double> dum;
dum.clear();
 
tsz = cstyle.fontSize();
 
/* if (cstyle.effects() & ScStyle_DropCap)
{
// QString chstr; // dummy, FIXME: replace by glyph
if (pstyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
tsz = qRound(10 * ((Doc->typographicSettings.valueBaseGrid * (pstyle.dropCapLines()-1)+(cstyle.font().ascent(pstyle.charStyle().fontSize() / 10.0))) / (cstyle.font().realCharHeight(chstr, 10))));
else
{
if (pstyle.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
tsz = qRound(10 * ((pstyle.lineSpacing() * (pstyle.dropCapLines()-1)+(cstyle.font().ascent(pstyle.charStyle().fontSize() / 10.0))) / (cstyle.font().realCharHeight(chstr, 10))));
else
{
double currasce = cstyle.font().height(pstyle.charStyle().fontSize());
tsz = qRound(10 * ((currasce * (pstyle.dropCapLines()-1)+(cstyle.font().ascent(pstyle.charStyle().fontSize() / 10.0))) / cstyle.font().realCharHeight(chstr, 10)));
}
}
}
*/
if (ite->itemText.hasObject(doh-1))
{
PageItem* embedded = ite->itemText.object(doh-1);
PS_save();
PS_translate(x + glyphs->xoffset + embedded->gXpos * (cstyle.scaleH() / 1000.0), (y + glyphs->yoffset - (embedded->gHeight * (cstyle.scaleV() / 1000.0)) + embedded->gYpos * (cstyle.scaleV() / 1000.0)) * -1);
if (doh == 0 || ite->itemText.text(doh-1) == SpecialChars::PARSEP)
{
if ((cstyle.baselineOffset() != 0) && (!pstyle.hasDropCap()))
PS_translate(0, embedded->gHeight * (cstyle.baselineOffset() / 1000.0));
}
else
{
if (cstyle.baselineOffset() != 0)
PS_translate(0, embedded->gHeight * (cstyle.baselineOffset() / 1000.0));
}
if (cstyle.scaleH() != 1000)
PS_scale(cstyle.scaleH() / 1000.0, 1);
if (cstyle.scaleV() != 1000)
PS_scale(1, cstyle.scaleV() / 1000.0);
ProcessItem(Doc, pg, embedded, argh, sep, farb, master, true);
PS_restore();
return;
}
 
if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode()) ||
glyph == (ScFace::CONTROL_GLYPHS + 32))
{
glyph = cstyle.font().char2CMap(QChar(' '));
chstr = ' ';
}
else if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode()))
{
glyph = cstyle.font().char2CMap(QChar('-'));
chstr = '-';
}
if (glyph < ScFace::CONTROL_GLYPHS)
{
if (((cstyle.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr)) //FIXME && (chstr != QChar(13)))
|| ((cstyle.effects() & ScStyle_UnderlineWords) && !chstr.isSpace() && !SpecialChars::isBreak(chstr)))
{
// double Ulen = cstyle.font().glyphWidth(glyph, cstyle.fontSize()) * glyphs->scaleH;
double Ulen = glyphs->xadvance;
double Upos, lw;
if ((cstyle.underlineOffset() != -1) || (cstyle.underlineWidth() != -1))
{
if (cstyle.underlineOffset() != -1)
Upos = (cstyle.underlineOffset() / 1000.0) * (cstyle.font().descent(cstyle.fontSize() / 10.0));
else
Upos = cstyle.font().underlinePos(cstyle.fontSize() / 10.0);
if (cstyle.underlineWidth() != -1)
lw = (cstyle.underlineWidth() / 1000.0) * (cstyle.fontSize() / 10.0);
else
lw = qMax(cstyle.font().strokeWidth(cstyle.fontSize() / 10.0), 1.0);
}
else
{
Upos = cstyle.font().underlinePos(cstyle.fontSize() / 10.0);
lw = qMax(cstyle.font().strokeWidth(cstyle.fontSize() / 10.0), 1.0);
}
if (cstyle.baselineOffset() != 0)
Upos += (cstyle.fontSize() / 10.0) * glyphs->scaleV * (cstyle.baselineOffset() / 1000.0);
if (cstyle.fillColor() != CommonStrings::None)
{
PS_setcapjoin(Qt::FlatCap, Qt::MiterJoin);
PS_setdash(Qt::SolidLine, 0, dum);
SetColor(cstyle.fillColor(), cstyle.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(lw);
if (cstyle.effects() & ScStyle_Subscript)
{
PS_moveto(x + glyphs->xoffset , -y - glyphs->yoffset+Upos);
PS_lineto(x + glyphs->xoffset+Ulen, -y - glyphs->yoffset+Upos);
}
else
{
PS_moveto(x + glyphs->xoffset , -y + Upos);
PS_lineto(x + glyphs->xoffset+Ulen, -y + Upos);
}
putColor(cstyle.fillColor(), cstyle.fillShade(), false);
}
/* Subset all TTF Fonts until the bug in the TTF-Embedding Code is fixed */
if (FontSubsetMap.contains(cstyle.font().scName()))
{
if (glyph != 0 && glyph != cstyle.font().char2CMap(QChar(' ')) && (!SpecialChars::isBreak(chstr)))
{
PS_save();
if (ite->reversed())
{
PS_translate(x + glyphs->xoffset, (y + glyphs->yoffset - (tsz / 10.0)) * -1);
PS_scale(-1, 1);
PS_translate(-glyphs->xadvance, 0);
}
else
PS_translate(x + glyphs->xoffset, (y + glyphs->yoffset - (cstyle.fontSize() / 10.0)) * -1);
if (cstyle.baselineOffset() != 0)
PS_translate(0, (cstyle.fontSize() / 10.0) * (cstyle.baselineOffset() / 1000.0));
if (glyphs->scaleH != 1.0)
PS_scale(glyphs->scaleH, 1);
if (glyphs->scaleV != 1.0)
{
PS_translate(0, -((tsz / 10.0) - (tsz / 10.0) * (glyphs->scaleV)));
PS_scale(1, glyphs->scaleV);
}
if (cstyle.fillColor() != CommonStrings::None)
{
putColorNoDraw(cstyle.fillColor(), cstyle.fillShade());
PS_showSub(glyph, FontSubsetMap[cstyle.font().scName()], tsz / 10.0, false);
}
PS_restore();
}
}
else if (glyph != 0)
{
PS_selectfont(cstyle.font().replacementName(), tsz / 10.0);
PS_save();
PS_translate(x + glyphs->xoffset, -y - glyphs->yoffset);
if (ite->reversed())
{
PS_scale(-1, 1);
PS_translate(glyphs->xadvance, 0);
}
if (cstyle.baselineOffset() != 0)
PS_translate(0, (cstyle.fontSize() / 10.0) * (cstyle.baselineOffset() / 1000.0));
if (glyphs->scaleH != 1.0 || glyphs->scaleV != 1.0)
PS_scale(glyphs->scaleH, glyphs->scaleV);
if (cstyle.fillColor() != CommonStrings::None)
{
PS_show_xyG(cstyle.font().replacementName(), glyph, 0, 0, cstyle.fillColor(), cstyle.fillShade());
}
PS_restore();
}
if ((cstyle.effects() & ScStyle_Outline) || glyph == 0)//&& (chstr != QChar(13)))
{
// if (cstyle.font().canRender(chstr))
{
FPointArray gly = cstyle.font().glyphOutline(glyph);
QTransform chma, chma2, chma3;
chma.scale(tsz / 100.0, tsz / 100.0);
chma2.scale(glyphs->scaleH, glyphs->scaleV);
if (cstyle.baselineOffset() != 0)
chma3.translate(0, -(cstyle.fontSize() / 10.0) * (cstyle.baselineOffset() / 1000.0));
gly.map(chma * chma2 * chma3);
if (ite->reversed())
{
chma = QTransform();
chma.scale(-1, 1);
chma.translate(wideR, 0);
gly.map(chma);
}
if ((cstyle.strokeColor() != CommonStrings::None) && ((tsz * cstyle.outlineWidth() / 10000.0) != 0))
{
PS_save();
PS_setlinewidth(tsz * cstyle.outlineWidth() / 10000.0);
PS_setcapjoin(Qt::FlatCap, Qt::MiterJoin);
PS_setdash(Qt::SolidLine, 0, dum);
PS_translate(x + glyphs->xoffset, (y + glyphs->yoffset - (tsz / 10.0)) * -1);
PS_translate(0, -((tsz / 10.0) - (tsz / 10.0) * glyphs->scaleV));
SetColor(cstyle.strokeColor(), cstyle.strokeShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
SetClipPath(&gly);
PS_closepath();
putColor(cstyle.strokeColor(), cstyle.strokeShade(), false);
PS_restore();
}
}
}
if ((cstyle.effects() & ScStyle_Strikethrough))//&& (chstr != QChar(13)))
{
// double Ulen = cstyle.font().glyphWidth(glyph, cstyle.fontSize()) * glyphs->scaleH;
double Ulen = glyphs->xadvance;
double Upos, lw;
if ((cstyle.strikethruOffset() != -1) || (cstyle.strikethruWidth() != -1))
{
if (cstyle.strikethruOffset() != -1)
Upos = (cstyle.strikethruOffset() / 1000.0) * (cstyle.font().ascent(cstyle.fontSize() / 10.0));
else
Upos = cstyle.font().strikeoutPos(cstyle.fontSize() / 10.0);
if (cstyle.strikethruWidth() != -1)
lw = (cstyle.strikethruWidth() / 1000.0) * (cstyle.fontSize() / 10.0);
else
lw = qMax(cstyle.font().strokeWidth(cstyle.fontSize() / 10.0), 1.0);
}
else
{
Upos = cstyle.font().strikeoutPos(cstyle.fontSize() / 10.0);
lw = qMax(cstyle.font().strokeWidth(cstyle.fontSize() / 10.0), 1.0);
}
if (cstyle.baselineOffset() != 0)
Upos += (cstyle.fontSize() / 10.0) * glyphs->scaleV * (cstyle.baselineOffset() / 1000.0);
if (cstyle.fillColor() != CommonStrings::None)
{
PS_setcapjoin(Qt::FlatCap, Qt::MiterJoin);
PS_setdash(Qt::SolidLine, 0, dum);
SetColor(cstyle.fillColor(), cstyle.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
}
PS_setlinewidth(lw);
PS_moveto(x + glyphs->xoffset , -y-glyphs->yoffset+Upos);
PS_lineto(x + glyphs->xoffset+Ulen, -y-glyphs->yoffset+Upos);
putColor(cstyle.fillColor(), cstyle.fillShade(), false);
}
}
if (glyphs->more) {
//// ugly hack until setTextCh interface is changed
//ScText hl2(*hl);
//hl2.glyph = *glyphs->more;
setTextCh(Doc, ite, x + glyphs->xadvance, y, argh, doh, chstr, glyphs->more, cstyle, pstyle, pg, sep, farb, master);
//// don't let hl2's destructor delete these!
//hl2.glyph.more = 0;
}
/* if (cstyle.effects() & ScStyle_SoftHyphenVisible)
{
int chs = cstyle.fontSize();
// double wide = cstyle.font().charWidth(chstr, chs) * (cstyle.scaleH() / 1000.0);
// chstr = '-';
// if (cstyle.font().canRender(chstr))
{
FPointArray gly = cstyle.font().glyphOutline(glyph);
QTransform chma;
chma.scale(tsz / 100.0, tsz / 100.0);
gly.map(chma);
chma = QTransform();
chma.scale(glyphs->scaleH, glyphs->scaleV);
gly.map(chma);
if (cstyle.fillColor() != CommonStrings::None)
{
PS_save();
PS_newpath();
PS_translate(x + glyphs->xoffset + glyphs->xadvance, (y + glyphs->yoffset - (tsz / 10.0)) * -1);
SetColor(cstyle.fillColor(), cstyle.fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_fill(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
SetClipPath(&gly);
PS_closepath();
putColor(cstyle.fillColor(), cstyle.fillShade(), true);
PS_restore();
}
}
}*/
}
 
void PSLib::putColor(const QString& colorName, double shade, bool fill)
{
ScColor& color(colorsToUse[colorName]);
/trunk/Scribus/scribus/pslib.h
45,6 → 45,7
class MultiProgressDialog;
class ScImage;
class ScLayer;
class PSPainter;
 
/**
*@author Franz Schmid
54,6 → 55,9
class SCRIBUS_API PSLib : public QObject
{
Q_OBJECT
 
friend class PSPainter;
 
public:
 
typedef enum
140,7 → 144,6
virtual void SetColor(const QString& color, double shade, int *h, int *s, int *v, int *k);
virtual void SetColor(const ScColor& color, double shade, int *h, int *s, int *v, int *k);
virtual void setTextSt(ScribusDoc* Doc, PageItem* ite, uint a, ScPage* pg, bool sep, bool farb, bool master);
virtual void setTextCh(ScribusDoc* Doc, PageItem* ite, double x, double y, uint a, uint d, QChar chstr, const GlyphLayout* glyphs, const CharStyle& cstyle, const ParagraphStyle& pstyle, ScPage* pg, bool sep, bool farb, bool master);
bool psExport;
 
private:
/trunk/Scribus/scribus/scpageoutput.cpp
10,7 → 10,7
#include <QPointF>
#include <QRectF>
#include <QStack>
 
#include <pageitem_textframe.h>
#include "cmsettings.h"
#include "collapsedtablepainterex.h"
#include "commonstrings.h"
31,11 → 31,13
#include "scimage.h"
#include "scpage.h"
#include "scpattern.h"
#include "text/textlayoutpainter.h"
 
#include "scribusdoc.h"
#include "util.h"
#include "util_formats.h"
#include "util_math.h"
#include "text/boxes.h"
 
 
MarksOptions::MarksOptions(void)
506,167 → 508,6
painter->restore();
}
 
void ScPageOutput::drawGlyphs(PageItem* item, ScPainterExBase *painter, const CharStyle& style, GlyphLayout& glyphs, QRect clip)
{
uint glyph = glyphs.glyph;
if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) // NBSPACE
glyph = style.font().char2CMap(QChar(' '));
else if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode())) // NBHYPHEN
glyph = style.font().char2CMap(QChar('-'));
if (glyph >= ScFace::CONTROL_GLYPHS)
{
if (glyphs.more)
{
painter->translate(glyphs.xadvance, 0);
drawGlyphs(item, painter, style, *glyphs.more, clip);
}
return;
}
//if (style.font().canRender(QChar(glyph)))
{
QTransform chma, chma2, chma3, chma4, chma5, chma6;
chma.scale(glyphs.scaleH * style.fontSize() / 100.00, glyphs.scaleV * style.fontSize() / 100.0);
FPointArray gly = style.font().glyphOutline(glyph);
// Do underlining first so you can get typographically correct
// underlines when drawing a white outline
if ((style.effects() & ScStyle_Underline) || ((style.effects() & ScStyle_UnderlineWords) && (glyph != style.font().char2CMap(QChar(' ')))))
{
double st, lw;
if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
{
if (style.underlineOffset() != -1)
st = (style.underlineOffset() / 1000.0) * (style.font().descent(style.fontSize() / 10.0));
else
st = style.font().underlinePos(style.fontSize() / 10.0);
if (style.underlineWidth() != -1)
lw = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
else
lw = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
st = style.font().underlinePos(style.fontSize() / 10.0);
lw = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
st += (style.fontSize() / 10.0) * glyphs.scaleV * (style.baselineOffset() / 1000.0);
ScColorShade tmpPen = painter->pen();
int tmpStrokeMode = painter->strokeMode();
painter->setPen(painter->brush());
painter->setLineWidth(lw);
painter->setStrokeMode(1);
if (style.effects() & ScStyle_Subscript)
painter->drawLine(FPoint(glyphs.xoffset, glyphs.yoffset - st), FPoint(glyphs.xoffset + glyphs.xadvance, glyphs.yoffset - st));
else
painter->drawLine(FPoint(glyphs.xoffset, -st), FPoint(glyphs.xoffset + glyphs.xadvance, -st));
painter->setStrokeMode(tmpStrokeMode);
painter->setPen(tmpPen);
}
if (gly.size() > 3)
{
painter->save();
painter->translate(glyphs.xoffset, glyphs.yoffset - ((style.fontSize() / 10.0) * glyphs.scaleV));
if (item->reversed())
{
painter->scale(-1, 1);
painter->translate(-glyphs.xadvance, 0);
}
if (style.baselineOffset() != 0)
painter->translate(0, -(style.fontSize() / 10.0) * (style.baselineOffset() / 1000.0));
double glxSc = glyphs.scaleH * style.fontSize() / 100.00;
double glySc = glyphs.scaleV * style.fontSize() / 100.0;
painter->scale(glxSc, glySc);
painter->setFillMode(ScPainterExBase::Solid);
bool fr = painter->fillRule();
painter->setFillRule(false);
painter->setupPolygon(&gly, true);
if (glyph == 0)
{
ScColorShade tmp(PrefsManager::instance()->appPrefs.displayPrefs.controlCharColor, 100);
painter->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
painter->setLineWidth(style.fontSize() * glyphs.scaleV * style.outlineWidth() * 2 / 10000.0);
painter->strokePath();
}
else if ((style.font().isStroked()) && ((style.fontSize() * glyphs.scaleV * style.outlineWidth() / 10000.0) != 0))
{
ScColorShade tmp = painter->brush();
painter->setStrokeMode(1);
painter->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
painter->setLineWidth(style.fontSize() * glyphs.scaleV * style.outlineWidth() / 10000.0);
painter->strokePath();
}
else
{
if ((style.effects() & ScStyle_Shadowed) && (style.strokeColor() != CommonStrings::None))
{
painter->save();
painter->translate((style.fontSize() * glyphs.scaleH * style.shadowXOffset() / 10000.0) / glxSc, -(style.fontSize() * glyphs.scaleV * style.shadowYOffset() / 10000.0) / glySc);
ScColorShade tmp = painter->brush();
painter->setBrush(painter->pen());
painter->setupPolygon(&gly, true);
fillPath(item, painter, clip);
painter->setBrush(tmp);
painter->restore();
painter->setupPolygon(&gly, true);
}
if (style.fillColor() != CommonStrings::None)
fillPath(item, painter, clip);
if ((style.effects() & ScStyle_Outline) && (style.strokeColor() != CommonStrings::None) && ((style.fontSize() * glyphs.scaleV * style.outlineWidth() / 10000.0) != 0))
{
painter->setStrokeMode(1);
painter->setLineWidth((style.fontSize() * glyphs.scaleV * style.outlineWidth() / 10000.0) / glySc);
painter->strokePath();
}
}
painter->setFillRule(fr);
painter->restore();
}
if (style.effects() & ScStyle_Strikethrough)
{
double st, lw;
if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
{
if (style.strikethruOffset() != -1)
st = (style.strikethruOffset() / 1000.0) * (style.font().ascent(style.fontSize() / 10.0));
else
st = style.font().strikeoutPos(style.fontSize() / 10.0);
if (style.strikethruWidth() != -1)
lw = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
else
lw = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
else
{
st = style.font().strikeoutPos(style.fontSize() / 10.0);
lw = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
}
if (style.baselineOffset() != 0)
st += (style.fontSize() / 10.0) * glyphs.scaleV * (style.baselineOffset() / 1000.0);
int tmpStrokeMode = painter->strokeMode();
painter->setPen(painter->brush());
painter->setLineWidth(lw);
painter->setStrokeMode(1);
painter->drawLine(FPoint(glyphs.xoffset, glyphs.yoffset - st), FPoint(glyphs.xoffset + glyphs.xadvance, glyphs.yoffset - st));
painter->setStrokeMode(tmpStrokeMode);
}
}
/*else
{
painter->setLineWidth(1);
painter->setPen(ScColorShade(Qt::red, 100));
painter->setBrush(ScColorShade(Qt::red, 100));
painter->setFillMode(1);
painter->drawRect(glyphs.xoffset, glyphs.yoffset - (style.fontSize() / 10.0) * glyphs.scaleV , (style.fontSize() / 10.0) * glyphs.scaleH, (style.fontSize() / 10.0) * glyphs.scaleV);
}*/
if (glyphs.more)
{
painter->translate(glyphs.xadvance, 0);
drawGlyphs(item, painter, style, *glyphs.more, clip);
}
}
 
void ScPageOutput::drawItem_Embedded( PageItem* item, ScPainterExBase *p, QRect clip, const CharStyle& style, PageItem* cembedded)
{
if (!cembedded)
1080,185 → 921,185
}
}
 
void ScPageOutput::drawItem_PathText( PageItem_PathText* item, ScPainterExBase* painter, QRect clip )
class ScpageoutputPainter: public TextLayoutPainter
{
QString chstr;
//ScText *hl;
FPoint point = FPoint(0, 0);
FPoint tangent = FPoint(0, 0);
double CurX = item->textToFrameDistLeft(); // item->CurX = item->textToFrameDistLeft()
QString actFill, actStroke;
double actFillShade, actStrokeShade, dx;
StoryText& itemText = item->itemText;
if (item->pathTextShowFrame())
private:
PageItem* m_item;
ScPainterExBase* m_painter;
ScPageOutput* m_scpage;
 
void setupState()
{
painter->setupPolygon(&item->PoLine, false);
if (item->NamedLStyle.isEmpty())
m_painter->setLineWidth(strokeWidth());
ScColorShade fill(m_item->doc()->PageColors[fillColor().color], qRound(fillColor().shade));
m_painter->setBrush(fill);
ScColorShade stroke(m_item->doc()->PageColors[strokeColor().color], qRound(strokeColor().shade));
m_painter->setPen(stroke);
if (matrix() != QTransform())
{
if (item->lineColor() != CommonStrings::None)
painter->strokePath();
m_painter->setWorldMatrix(matrix() * m_painter->worldMatrix());
}
else
{
multiLine ml = m_doc->MLineStyles[item->NamedLStyle];
for (int it = ml.size() - 1; it > -1; it--)
{
const SingleLine& sl = ml[it];
if ((sl.Color != CommonStrings::None) && (sl.Width != 0))
{
ScColorShade tmp(m_doc->PageColors[sl.Color], sl.Shade);
painter->setPen(tmp, sl.Width, static_cast<Qt::PenStyle>(sl.Dash),
static_cast<Qt::PenCapStyle>(sl.LineEnd),
static_cast<Qt::PenJoinStyle>(sl.LineJoin));
painter->drawLine(FPoint(0, 0), FPoint(item->width(), 0));
}
}
}
}
double totalTextLen = 0.0;
double totalCurveLen = 0.0;
double extraOffset = 0.0;
if (itemText.length() != 0)
 
public:
ScpageoutputPainter(PageItem* item, ScPainterExBase* painter, ScPageOutput* scpage)
: m_item(item)
, m_painter(painter)
, m_scpage(scpage)
{}
 
void translate(double xp, double yp)
{
CurX += itemText.charStyle(0).fontSize() * itemText.charStyle(0).tracking() / 10000.0;
totalTextLen += itemText.charStyle(0).fontSize() * itemText.charStyle(0).tracking() / 10000.0;
TextLayoutPainter::translate(xp, yp);
m_painter->translate(xp, yp);
}
for (int a = 0; a < itemText.length(); ++a)
 
void save()
{
GlyphLayout* glyphs = itemText.getGlyphs(a);
chstr =itemText.text(a,1);
if (chstr[0] == SpecialChars::PAGENUMBER || chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::PAGECOUNT
|| chstr[0] == SpecialChars::TAB || chstr == SpecialChars::LINEBREAK)
continue;
if (a < itemText.length()-1)
chstr += itemText.text(a+1, 1);
glyphs->yadvance = 0;
item->layoutGlyphs(itemText.charStyle(a), chstr, itemText.flags(a), *glyphs);
glyphs->shrink();
if (item->itemText.hasObject(a))
totalTextLen += (item->itemText.object(a)->width() + item->itemText.object(a)->lineWidth()) * glyphs->scaleH;
else
totalTextLen += glyphs->wide()+itemText.charStyle(a).fontSize() * itemText.charStyle(a).tracking() / 10000.0;
TextLayoutPainter::save();
m_painter->save();
}
for (int segs = 0; segs < item->PoLine.size()-3; segs += 4)
 
void restore()
{
totalCurveLen += item->PoLine.lenPathSeg(segs);
TextLayoutPainter::restore();
m_painter->restore();
}
if ((itemText.defaultStyle().alignment() != 0) && (totalCurveLen >= totalTextLen + item->textToFrameDistLeft()))
 
void setScale(double h, double v)
{
if (itemText.defaultStyle().alignment() == 2)
{
CurX = totalCurveLen - totalTextLen;
CurX -= item->textToFrameDistLeft();
}
if (itemText.defaultStyle().alignment() == 1)
CurX = (totalCurveLen - totalTextLen) / 2.0;
if ((itemText.defaultStyle().alignment() == 3) || (itemText.defaultStyle().alignment() == 4))
extraOffset = (totalCurveLen - item->textToFrameDistLeft() - totalTextLen) / static_cast<double>(itemText.length());
TextLayoutPainter::setScale(h, v);
m_painter->scale(h, v);
}
 
QPainterPath guidePath = item->PoLine.toQPainterPath(false);
QList<QPainterPath> pathList = decomposePath(guidePath);
QPainterPath currPath = pathList[0];
int currPathIndex = 0;
for (int a = item->firstInFrame(); a < itemText.length(); ++a)
void drawGlyph(const GlyphLayout gl)
{
GlyphLayout* glyphs = itemText.getGlyphs(a);
PathData* pdata = &(item->textLayout.point(a));
chstr = itemText.text(a,1);
if (chstr[0] == SpecialChars::PAGENUMBER || chstr[0] == SpecialChars::PARSEP || chstr[0] == SpecialChars::PAGECOUNT
|| chstr[0] == SpecialChars::TAB || chstr[0] == SpecialChars::LINEBREAK)
continue;
if (a < itemText.length()-1)
chstr += itemText.text(a+1, 1);
glyphs->yadvance = 0;
item->layoutGlyphs(itemText.charStyle(a), chstr, itemText.flags(a), *glyphs);
glyphs->shrink(); // HACK
// Unneeded now that glyph xadvance is set appropriately for inline objects by PageItem_TextFrame::layout() - JG
/*if (hl->hasObject())
dx = (hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth()) * hl->glyph.scaleH / 2.0;
else*/
dx = glyphs->wide() / 2.0;
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
CurX += dx;
m_painter->save();
bool fr = m_painter->fillRule();
int fm = m_painter->fillMode();
 
double currPerc = currPath.percentAtLength(CurX);
if (currPerc >= 0.9999999)
{
currPathIndex++;
if (currPathIndex == pathList.count())
break;
currPath = pathList[currPathIndex];
CurX = dx;
currPerc = currPath.percentAtLength(CurX);
}
double currAngle = currPath.angleAtPercent(currPerc);
if (currAngle <= 180.0)
currAngle *= -1.0;
else
currAngle = 360.0 - currAngle;
QPointF currPoint = currPath.pointAtPercent(currPerc);
tangent = FPoint(cos(currAngle * M_PI / 180.0), sin(currAngle * M_PI / 180.0));
point = FPoint(currPoint.x(), currPoint.y());
m_painter->setFillRule(false);
m_painter->setFillMode(1);
 
//hl = itemText.item_p(a);
glyphs->xoffset = 0;
pdata->PtransX = point.x();
pdata->PtransY = point.y();
pdata->PRot = currAngle * M_PI / 180.0;
pdata->PDx = dx;
QTransform trafo = QTransform( 1, 0, 0, -1, -dx, 0 );
if (item->textPathFlipped)
trafo *= QTransform(1, 0, 0, -1, 0, 0);
if (item->textPathType == 0)
trafo *= QTransform( tangent.x(), tangent.y(), tangent.y(), -tangent.x(), point.x(), point.y() ); // ID's Rainbow mode
else if (item->textPathType == 1)
trafo *= QTransform( 1, 0, 0, -1, point.x(), point.y() ); // ID's Stair Step mode
else if (item->textPathType == 2)
setupState();
m_painter->translate(0, -(fontSize() * gl.scaleV));
FPointArray outline = font().glyphOutline(gl.glyph);
double scaleH = gl.scaleH * fontSize() / 10.0;
double scaleV = gl.scaleV * fontSize() / 10.0;
m_painter->scale(scaleH, scaleV);
m_painter->setupPolygon(&outline, true);
if (outline.size() > 3)
m_painter->fillPath();
 
m_painter->setFillMode(fm);
m_painter->setFillRule(fr);
m_painter->restore();
}
 
void drawGlyphOutline(const GlyphLayout gl, bool fill)
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
m_painter->save();
bool fr = m_painter->fillRule();
m_painter->setFillRule(false);
 
setupState();
m_painter->translate(0, -(fontSize() * gl.scaleV));
 
FPointArray outline = font().glyphOutline(gl.glyph);
double scaleH = gl.scaleH * fontSize() / 10.0;
double scaleV = gl.scaleV * fontSize() / 10.0;
m_painter->scale(scaleH, scaleV);
m_painter->setupPolygon(&outline, true);
if (outline.size() > 3)
{
double a = 1;
if (tangent.x() < 0)
a = -1;
if (fabs(tangent.x()) > 0.1)
trafo *= QTransform( a, (tangent.y() / tangent.x()) * a, 0, -1, point.x(), point.y() ); // ID's Skew mode
else
trafo *= QTransform( a, 4 * a, 0, -1, point.x(), point.y() );
m_painter->setLineWidth(strokeWidth());
m_painter->strokePath();
}
QTransform sca = painter->worldMatrix();
trafo *= sca;
painter->save();
QTransform savWM = painter->worldMatrix();
painter->setWorldMatrix(trafo);
 
actFill = itemText.charStyle(a).fillColor();
actFillShade = itemText.charStyle(a).fillShade();
if (actFill != CommonStrings::None)
m_painter->setFillRule(fr);
m_painter->restore();
 
if (fill)
drawGlyph(gl);
}
 
void drawLine(QPointF start, QPointF end)
{
m_painter->save();
setupState();
m_painter->drawLine(start, end);
m_painter->restore();
}
 
void drawRect(QRectF rect)
{
m_painter->save();
setupState();
m_painter->setFillMode(1);
m_painter->setStrokeMode(1);
m_painter->drawRect(rect.x(), rect.y(), rect.width(), rect.height());
m_painter->restore();
}
 
void drawObject(PageItem* embedded)
{
QRect cullingArea;
if (!embedded)
return;
if (!m_item->m_Doc->DoDrawing)
return;
 
m_painter->save();
double pws = embedded->m_lineWidth;
 
embedded->Dirty = m_item->Dirty;
embedded->invalid = true;
m_scpage->drawItem_Pre(embedded, m_painter);
 
switch(embedded->itemType())
{
ScColorShade tmp(m_doc->PageColors[actFill], qRound(actFillShade));
painter->setBrush(tmp);
case PageItem::ImageFrame:
case PageItem::TextFrame:
case PageItem::LatexFrame:
case PageItem::OSGFrame:
case PageItem::Polygon:
case PageItem::PathText:
case PageItem::Symbol:
case PageItem::Group:
case PageItem::RegularPolygon:
case PageItem::Arc:
case PageItem::Table:
m_scpage->drawItem(embedded, m_painter, cullingArea);
break;
case PageItem::Line:
case PageItem::PolyLine:
case PageItem::Spiral:
embedded->m_lineWidth = pws * qMin(scaleH(), scaleV());
m_scpage->drawItem(embedded, m_painter, cullingArea);
break;
default:
break;
}
actStroke = itemText.charStyle(a).strokeColor();
actStrokeShade = itemText.charStyle(a).strokeShade();
if (actStroke != CommonStrings::None)
{
ScColorShade tmp(m_doc->PageColors[actStroke], qRound(actStrokeShade));
painter->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
}
painter->translate(0.0, item->pathTextBaseOffset());
if (itemText.hasObject(a))
drawItem_Embedded(itemText.object(a), painter, clip, itemText.charStyle(a), itemText.object(a));
else
drawGlyphs(item, painter, itemText.charStyle(a), *glyphs, clip);
 
painter->setWorldMatrix(savWM);
painter->restore();
CurX -= dx;
if (itemText.hasObject(a))
CurX += (itemText.object(a)->width() + itemText.object(a)->lineWidth()) * glyphs->scaleH;
else
CurX += glyphs->wide()+itemText.charStyle(a).fontSize() * itemText.charStyle(a).tracking() / 10000.0 + extraOffset;
embedded->m_lineWidth = pws * qMin(scaleH(), scaleV());
m_scpage->drawItem_Post(embedded, m_painter);
embedded->m_lineWidth = pws;
m_painter->restore();
}
};
 
 
void ScPageOutput::drawItem_PathText( PageItem_PathText* item, ScPainterExBase* painter, QRect clip )
{
ScpageoutputPainter p(item, painter, this);
item->textLayout.renderBackground(&p);
item->textLayout.render(&p);
}
 
void ScPageOutput::drawItem_Polygon ( PageItem_Polygon* item , ScPainterExBase* painter, QRect clip )
1610,251 → 1451,9
 
void ScPageOutput::drawItem_TextFrame( PageItem_TextFrame* item, ScPainterExBase* painter, QRect cullingArea )
{
QTransform wm;
QPoint pt1, pt2;
FPoint ColBound;
QRegion cm;
int a;
double desc, asce;
painter->save();
if (!item->isEmbedded)
wm.translate(item->xPos(), item->yPos());
wm.rotate(item->rotation());
 
if ((item->fillColor() != CommonStrings::None) || (item->GrType != 0))
{
painter->setupPolygon(&item->PoLine);
fillPath(item, painter, cullingArea);
}
if ((item->isAnnotation()) && (item->annotation().Type() == Annotation::Button) && (!item->Pfile.isEmpty()) && (item->imageIsAvailable) && (item->imageVisible()) && (item->annotation().UseIcons()))
{
painter->save();
painter->setupPolygon(&item->PoLine);
painter->setClipPath();
painter->scale(item->imageXScale(), item->imageYScale());
painter->translate(static_cast<int>(item->imageXOffset() * item->imageXScale()), static_cast<int>(item->imageYOffset() * item->imageYScale()));
if (!item->pixm.qImage().isNull())
painter->drawImage(&item->pixm, ScPainterExBase::rgbImages);
painter->restore();
}
if ((item->itemText.length() != 0))
{
if (item->imageFlippedH())
{
painter->translate(item->width(), 0);
painter->scale(-1, 1);
wm.translate(item->width(), 0);
wm.scale(-1, 1);
}
if (item->imageFlippedV())
{
painter->translate(0, item->height());
painter->scale(1, -1);
wm.translate(0, item->height());
wm.scale(1, -1);
}
 
uint llp = 0;
LineSpec ls;
while (llp < item->textLayout.lines())
{
ls = item->textLayout.line(llp++);
const ParagraphStyle& LineStyle = item->itemText.paragraphStyle(ls.firstItem);
if (LineStyle.backgroundColor() != CommonStrings::None)
{
ScColorShade colorShade;
colorShade.color = m_doc->PageColors[LineStyle.backgroundColor()];
colorShade.shade = LineStyle.backgroundShade();
double y0 = ls.y;
double y2 = ls.y;
double ascent = ls.ascent;
double descent = ls.descent;
double rMarg = LineStyle.rightMargin();
double lMarg = ls.colLeft;
double adjX = 0;
if (LineStyle.firstIndent() <= 0)
adjX += LineStyle.leftMargin() + LineStyle.firstIndent();
while (llp < item->textLayout.lines())
{
ls = item->textLayout.line(llp);
if ((ls.colLeft > lMarg) || (item->itemText.paragraphStyle(ls.firstItem) != LineStyle))
{
if (y2 == 0)
y2 = y0;
break;
}
if (item->itemText.text(ls.lastItem) == SpecialChars::PARSEP)
{
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < item->textLayout.lines())
{
if ((item->textLayout.line(llp + 1).lastItem - item->textLayout.line(llp + 1).firstItem) > 0)
descent += LineStyle.lineSpacing() - (ls.descent + item->textLayout.line(llp + 1).ascent);
}
llp++;
break;
}
y2 = ls.y;
descent = ls.descent;
if ((llp + 1) < item->textLayout.lines())
descent += LineStyle.lineSpacing() - (ls.descent + item->textLayout.line(llp + 1).ascent);
llp++;
}
painter->save();
painter->setupPolygon(&item->PoLine);
painter->setClipPath();
painter->setFillMode(1);
painter->setStrokeMode(0);
painter->setBrush(colorShade);
painter->drawRect(lMarg + adjX, y0 - ascent, item->columnWidth() - adjX - rMarg, y2 - y0 + descent + ascent);
painter->restore();
}
}
 
for (uint ll=0; ll < item->textLayout.lines(); ++ll)
{
const LineSpec& ls = item->textLayout.line(ll);
double CurX = ls.x;
 
// Draw text background
ScColorShade tmpShade;
double curXB = ls.x;
QRectF scrG;
QString oldBack;
double oldShade = 100;
for (a = ls.firstItem; a <= ls.lastItem; ++a)
{
GlyphLayout* glyphs = item->itemText.getGlyphs(a);
const CharStyle& charStyle(item->itemText.charStyle(a));
if (charStyle.backColor() != CommonStrings::None)
{
tmpShade.color = m_doc->PageColors[charStyle.backColor()];
tmpShade.shade = charStyle.backShade();
const ParagraphStyle& lineStyle = item->itemText.paragraphStyle(ls.firstItem);
double y1 = ls.y;
double hl = ls.height;
if (lineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
hl = m_doc->guidesPrefs().valueBaselineGrid;
else if (lineStyle.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
hl = lineStyle.lineSpacing();
if (ls.isFirstLine)
{
if (item->textLayout.lines() == 1)
hl = ls.ascent + ls.descent;
if (lineStyle.hasDropCap() && (a == ls.firstItem))
hl *= lineStyle.dropCapLines();
if (lineStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
y1 -= lineStyle.lineSpacing();
else if (item->firstLineOffset() == FLOPRealGlyphHeight || item->firstLineOffset() == FLOPFontAscent)
y1 -= ls.ascent;
else
y1 -= lineStyle.lineSpacing();
}
else
y1 -= ls.ascent + (hl - (ls.ascent + ls.descent)) / 2.0;
QRectF scr;
if (item->itemText.hasObject(a))
{
PageItem* obj = item->itemText.object(a);
double ww = (obj->width() + obj->lineWidth()) * glyphs->scaleH;
double hh = (obj->height() + obj->lineWidth()) * glyphs->scaleV;
scr = QRectF(curXB, ls.y - hh, ww , hh);
}
else
scr = QRectF(curXB, y1, glyphs->wide(), hl);
if ((oldBack.isEmpty()) || ((oldBack == charStyle.backColor()) && (oldShade == charStyle.backShade())))
scrG |= scr;
else if ((oldBack != charStyle.backColor()) || (oldShade != charStyle.backShade()))
{
tmpShade.color = m_doc->PageColors[oldBack];
tmpShade.shade = oldShade;
painter->save();
painter->setFillMode(1);
painter->setStrokeMode(0);
painter->setBrush(tmpShade);
painter->drawRect(scrG.x(), scrG.y(), scrG.width(), scrG.height());
painter->restore();
scrG = scr;
}
oldBack = charStyle.backColor();
oldShade = charStyle.backShade();
}
else
{
oldBack.clear();
oldShade = 100;
if (!scrG.isNull())
{
painter->save();
painter->setFillMode(1);
painter->setStrokeMode(0);
painter->setBrush(tmpShade);
painter->drawRect(scrG.x(), scrG.y(), scrG.width(), scrG.height());
painter->restore();
}
scrG = QRectF();
}
curXB += glyphs->wide();
}
if (!scrG.isNull())
{
painter->save();
painter->setFillMode(1);
painter->setStrokeMode(0);
painter->setBrush(tmpShade);
painter->drawRect(scrG.x(), scrG.y(), scrG.width(), scrG.height());
painter->restore();
}
 
// Draw text
for (a = ls.firstItem; a <= ls.lastItem; ++a)
{
GlyphLayout* glyphs = item->itemText.getGlyphs(a);
const CharStyle& charStyle = item->itemText.charStyle(a);
 
if (charStyle.fillColor() != CommonStrings::None)
{
ScColorShade tmp(m_doc->PageColors[charStyle.fillColor()], (int) charStyle.fillShade());
painter->setBrush(tmp);
}
if (charStyle.strokeColor() != CommonStrings::None)
{
ScColorShade tmp(m_doc->PageColors[charStyle.strokeColor()], (int) charStyle.strokeShade());
painter->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
}
 
//if (!m_doc->RePos)
{
//double xcoZli = CurX + glyphs->xoffset;
desc = - charStyle.font().descent(charStyle.fontSize() / 10.0);
asce = charStyle.font().ascent(charStyle.fontSize() / 10.0);
if (charStyle.strokeColor() != CommonStrings::None)
{
ScColorShade tmp(m_doc->PageColors[charStyle.strokeColor()], (int) charStyle.strokeShade());
painter->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
}
if (item->isEmbedded || cullingArea.intersects(wm.mapRect(QRect(qRound(CurX + glyphs->xoffset),qRound(ls.y + glyphs->yoffset-asce), qRound(glyphs->xadvance+1), qRound(asce+desc)))))
{
painter->save();
painter->translate(CurX, ls.y);
if (item->itemText.hasObject(a))
drawItem_Embedded(item, painter, cullingArea, charStyle, item->itemText.object(a));
else
drawGlyphs(item, painter, charStyle, *glyphs, cullingArea);
painter->restore();
}
// Unneeded now that glyph xadvance is set appropriately for inline objects by PageItem_TextFrame::layout() - JG
/*if (hl->hasObject())
CurX += (hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth());
else*/
CurX += glyphs->wide();
}
}
}
}
painter->restore();
ScpageoutputPainter p(item, painter, this);
item->textLayout.renderBackground(&p);
item->textLayout.render(&p);
}
 
void ScPageOutput::drawArrow(ScPainterExBase* painter, PageItem* item, QTransform &arrowTrans, int arrowIndex)
/trunk/Scribus/scribus/scpageoutput.h
53,6 → 53,8
 
class SCRIBUS_API ScPageOutput
{
friend class ScpageoutputPainter;
 
public:
ScPageOutput(ScribusDoc* doc, bool reloadImages = false, int resolution = 72, bool useProfiles = false);
virtual ~ScPageOutput() { }
82,7 → 84,6
virtual void drawItem_Pre( PageItem* item, ScPainterExBase* painter );
virtual void drawItem_Post( PageItem* item, ScPainterExBase* painter );
 
virtual void drawGlyphs(PageItem* item, ScPainterExBase *painter, const CharStyle& style, GlyphLayout& glyphs, QRect clip);
virtual void drawItem_Embedded( PageItem* item, ScPainterExBase *p, QRect clip, const CharStyle& style, PageItem* cembedded);
virtual void drawPattern(PageItem* item, ScPainterExBase* painter, QRect clip);
virtual void drawStrokePattern(PageItem* item, ScPainterExBase* painter, const QPainterPath& path);
/trunk/Scribus/scribus/scpainter.cpp
181,6 → 181,11
m_image->fill( qRgba(qRed(cs), qGreen(cs), qBlue(cs), qAlpha(cs)) );
}
 
cairo_t *ScPainter::context()
{
return m_cr;
}
 
const QTransform ScPainter::worldMatrix()
{
cairo_matrix_t matrix;
424,6 → 429,11
return m_fill;
}
 
double ScPainter::brushOpacity()
{
return m_fill_trans;
}
 
void ScPainter::setPen( const QColor &c )
{
m_stroke = c;
495,6 → 505,11
m_zoomFactor = m_zoomStack.pop();
}
 
int ScPainter::blendModeFill()
{
return m_blendModeFill;
}
 
void ScPainter::setRasterOp(int blendMode)
{
if (blendMode == 0)
1932,6 → 1947,7
 
void ScPainter::drawText(QRectF area, QString text, bool filled, int align)
{
// FIXME HOST: This uses Cairo "Toy text API" which does not support complex text layout.
cairo_text_extents_t extents;
cairo_font_extents_t extentsF;
double x;
/trunk/Scribus/scribus/scpainter.h
19,6 → 19,7
#include <QPointF>
#include "scribusapi.h"
#include "scconfig.h"
#include "sctextstruct.h"
#include "fpoint.h"
#include "fpointarray.h"
#include "vgradient.h"
43,6 → 44,7
virtual void end();
void clear();
virtual void clear( const QColor & );
virtual cairo_t* context();
 
// matrix manipulation
virtual void setWorldMatrix( const QTransform & );
66,6 → 68,7
virtual bool fillRule() { return m_fillRule; }
virtual void setFillMode( int fill );
virtual int fillMode() { return m_fillMode; }
virtual int maskMode() { return m_maskMode; }
virtual void setStrokeMode( int stroke );
virtual int strokeMode() { return m_strokeMode; }
virtual void setGradient( VGradient::VGradientType mode, FPoint orig, FPoint vec, FPoint foc, double scale, double skew);
109,6 → 112,7
// pen + brush
virtual QColor pen();
virtual QColor brush();
virtual double brushOpacity();
virtual void setPen( const QColor & );
virtual void setPen( const QColor &c, double w, Qt::PenStyle st, Qt::PenCapStyle ca, Qt::PenJoinStyle jo );
virtual void setPenOpacity( double op );
123,6 → 127,7
// stack management
virtual void save();
virtual void restore();
virtual int blendModeFill();
 
 
virtual void setRasterOp( int blendMode );
/trunk/Scribus/scribus/scribusdoc.cpp
42,6 → 42,7
 
#include "actionmanager.h"
#include "appmodes.h"
#include "text/boxes.h"
#include "canvas.h"
#include "colorblind.h"
#include "commonstrings.h"
95,6 → 96,7
#include "selection.h"
#include "serializer.h"
#include "tableborder.h"
#include "text/textlayoutpainter.h"
#include "ui/hruler.h"
#include "ui/layers.h"
#include "ui/mark2item.h"
4497,181 → 4499,45
}
}
 
 
void ScribusDoc::checkItemForFonts(PageItem *it, QMap<QString, QMap<uint, FPointArray> > & Really, uint lc)
// a special painter that does not actually paint anything,
// but collects the glyphs used in the frame.
class UsedGlyphsPainter: public TextLayoutPainter
{
if (!it->isTextFrame() && !it->isPathText())
return;
public:
UsedGlyphsPainter(QMap<QString, QMap<uint, FPointArray> > & Really)
: m_really(Really)
{}
 
FPointArray gly;
QChar chstr;
 
int start = it->isTextFrame() ? it->firstInFrame() : 0;
int stop = it->isTextFrame() ? it->lastInFrame() + 1 : it->itemText.length();
for (int e = start; e < stop; ++e)
void drawGlyph(const GlyphLayout gl)
{
const ScFace* font = &it->itemText.charStyle(e).font();
if (it->itemText.hasMark(e))
{
QString mrkStr = it->itemText.mark(e)->getString();
for (int i=0;i<mrkStr.length(); ++i)
{
if (font->canRender(mrkStr[i].unicode()))
{
uint gl = font->char2CMap(mrkStr[i]);
FPointArray gly(font->glyphOutline(gl));
if (!font->replacementName().isEmpty())
Really[font->replacementName()].insert(gl, gly);
}
}
}
if (! Really.contains(font->replacementName()) )
{
if (!font->replacementName().isEmpty())
Really.insert(font->replacementName(), QMap<uint, FPointArray>());
}
uint chr = it->itemText.text(e).unicode();
if ((chr == 13) || (chr == 32) || ((chr >= 26) && (chr <= 29)))
continue;
if (chr == 9)
{
for (int t1 = 0; t1 < it->itemText.paragraphStyle(e).tabValues().count(); t1++)
{
if (it->itemText.paragraphStyle(e).tabValues()[t1].tabFillChar.isNull())
continue;
chstr = it->itemText.paragraphStyle(e).tabValues()[t1].tabFillChar;
if ((it->itemText.charStyle(e).effects() & ScStyle_SmallCaps) || (it->itemText.charStyle(e).effects() & ScStyle_AllCaps))
{
if (chstr.toUpper() != chstr)
chstr = chstr.toUpper();
}
chr = chstr.unicode();
uint gl = font->char2CMap(chstr);
gly = font->glyphOutline(gl);
if (!font->replacementName().isEmpty())
Really[font->replacementName()].insert(gl, gly);
}
for (int t1 = 0; t1 < it->itemText.defaultStyle().tabValues().count(); t1++)
{
if (it->itemText.defaultStyle().tabValues()[t1].tabFillChar.isNull())
continue;
chstr = it->itemText.defaultStyle().tabValues()[t1].tabFillChar;
if ((it->itemText.charStyle(e).effects() & ScStyle_SmallCaps) || (it->itemText.charStyle(e).effects() & ScStyle_AllCaps))
{
if (chstr.toUpper() != chstr)
chstr = chstr.toUpper();
}
chr = chstr.unicode();
uint gl = font->char2CMap(chstr);
gly = font->glyphOutline(gl);
if (!font->replacementName().isEmpty())
Really[font->replacementName()].insert(gl, gly);
}
continue;
}
if ((chr == 30) || (chr == 23))
{
//Our page number collection string
QString pageNumberText(QString::null);
if (chr == 30)
{//ch == SpecialChars::PAGENUMBER
if (e > 0 && it->itemText.text(e-1) == SpecialChars::PAGENUMBER)
pageNumberText=SpecialChars::ZWNBSPACE;
else if (lc!=0) //If not on a master page just get the page number for the page and the text
{
pageNumberText = QString("%1").arg(getSectionPageNumberForPageIndex(it->OwnPage),
getSectionPageNumberWidthForPageIndex(it->OwnPage),
getSectionPageNumberFillCharForPageIndex(it->OwnPage));
}
else
{
//Else, for a page number in a text frame on a master page we must scan
//all pages to see which ones use this page and get their page numbers.
//We only add each character of the pages' page number text if its nothing
//already in the pageNumberText variable. No need to add glyphs twice.
QString newText;
uint docPageCount=DocPages.count();
for (uint a = 0; a < docPageCount; ++a)
{
if (DocPages.at(a)->MPageNam == it->OnMasterPage)
{
newText = QString("%1").arg(getSectionPageNumberForPageIndex(a),
getSectionPageNumberWidthForPageIndex(a),
getSectionPageNumberFillCharForPageIndex(a));
for (int nti=0;nti<newText.length();++nti)
if (pageNumberText.indexOf(newText[nti])==-1)
pageNumberText+=newText[nti];
}
}
}
}
else
{//ch == SpecialChars::PAGECOUNT
if (lc!=0)
{
int key = getSectionKeyForPageIndex(it->OwnPage);
if (key == -1)
pageNumberText = "";
else
pageNumberText = QString("%1").arg(getStringFromSequence(m_docPrefsData.docSectionMap[key].type, m_docPrefsData.docSectionMap[key].toindex - m_docPrefsData.docSectionMap[key].fromindex + 1));
}
else
{
QString newText;
uint docPageCount=DocPages.count();
for (uint a = 0; a < docPageCount; ++a)
{
if (DocPages.at(a)->MPageNam == it->OnMasterPage)
{
int key = getSectionKeyForPageIndex(a);
if (key == -1)
newText = "";
else
newText = QString("%1").arg(getStringFromSequence(m_docPrefsData.docSectionMap[key].type, m_docPrefsData.docSectionMap[key].toindex - m_docPrefsData.docSectionMap[key].fromindex + 1));
for (int nti=0;nti<newText.length();++nti)
if (pageNumberText.indexOf(newText[nti])==-1)
pageNumberText+=newText[nti];
}
}
}
}
//Now scan and add any glyphs used in page numbers
for (int pnti=0;pnti<pageNumberText.length(); ++pnti)
{
uint chr = pageNumberText[pnti].unicode();
if (font->canRender(chr))
{
uint gl = font->char2CMap(pageNumberText[pnti]);
FPointArray gly(font->glyphOutline(gl));
if (!font->replacementName().isEmpty())
Really[font->replacementName()].insert(gl, gly);
}
}
continue;
}
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
return;
 
if (it->itemText.hasFlag(e, ScLayout_SoftHyphenVisible))
if (!font().replacementName().isEmpty())
{
uint gl = it->itemText.charStyle(e).font().char2CMap(QChar('-'));
FPointArray gly(it->itemText.charStyle(e).font().glyphOutline(gl));
if (!it->itemText.charStyle(e).font().replacementName().isEmpty())
Really[it->itemText.charStyle(e).font().replacementName()].insert(gl, gly);
FPointArray outline(font().glyphOutline(gl.glyph));
m_really[font().replacementName()].insert(gl.glyph, outline);
}
if ((it->itemText.charStyle(e).effects() & ScStyle_SmallCaps) || (it->itemText.charStyle(e).effects() & ScStyle_AllCaps))
{
chstr = it->itemText.text(e);
if (chstr.toUpper() != chstr)
chstr = chstr.toUpper();
chr = chstr.unicode();
}
if (it->itemText.charStyle(e).font().canRender(chr))
{
uint gl = it->itemText.charStyle(e).font().char2CMap(chr);
gly = it->itemText.charStyle(e).font().glyphOutline(gl);
if (!it->itemText.charStyle(e).font().replacementName().isEmpty())
Really[it->itemText.charStyle(e).font().replacementName()].insert(gl, gly);
}
}
 
void drawGlyphOutline(const GlyphLayout gl, bool) { drawGlyph(gl); }
 
// we don't need this one
void drawLine(QPointF, QPointF) {}
void drawRect(QRectF) {}
void drawObject(PageItem*) {}
 
private:
QMap<QString, QMap<uint, FPointArray> > & m_really;
};
 
void ScribusDoc::checkItemForFonts(PageItem *it, QMap<QString, QMap<uint, FPointArray> > & Really, uint lc)
{
if (!it->isTextFrame() && !it->isPathText())
return;
 
UsedGlyphsPainter p(Really);
it->textLayout.render(&p);
}
 
 
/trunk/Scribus/scribus/scribusview.cpp
80,6 → 80,7
#include "hyphenator.h"
#include "iconmanager.h"
#include "loadsaveplugin.h"
#include "text/textlayoutpainter.h"
#include "pageitem.h"
#include "pageitem_group.h"
#include "pageitem_imageframe.h"
1651,8 → 1652,14
point.setX(textFrame->width() - point.x());
if (textFrame->imageFlippedV())
point.setY(textFrame->height() - point.y());
textFrame->itemText.setCursorPosition(textFrame->itemText.length() == 0 ? 0 :
textFrame->textLayout.screenToPosition(point));
if (textFrame->itemText.length() == 0)
textFrame->itemText.setCursorPosition(0);
else
{
int result = textFrame->textLayout.pointToPosition(point.toQPointF());
if (result >= 0)
textFrame->itemText.setCursorPosition(result);
}
 
if (textFrame->itemText.length() > 0)
{
2998,6 → 3005,91
}
}
 
// FIXME: the following code is untested, but it should give an idea for
// anyone who wants to fix and knows how to test it.
class TextToPathPainter: public TextLayoutPainter
{
ScribusView* m_view;
PageItem* m_item;
QList<PageItem*> m_group;
int m_counter;
 
public:
TextToPathPainter(ScribusView* view, PageItem* item)
: m_view(view)
, m_item(item)
, m_counter(0)
{}
 
void drawGlyph(const GlyphLayout gl)
{
 
FPointArray outline = font().glyphOutline(gl.glyph);
if (outline.size() < 4)
return;
QTransform transform = matrix();
transform.scale(x(), y());
outline.map(transform);
uint z = m_view->Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, m_item->xPos(), m_item->yPos(), m_item->width(), m_item->height(), m_item->lineWidth(), m_item->lineColor(), m_item->fillColor());
PageItem* item = m_view->Doc->Items->at(z);
m_view->undoManager->setUndoEnabled(false);
item->setTextFlowMode(m_item->textFlowMode());
item->setSizeLocked(m_item->sizeLocked());
item->setLocked(m_item->locked());
item->NamedLStyle = m_item->NamedLStyle;
item->setItemName(m_item->itemName() + "+U" + QString::number(m_counter++));
item->PoLine = outline.copy();
if (!m_item->asPathText())
item->setRotation(m_item->rotation());
item->setFillColor(fillColor().color);
item->setFillShade(fillColor().shade);
item->setLineWidth(strokeWidth());
m_view->Doc->adjustItemSize(item);
item->ContourLine = item->PoLine.copy();
item->ClipEdited = true;
item->FrameType = 3;
item->OldB2 = item->width();
item->OldH2 = item->height();
m_view->Doc->setRedrawBounding(item);
m_view->undoManager->setUndoEnabled(true);
m_group.append(m_view->Doc->Items->takeAt(z));
}
void drawGlyphOutline(const GlyphLayout gl, bool fill)
{
drawGlyph(gl);
}
void drawLine(QPointF start, QPointF end)
{
QTransform transform = matrix();
transform.translate(x(), y());
uint z = m_view->Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, m_item->xPos(), m_item->yPos(), m_item->width(), m_item->height(), m_item->lineWidth(), m_item->lineColor(), m_item->fillColor());
PageItem* item = m_view->Doc->Items->at(z);
m_view->undoManager->setUndoEnabled(false);
item->setTextFlowMode(m_item->textFlowMode());
item->setSizeLocked(m_item->sizeLocked());
item->setLocked(m_item->locked());
item->NamedLStyle = m_item->NamedLStyle;
item->setItemName(m_item->itemName() + "+U" + QString::number(m_counter++));
item->PoLine.resize(0);
item->PoLine.addQuadPoint(FPoint(start), FPoint(start), FPoint(end), FPoint(end));
item->PoLine.map(transform);
item->setLineColor(fillColor().color);
item->setLineShade(fillColor().shade);
item->setLineWidth(strokeWidth());
m_view->Doc->adjustItemSize(item);
item->ContourLine = item->PoLine.copy();
item->ClipEdited = true;
item->FrameType = 3;
item->OldB2 = item->width();
item->OldH2 = item->height();
m_view->Doc->setRedrawBounding(item);
m_view->undoManager->setUndoEnabled(true);
m_group.append(m_view->Doc->Items->takeAt(z));
}
void drawRect(QRectF rect) {}
void drawObject(PageItem* item) {}
};
 
void ScribusView::TextToPath()
{
if (Doc->appMode == modeEditClip)
3048,642 → 3140,9
++offset;
continue;
}
// newGroupedItems.clear();
FPointArray pts;
double x=0.0, y=0.0, wide=0.0;
QString chstr, ccounter;
QChar chstrex;
PageItem* bb;
 
if (currItem->asPathText())
{
for (int a = 0; a < currItem->asPathText()->itemRenderText.length(); ++a)
{
pts.resize(0);
x = 0.0;
y = 0.0;
//ScText * hl = currItem->asPathText()->itemRenderText.item_p(a);
const CharStyle& charStyle(currItem->asPathText()->itemRenderText.charStyle(a));
const PathData& pdata(currItem->textLayout.point(a));
const GlyphLayout* glyphs = currItem->asPathText()->itemRenderText.getGlyphs(a);
LayoutFlags flags = currItem->asPathText()->itemRenderText.flags(a);
chstr = currItem->asPathText()->itemRenderText.text(a,1);
if ((chstr == SpecialChars::PARSEP) || (chstr == SpecialChars::OLD_NBSPACE))
continue;
if (chstr == SpecialChars::OBJECT)
{
continue;
}
if (chstr == SpecialChars::PAGENUMBER)
chstr = currItem->ExpandToken(a);
double chs = charStyle.fontSize();
if (charStyle.effects() & ScStyle_SmallCaps)
{
if (chstr[0].toUpper() != chstr[0])
{
chs = qMax(static_cast<int>(charStyle.fontSize() * Doc->typographicPrefs().valueSmallCaps / 100), 1);
chstr = chstr[0].toUpper();
}
}
else if (charStyle.effects() & ScStyle_AllCaps)
chstr = chstr[0].toUpper();
// double csi = static_cast<double>(chs) / 100.0;
uint chr = chstr[0].unicode();
QPointF tangt = QPointF( cos(pdata.PRot), sin(pdata.PRot) );
QTransform chma, chma2, chma3, chma4, chma6;
QTransform trafo = QTransform( 1, 0, 0, -1, -pdata.PDx, 0 );
if (currItem->textPathFlipped)
trafo *= QTransform(1, 0, 0, -1, 0, 0);
if (currItem->textPathType == 0)
trafo *= QTransform( tangt.x(), tangt.y(), tangt.y(), -tangt.x(), pdata.PtransX, pdata.PtransY );
else if (currItem->textPathType == 1)
trafo *= QTransform(1, 0, 0, -1, pdata.PtransX, pdata.PtransY );
else if (currItem->textPathType == 2)
{
double a = 1;
double b = -1;
if (tangt.x() < 0)
{
a = -1;
b = 1;
}
if (fabs(tangt.x()) > 0.1)
trafo *= QTransform( a, (tangt.y() / tangt.x()) * b, 0, -1, pdata.PtransX, pdata.PtransY ); // ID's Skew mode
else
trafo *= QTransform( a, 6 * b, 0, -1, pdata.PtransX, pdata.PtransY );
}
//trafo *= QTransform( hl->PtransX, hl->PtransY, hl->PtransY, -hl->PtransX, glyphs->xoffset, glyphs->yoffset);
if (currItem->rotation() != 0)
{
QTransform sca;
sca.translate(-currItem->xPos(), -currItem->yPos());
sca.rotate(currItem->rotation());
trafo *= sca;
}
chma.scale(glyphs->scaleH * charStyle.fontSize() / 100.00, glyphs->scaleV * charStyle.fontSize() / 100.0);
if (currItem->reversed())
{
if (a < currItem->asPathText()->itemRenderText.length()-1)
wide = charStyle.font().charWidth(chstr[0], charStyle.fontSize(), currItem->asPathText()->itemRenderText.text(a+1));
else
wide = charStyle.font().charWidth(chstr[0], charStyle.fontSize());
chma3.scale(-1, 1);
chma3.translate(-wide, 0);
}
chma4.translate(0, currItem->BaseOffs - (charStyle.fontSize() / 10.0) * glyphs->scaleV);
if (charStyle.effects() & (ScStyle_Subscript | ScStyle_Superscript))
chma6.translate(0, glyphs->yoffset);
if (charStyle.baselineOffset() != 0)
chma6.translate(0, (-charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0));
uint gl = charStyle.font().char2CMap(chr);
QTransform finalMat = QTransform(chma * chma2 * chma3 * chma4 * chma6 * trafo);
if (currItem->rotation() != 0)
{
QTransform sca;
sca.translate(currItem->xPos(), currItem->yPos());
pts.map(sca);
}
QChar chstc = chstr[0];
if (((charStyle.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstc))
|| ((charStyle.effects() & ScStyle_UnderlineWords) && !chstc.isSpace() && !SpecialChars::isBreak(chstc)))
{
QTransform stro = QTransform(chma2 * chma3 * chma6 * trafo);
if (currItem->rotation() != 0)
{
QTransform sca;
sca.translate(currItem->xPos(), currItem->yPos());
stro *= sca;
}
double Ulen = glyphs->xadvance;
double Upos, Uwid, kern;
if (flags & ScLayout_StartOfLine)
kern = 0;
else
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
if ((charStyle.underlineOffset() != -1) || (charStyle.underlineWidth() != -1))
{
if (charStyle.underlineOffset() != -1)
Upos = (charStyle.underlineOffset() / 1000.0) * (charStyle.font().descent(charStyle.fontSize() / 10.0));
else
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
if (charStyle.underlineWidth() != -1)
Uwid = (charStyle.underlineWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
else
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
else
{
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
if (charStyle.baselineOffset() != 0)
Upos += (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
uint z = Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, currItem->xPos(), currItem->yPos(), currItem->width(), currItem->height(), currItem->lineWidth(), currItem->lineColor(), currItem->fillColor());
bb = Doc->Items->at(z);
undoManager->setUndoEnabled(false);
bb->setTextFlowMode(currItem->textFlowMode());
bb->setSizeLocked(currItem->sizeLocked());
bb->setLocked(currItem->locked());
bb->NamedLStyle = currItem->NamedLStyle;
bb->setItemName(currItem->itemName()+"+U"+ccounter.setNum(a));
FPoint start, stop;
if (charStyle.effects() & ScStyle_Subscript)
{
start = FPoint(glyphs->xoffset-kern, -Upos);
stop = FPoint(glyphs->xoffset+Ulen, -Upos);
}
else
{
start = FPoint(glyphs->xoffset-kern, -(Upos + glyphs->yoffset));
stop = FPoint(glyphs->xoffset+Ulen, -(Upos + glyphs->yoffset));
}
bb->PoLine.resize(0);
bb->PoLine.addQuadPoint(start, start, stop, stop);
bb->PoLine.map(stro);
bb->setLineColor(charStyle.fillColor());
bb->setLineShade(charStyle.fillShade());
bb->setLineWidth(Uwid);
Doc->adjustItemSize(bb);
bb->ContourLine = bb->PoLine.copy();
bb->ClipEdited = true;
bb->FrameType = 3;
bb->OldB2 = bb->width();
bb->OldH2 = bb->height();
Doc->setRedrawBounding(bb);
undoManager->setUndoEnabled(true);
newGroupedItems.append(Doc->Items->takeAt(z));
}
if ((chstr.length() > 0) && (!chstr.at(0).isSpace()))
{
pts = charStyle.font().glyphOutline(gl);
if (pts.size() < 4)
continue;
if ((charStyle.effects() & ScStyle_Shadowed) && (charStyle.strokeColor() != CommonStrings::None))
{
double glxTr = charStyle.fontSize() * charStyle.shadowXOffset() / 10000.0;
double glyTr = -charStyle.fontSize() * charStyle.shadowYOffset() / 10000.0;
uint z = Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, currItem->xPos(), currItem->yPos(), currItem->width(), currItem->height(), currItem->lineWidth(), currItem->lineColor(), currItem->fillColor());
bb = Doc->Items->at(z);
undoManager->setUndoEnabled(false);
bb->setTextFlowMode(currItem->textFlowMode());
bb->setSizeLocked(currItem->sizeLocked());
bb->setLocked(currItem->locked());
bb->NamedLStyle = currItem->NamedLStyle;
bb->setItemName(currItem->itemName()+"+Sh"+ccounter.setNum(a));
bb->PoLine = pts.copy();
QTransform shmap;
shmap.translate(glxTr, glyTr);
bb->PoLine.map(finalMat * shmap);
bb->setFillColor(charStyle.strokeColor());
bb->setFillShade(charStyle.strokeShade());
if (currItem->asPathText()->itemRenderText.charStyle(a).effects() & ScStyle_Outline)
{
bb->setLineColor(charStyle.strokeColor());
bb->setLineShade(charStyle.strokeShade());
}
else
{
bb->setLineColor(CommonStrings::None);
bb->setLineShade(100);
}
bb->setLineWidth(chs * charStyle.outlineWidth() / 10000.0);
Doc->adjustItemSize(bb);
bb->ContourLine = bb->PoLine.copy();
bb->ClipEdited = true;
bb->FrameType = 3;
bb->OldB2 = bb->width();
bb->OldH2 = bb->height();
Doc->setRedrawBounding(bb);
undoManager->setUndoEnabled(true);
newGroupedItems.append(Doc->Items->takeAt(z));
}
pts.map(finalMat);
uint z = Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, currItem->xPos(), currItem->yPos(), currItem->width(), currItem->height(), currItem->lineWidth(), currItem->lineColor(), currItem->fillColor());
bb = Doc->Items->at(z);
//bb->setTextFlowsAroundFrame(currItem->textFlowsAroundFrame());
//bb->setTextFlowUsesBoundingBox(currItem->textFlowUsesBoundingBox());
undoManager->setUndoEnabled(false);
bb->setTextFlowMode(currItem->textFlowMode());
bb->setSizeLocked(currItem->sizeLocked());
bb->setLocked(currItem->locked());
bb->NamedLStyle = currItem->NamedLStyle;
bb->setItemName(currItem->itemName()+"+"+ccounter.setNum(a));
bb->PoLine = pts.copy();
if (!currItem->asPathText())
bb->setRotation(currItem->rotation());
bb->setFillColor(charStyle.fillColor());
bb->setFillShade(charStyle.fillShade());
if (currItem->asPathText()->itemRenderText.charStyle(a).effects() & ScStyle_Outline)
{
bb->setLineColor(charStyle.strokeColor());
bb->setLineShade(charStyle.strokeShade());
}
else
{
bb->setLineColor(CommonStrings::None);
bb->setLineShade(100);
}
bb->setLineWidth(chs * charStyle.outlineWidth() / 10000.0);
Doc->adjustItemSize(bb);
bb->ContourLine = bb->PoLine.copy();
bb->ClipEdited = true;
bb->FrameType = 3;
bb->OldB2 = bb->width();
bb->OldH2 = bb->height();
Doc->setRedrawBounding(bb);
undoManager->setUndoEnabled(true);
newGroupedItems.append(Doc->Items->takeAt(z));
}
if (charStyle.effects() & ScStyle_Strikethrough)
{
QTransform stro = QTransform(chma2 * chma3 * chma6 * trafo);
if (currItem->rotation() != 0)
{
QTransform sca;
sca.translate(currItem->xPos(), currItem->yPos());
stro *= sca;
}
double Ulen = glyphs->xadvance;
double Upos, Uwid, kern;
if (flags & ScLayout_StartOfLine)
kern = 0;
else
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
if ((charStyle.strikethruOffset() != -1) || (charStyle.strikethruWidth() != -1))
{
if (charStyle.strikethruOffset() != -1)
Upos = (charStyle.strikethruOffset() / 1000.0) * (charStyle.font().ascent(charStyle.fontSize() / 10.0));
else
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
if (charStyle.strikethruWidth() != -1)
Uwid = (charStyle.strikethruWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
else
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
else
{
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
}
if (charStyle.baselineOffset() != 0)
Upos += (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
uint z = Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, currItem->xPos(), currItem->yPos(), currItem->width(), currItem->height(), currItem->lineWidth(), currItem->lineColor(), currItem->fillColor());
bb = Doc->Items->at(z);
undoManager->setUndoEnabled(false);
bb->setTextFlowMode(currItem->textFlowMode());
bb->setSizeLocked(currItem->sizeLocked());
bb->setLocked(currItem->locked());
bb->NamedLStyle = currItem->NamedLStyle;
bb->setItemName(currItem->itemName()+"+S"+ccounter.setNum(a));
FPoint start = FPoint(glyphs->xoffset-kern, -Upos);
FPoint stop = FPoint(glyphs->xoffset+Ulen, -Upos);
bb->PoLine.resize(0);
bb->PoLine.addQuadPoint(start, start, stop, stop);
bb->PoLine.map(stro);
bb->setLineColor(charStyle.fillColor());
bb->setLineShade(charStyle.fillShade());
bb->setLineWidth(Uwid);
Doc->adjustItemSize(bb);
bb->ContourLine = bb->PoLine.copy();
bb->ClipEdited = true;
bb->FrameType = 3;
bb->OldB2 = bb->width();
bb->OldH2 = bb->height();
Doc->setRedrawBounding(bb);
bb->setItemName(currItem->itemName()+"+S"+ccounter.setNum(a));
undoManager->setUndoEnabled(true);
newGroupedItems.append(Doc->Items->takeAt(z));
}
}
}
else
{
for (uint ll=0; ll < currItem->textLayout.lines(); ++ll)
{
LineSpec ls = currItem->textLayout.line(ll);
double CurX = ls.x;
for (int a = ls.firstItem; a <= ls.lastItem; ++a)
{
pts.resize(0);
x = 0.0;
y = 0.0;
GlyphLayout* glyphs = currItem->itemText.getGlyphs(a);
const CharStyle& charStyle(currItem->itemText.charStyle(a));
 
chstr = currItem->itemText.text(a,1);
if ((chstr == SpecialChars::PARSEP) || (chstr == SpecialChars::OLD_NBSPACE))
{
if (chstr == SpecialChars::OLD_NBSPACE)
CurX += glyphs->wide();
continue;
}
if (chstr == SpecialChars::OBJECT)
{
if (currItem->itemText.hasObject(a))
{
ScriXmlDoc ss;
Selection tempSelection(this, false);
tempSelection.addItem(currItem->itemText.object(a), true);
QString dataS = ss.WriteElem(Doc, &tempSelection);
emit LoadElem(dataS, currItem->xPos(), currItem->yPos(), false, true, Doc, this);
bb = Doc->Items->last();
int z = Doc->Items->indexOf(bb);
bb->setTextFlowMode(currItem->textFlowMode());
bb->setSizeLocked(currItem->sizeLocked());
bb->setLocked(currItem->locked());
bb->setItemName(currItem->itemName()+"+"+ccounter.setNum(a));
bb->setRotation(currItem->rotation());
double textX = CurX + glyphs->xoffset;
double textY = ls.y - bb->height();
if (charStyle.baselineOffset() != 0)
textY -= (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
if (currItem->imageFlippedH())
textX = currItem->width() - textX - wide;
if (currItem->imageFlippedV())
textY = currItem->height() - textY + y - (bb->height() - y);
FPoint npo(textX, textY, 0.0, 0.0, currItem->rotation(), 1.0, 1.0);
bb->setXYPos(currItem->xPos() + npo.x(), currItem->yPos() + npo.y(), false);
Doc->setRedrawBounding(bb);
newGroupedItems.append(Doc->Items->takeAt(z));
}
CurX += glyphs->wide();
continue;
}
if (chstr == SpecialChars::PAGENUMBER)
chstr = currItem->ExpandToken(a);
for (int cx = 0; cx < chstr.count(); cx++)
{
chstrex = chstr[cx];
double chs = charStyle.fontSize();
if (currItem->itemText.charStyle(a).effects() & ScStyle_SmallCaps)
{
if (chstrex.toUpper() != chstrex)
{
chs = qMax(static_cast<int>(chs * Doc->typographicPrefs().valueSmallCaps / 100), 1);
chstrex = chstrex.toUpper();
}
}
else if (currItem->itemText.charStyle(a).effects() & ScStyle_AllCaps)
chstrex = chstrex.toUpper();
double csi = static_cast<double>(chs) / 100.0;
uint chr = chstrex.unicode();
QTransform chma, chma6;