📄 bidi.cpp
字号:
}static void reverseRuns(int start, int end){ if (start >= end) return; assert(start >= 0 && end < sBidiRunCount); // Get the item before the start of the runs to reverse and put it in // |beforeStart|. |curr| should point to the first run to reverse. BidiRun* curr = sFirstBidiRun; BidiRun* beforeStart = 0; int i = 0; while (i < start) { i++; beforeStart = curr; curr = curr->nextRun; } BidiRun* startRun = curr; while (i < end) { i++; curr = curr->nextRun; } BidiRun* endRun = curr; BidiRun* afterEnd = curr->nextRun; i = start; curr = startRun; BidiRun* newNext = afterEnd; while (i <= end) { // Do the reversal. BidiRun* next = curr->nextRun; curr->nextRun = newNext; newNext = curr; curr = next; i++; } // Now hook up beforeStart and afterEnd to the newStart and newEnd. if (beforeStart) beforeStart->nextRun = endRun; else sFirstBidiRun = endRun; startRun->nextRun = afterEnd; if (!afterEnd) sLastBidiRun = startRun;}static void chopMidpointsAt(RenderObject* obj, uint pos){ if (!sNumMidpoints) return; BidiIterator* midpoints = smidpoints->data(); for (uint i = 0; i < sNumMidpoints; i++) { const BidiIterator& point = midpoints[i]; if (point.obj == obj && point.pos == pos) { sNumMidpoints = i; break; } }}static void checkMidpoints(BidiIterator& lBreak, BidiState &bidi){ // Check to see if our last midpoint is a start point beyond the line break. If so, // shave it off the list, and shave off a trailing space if the previous end point isn't // white-space: pre. if (lBreak.obj && sNumMidpoints && sNumMidpoints%2 == 0) { BidiIterator* midpoints = smidpoints->data(); BidiIterator& endpoint = midpoints[sNumMidpoints-2]; const BidiIterator& startpoint = midpoints[sNumMidpoints-1]; BidiIterator currpoint = endpoint; while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak) currpoint.increment( bidi ); if (currpoint == lBreak) { // We hit the line break before the start point. Shave off the start point. sNumMidpoints--; if (!endpoint.obj->style()->preserveWS()) { if (endpoint.obj->isText()) { // Don't shave a character off the endpoint if it was from a soft hyphen. RenderText* textObj = static_cast<RenderText*>(endpoint.obj); if (endpoint.pos+1 < textObj->length() && textObj->text()[endpoint.pos+1].unicode() == SOFT_HYPHEN) return; } endpoint.pos--; } } }}static void addMidpoint(const BidiIterator& midpoint){ if (!smidpoints) return; if (smidpoints->size() <= sNumMidpoints) smidpoints->resize(sNumMidpoints+10); BidiIterator* midpoints = smidpoints->data(); midpoints[sNumMidpoints++] = midpoint;}static void appendRunsForObject(int start, int end, RenderObject* obj, BidiState &bidi){ if (start > end || obj->isFloating() || (obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY())) return; bool haveNextMidpoint = (smidpoints && sCurrMidpoint < sNumMidpoints); BidiIterator nextMidpoint; if (haveNextMidpoint) nextMidpoint = smidpoints->at(sCurrMidpoint); if (betweenMidpoints) { if (!(haveNextMidpoint && nextMidpoint.obj == obj)) return; // This is a new start point. Stop ignoring objects and // adjust our start. betweenMidpoints = false; start = nextMidpoint.pos; sCurrMidpoint++; if (start < end) return appendRunsForObject(start, end, obj, bidi); } else { if (!smidpoints || !haveNextMidpoint || (obj != nextMidpoint.obj)) { addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context, dir)); return; } // An end midpoint has been encountered within our object. We // need to go ahead and append a run with our endpoint. if (int(nextMidpoint.pos+1) <= end) { betweenMidpoints = true; sCurrMidpoint++; if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it. addRun(new (obj->renderArena()) BidiRun(start, nextMidpoint.pos+1, obj, bidi.context, dir)); return appendRunsForObject(nextMidpoint.pos+1, end, obj, bidi); } } else addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context, dir)); }}static void appendRun( BidiState &bidi ){ if ( emptyRun ) return;#if BIDI_DEBUG > 1 kdDebug(6041) << "appendRun: dir="<<(int)dir<<endl;#endif bool b = adjustEmbedding; adjustEmbedding = false; int start = bidi.sor.pos; RenderObject *obj = bidi.sor.obj; while( obj && obj != bidi.eor.obj ) { appendRunsForObject(start, obj->length(), obj, bidi); start = 0; obj = Bidinext( bidi.sor.par, obj, bidi ); } if (obj) appendRunsForObject(start, bidi.eor.pos+1, obj, bidi); bidi.eor.increment( bidi ); bidi.sor = bidi.eor; dir = QChar::DirON; bidi.status.eor = QChar::DirON; adjustEmbedding = b;}static void embed( QChar::Direction d, BidiState &bidi ){#if BIDI_DEBUG > 1 qDebug("*** embed dir=%d emptyrun=%d", d, emptyRun );#endif bool b = adjustEmbedding ; adjustEmbedding = false; if ( d == QChar::DirPDF ) { BidiContext *c = bidi.context->parent; if (c) { if ( bidi.eor != bidi.last ) { appendRun( bidi ); bidi.eor = bidi.last; } appendRun( bidi ); emptyRun = true; bidi.status.last = bidi.context->dir; bidi.context->deref(); bidi.context = c; if(bidi.context->override) dir = bidi.context->dir; else dir = QChar::DirON; bidi.status.lastStrong = bidi.context->dir; } } else { QChar::Direction runDir; if( d == QChar::DirRLE || d == QChar::DirRLO ) runDir = QChar::DirR; else runDir = QChar::DirL; bool override; if( d == QChar::DirLRO || d == QChar::DirRLO ) override = true; else override = false; unsigned char level = bidi.context->level; if ( runDir == QChar::DirR ) { if(level%2) // we have an odd level level += 2; else level++; } else { if(level%2) // we have an odd level level++; else level += 2; } if(level < 61) { if ( bidi.eor != bidi.last ) { appendRun( bidi ); bidi.eor = bidi.last; } appendRun( bidi ); emptyRun = true; bidi.context = new BidiContext(level, runDir, bidi.context, override); bidi.context->ref(); dir = runDir; bidi.status.last = runDir; bidi.status.lastStrong = runDir; bidi.status.eor = runDir; } } adjustEmbedding = b;}InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj){ // See if we have an unconstructed line box for this object that is also // the last item on the line. KHTMLAssert(obj->isInlineFlow() || obj == this); RenderFlow* flow = static_cast<RenderFlow*>(obj); // Get the last box we made for this render object. InlineFlowBox* box = flow->lastLineBox(); // If this box is constructed then it is from a previous line, and we need // to make a new box for our line. If this box is unconstructed but it has // something following it on the line, then we know we have to make a new box // as well. In this situation our inline has actually been split in two on // the same line (this can happen with very fancy language mixtures). if (!box || box->isConstructed() || box->nextOnLine()) { // We need to make a new box for this render object. Once // made, we need to place it at the end of the current line. InlineBox* newBox = obj->createInlineBox(false, obj == this); KHTMLAssert(newBox->isInlineFlowBox()); box = static_cast<InlineFlowBox*>(newBox); box->setFirstLineStyleBit(m_firstLine); // We have a new box. Append it to the inline box we get by constructing our // parent. If we have hit the block itself, then |box| represents the root // inline box for the line, and it doesn't have to be appended to any parent // inline. if (obj != this) { InlineFlowBox* parentBox = createLineBoxes(obj->parent()); parentBox->addToLine(box); } } return box;}InlineFlowBox* RenderBlock::constructLine(const BidiIterator &start, const BidiIterator &end){ if (!sFirstBidiRun) return 0; // We had no runs. Don't make a root inline box at all. The line is empty. InlineFlowBox* parentBox = 0; for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) { // Create a box for our object. r->box = r->obj->createInlineBox(r->obj->isPositioned(), false); // If we have no parent box yet, or if the run is not simply a sibling, // then we need to construct inline boxes as necessary to properly enclose the // run's inline box. if (!parentBox || (parentBox->object() != r->obj->parent())) // Create new inline boxes all the way back to the appropriate insertion point. parentBox = createLineBoxes(r->obj->parent()); // Append the inline box to this line. parentBox->addToLine(r->box); } // We should have a root inline box. It should be unconstructed and // be the last continuation of our line list. KHTMLAssert(lastLineBox() && !lastLineBox()->isConstructed()); // Set bits on our inline flow boxes that indicate which sides should // paint borders/margins/padding. This knowledge will ultimately be used when // we determine the horizontal positions and widths of all the inline boxes on // the line. RenderObject* endObject = 0; bool lastLine = !end.obj; if (end.obj && end.pos == 0) endObject = end.obj; lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject); // Now mark the line boxes as being constructed. lastLineBox()->setConstructed(); // Return the last line. return lastLineBox();}void RenderBlock::computeHorizontalPositionsForLine(InlineFlowBox* lineBox, BidiState &bidi){ // First determine our total width. int totWidth = lineBox->getFlowSpacingWidth(); BidiRun* r = 0; for (r = sFirstBidiRun; r; r = r->nextRun) { if (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()) r->box->setWidth(static_cast<RenderText *>(r->obj)->width(r->start, r->stop-r->start, m_firstLine)); else if (!r->obj->isInlineFlow()) { r->obj->calcWidth(); r->box->setWidth(r->obj->width()); totWidth += r->obj->marginLeft() + r->obj->marginRight(); } 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); int availableWidth = lineWidth(m_height); switch(style()->textAlign()) { case LEFT: case KHTML_LEFT: numSpaces = 0; break; case JUSTIFY: if (numSpaces != 0 && !bidi.current.atEnd() && !bidi.current.obj->isBR() ) 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: x += availableWidth - totWidth; numSpaces = 0; break; case CENTER: case KHTML_CENTER: int xd = (availableWidth - totWidth)/2; x += xd >0 ? xd : 0; numSpaces = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -