📄 bidi.cpp
字号:
BidiRun* r = 0;
for (r = sFirstBidiRun; r; r = r->nextRun) {
if (!r->box || r->obj->isPositioned())
continue; // Positioned objects are only participating to figure out their
// correct static x position. They have no effect on the width.
if (r->obj->isText()) {
int textWidth = static_cast<RenderText *>(r->obj)->width(r->start, r->stop-r->start, m_firstLine);
if (!r->compact) {
RenderStyle *style = r->obj->style();
if (style->whiteSpace() == NORMAL && style->khtmlLineBreak() == AFTER_WHITE_SPACE) {
// shrink the box as needed to keep the line from overflowing the available width
textWidth = kMin(textWidth, availableWidth - totWidth + style->borderLeftWidth());
}
}
r->box->setWidth(textWidth);
}
else if (!r->obj->isInlineFlow()) {
r->obj->calcWidth();
r->box->setWidth(r->obj->width());
if (!r->compact)
totWidth += r->obj->marginLeft() + r->obj->marginRight();
}
// Compacts don't contribute to the width of the line, since they are placed in the margin.
if (!r->compact)
totWidth += r->box->width();
}
// Armed with the total width of the line (without justification),
// we now examine our text-align property in order to determine where to position the
// objects horizontally. The total width of the line can be increased if we end up
// justifying text.
int x = leftOffset(m_height);
switch(style()->textAlign()) {
case LEFT:
case KHTML_LEFT:
// The direction of the block should determine what happens with wide lines. In
// particular with RTL blocks, wide lines should still spill out to the left.
if (style()->direction() == RTL && totWidth > availableWidth)
x -= (totWidth - availableWidth);
numSpaces = 0;
break;
case JUSTIFY:
if (numSpaces != 0 && !bidi.current.atEnd() && !lineBox->endsWithBreak())
break;
// fall through
case TAAUTO:
numSpaces = 0;
// for right to left fall through to right aligned
if (bidi.context->basicDir == QChar::DirL)
break;
case RIGHT:
case KHTML_RIGHT:
// Wide lines spill out of the block based off direction.
// So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
// side of the block.
if (style()->direction() == RTL || totWidth < availableWidth)
x += availableWidth - totWidth;
numSpaces = 0;
break;
case CENTER:
case KHTML_CENTER:
int xd = (availableWidth - totWidth)/2;
x += xd >0 ? xd : 0;
numSpaces = 0;
break;
}
if (numSpaces > 0) {
for (r = sFirstBidiRun; r; r = r->nextRun) {
if (!r->box) continue;
int spaceAdd = 0;
if (numSpaces > 0 && r->obj->isText() && !r->compact) {
// get the number of spaces in the run
int spaces = 0;
for ( int i = r->start; i < r->stop; i++ ) {
const QChar c = static_cast<RenderText *>(r->obj)->text()[i];
if (c == ' ' || c == '\n')
spaces++;
}
KHTMLAssert(spaces <= numSpaces);
// Only justify text with white-space: normal.
if (r->obj->style()->whiteSpace() != PRE) {
#if NOKIA_CHANGES
RenderCanvas* c = canvas();
if(c) {
if(c->view()) {
int bidiWidth = c->view()->maxBidiWidth();
bidiWidth = QMAX(bidiWidth - leftOffset(m_height),0);
availableWidth = QMIN(availableWidth,bidiWidth);
}
}
#endif
spaceAdd = (availableWidth - totWidth)*spaces/numSpaces;
static_cast<InlineTextBox*>(r->box)->setSpaceAdd(spaceAdd);
totWidth += spaceAdd;
}
numSpaces -= spaces;
}
}
}
// The widths of all runs are now known. We can now place every inline box (and
// compute accurate widths for the inline flow boxes).
int leftPosition = x;
int rightPosition = x;
lineBox->placeBoxesHorizontally(x, leftPosition, rightPosition);
lineBox->setHorizontalOverflowPositions(leftPosition, rightPosition);
}
void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox)
{
lineBox->verticallyAlignBoxes(m_height);
lineBox->setBlockHeight(m_height);
// See if the line spilled out. If so set overflow height accordingly.
int bottomOfLine = lineBox->bottomOverflow();
if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight)
m_overflowHeight = bottomOfLine;
// Now make sure we place replaced render objects correctly.
for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
if (!r->box) continue; // Skip runs with no line boxes.
// Align positioned boxes with the top of the line box. This is
// a reasonable approximation of an appropriate y position.
if (r->obj->isPositioned())
r->box->setYPos(m_height);
// Position is used to properly position both replaced elements and
// to update the static normal flow x/y of positioned elements.
r->obj->position(r->box, r->start, r->stop - r->start, r->level%2);
}
}
// collects one line of the paragraph and transforms it to visual order
void RenderBlock::bidiReorderLine(const BidiIterator &start, const BidiIterator &end, BidiState &bidi)
{
if ( start == end ) {
if ( start.current() == '\n' ) {
m_height += lineHeight( m_firstLine, true );
}
return;
}
#if BIDI_DEBUG > 1
kdDebug(6041) << "reordering Line from " << start.obj << "/" << start.pos << " to " << end.obj << "/" << end.pos << endl;
#endif
sFirstBidiRun = 0;
sLastBidiRun = 0;
sBidiRunCount = 0;
// context->ref();
dir = QChar::DirON;
// Adopt the directionality of the text's element if specified as RTL
// and the first position is neutral.
if (start.direction() == QChar::DirON) {
if (start.obj) {
if (start.obj->style()->direction() == RTL)
dir = QChar::DirR;
}
else if (style()->direction() == RTL) {
dir = QChar::DirR;
}
}
emptyRun = true;
numSpaces = 0;
bidi.current = start;
bidi.last = bidi.current;
bool atEnd = false;
while( 1 ) {
QChar::Direction dirCurrent;
if (atEnd) {
//kdDebug(6041) << "atEnd" << endl;
BidiContext *c = bidi.context;
if ( bidi.current.atEnd())
while ( c->parent )
c = c->parent;
dirCurrent = c->dir;
} else {
dirCurrent = bidi.current.direction();
}
#ifndef QT_NO_UNICODETABLES
#if BIDI_DEBUG > 1
kdDebug(6041) << "directions: dir=" << (int)dir << " current=" << (int)dirCurrent << " last=" << status.last << " eor=" << status.eor << " lastStrong=" << status.lastStrong << " embedding=" << (int)context->dir << " level =" << (int)context->level << endl;
#endif
switch(dirCurrent) {
// embedding and overrides (X1-X9 in the Bidi specs)
case QChar::DirRLE:
case QChar::DirLRE:
case QChar::DirRLO:
case QChar::DirLRO:
case QChar::DirPDF:
bidi.eor = bidi.last;
embed( dirCurrent, bidi );
break;
// strong types
case QChar::DirL:
if(dir == QChar::DirON)
dir = QChar::DirL;
switch(bidi.status.last)
{
case QChar::DirL:
bidi.eor = bidi.current; bidi.status.eor = QChar::DirL; break;
case QChar::DirR:
case QChar::DirAL:
case QChar::DirEN:
case QChar::DirAN:
appendRun( bidi );
break;
case QChar::DirES:
case QChar::DirET:
case QChar::DirCS:
case QChar::DirBN:
case QChar::DirB:
case QChar::DirS:
case QChar::DirWS:
case QChar::DirON:
if(dir != QChar::DirL) {
//last stuff takes embedding dir
if( bidi.context->dir == QChar::DirR ) {
if(!(bidi.status.eor == QChar::DirR)) {
// AN or EN
appendRun( bidi );
dir = QChar::DirR;
}
else
bidi.eor = bidi.last;
appendRun( bidi );
dir = QChar::DirL;
bidi.status.eor = QChar::DirL;
} else {
if(bidi.status.eor == QChar::DirR) {
appendRun( bidi );
dir = QChar::DirL;
} else {
bidi.eor = bidi.current; bidi.status.eor = QChar::DirL; break;
}
}
} else {
bidi.eor = bidi.current; bidi.status.eor = QChar::DirL;
}
default:
break;
}
bidi.status.lastStrong = QChar::DirL;
break;
case QChar::DirAL:
case QChar::DirR:
if(dir == QChar::DirON) dir = QChar::DirR;
switch(bidi.status.last)
{
case QChar::DirR:
case QChar::DirAL:
bidi.eor = bidi.current; bidi.status.eor = QChar::DirR; break;
case QChar::DirL:
case QChar::DirEN:
case QChar::DirAN:
appendRun( bidi );
dir = QChar::DirR;
bidi.eor = bidi.current;
bidi.status.eor = QChar::DirR;
break;
case QChar::DirES:
case QChar::DirET:
case QChar::DirCS:
case QChar::DirBN:
case QChar::DirB:
case QChar::DirS:
case QChar::DirWS:
case QChar::DirON:
if( !(bidi.status.eor == QChar::DirR) && !(bidi.status.eor == QChar::DirAL) ) {
//last stuff takes embedding dir
if(bidi.context->dir == QChar::DirR || bidi.status.lastStrong == QChar::DirR) {
appendRun( bidi );
dir = QChar::DirR;
bidi.eor = bidi.current;
bidi.status.eor = QChar::DirR;
} else {
bidi.eor = bidi.last;
appendRun( bidi );
dir = QChar::DirR;
bidi.status.eor = QChar::DirR;
}
} else {
bidi.eor = bidi.current; bidi.status.eor = QChar::DirR;
}
default:
break;
}
bidi.status.lastStrong = dirCurrent;
break;
// weak types:
case QChar::DirNSM:
// ### if @sor, set dir to dirSor
break;
case QChar::DirEN:
if(!(bidi.status.lastStrong == QChar::DirAL)) {
// if last strong was AL change EN to AN
if(dir == QChar::DirON) {
if(bidi.status.lastStrong == QChar::DirAL)
dir = QChar::DirAN;
else
dir = QChar::DirL;
}
switch(bidi.status.last)
{
case QChar::DirET:
if ( bidi.status.lastStrong == QChar::DirR || bidi.status.lastStrong == QChar::DirAL ) {
appendRun( bidi );
dir = QChar::DirEN;
bidi.status.eor = QChar::DirEN;
}
// fall through
case QChar::DirEN:
case QChar::DirL:
bidi.eor = bidi.current;
bidi.status.eor = dirCurrent;
break;
case QChar::DirR:
case QChar::DirAL:
case QChar::DirAN:
appendRun( bidi );
bidi.status.eor = QChar::DirEN;
dir = QChar::DirEN; break;
case QChar::DirES:
case QChar::DirCS:
if(bidi.status.eor == QChar::DirEN) {
bidi.eor = bidi.current; break;
}
case QChar::DirBN:
case QChar::DirB:
case QChar::DirS:
case QChar::DirWS:
case QChar::DirON:
if(bidi.status.eor == QChar::DirR) {
// neutrals go to R
bidi.eor = bidi.last;
appendRun( bidi );
dir = QChar::DirEN;
bidi.status.eor = QChar::DirEN;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -