drawBidiText >> width > floatWidthForComplexText > widthOfFullRun > nextScriptRun > setupFontForScriptRun
148 void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, int tx, int ty) 149 { 150 if (!pluginCrashedOrWasMissing()) 151 return; 152 153 if (paintInfo.phase == PaintPhaseSelection) 154 return; 155 156 GraphicsContext* context = paintInfo.context; 157 if (context->paintingDisabled()) 158 return; 159 160 FloatRect contentRect; 161 Path path; 162 FloatRect replacementTextRect; 163 Font font; 164 TextRun run(""); 165 float textWidth; 166 if (!getReplacementTextGeometry(tx, ty, contentRect, path, replacementTextRect, font, run, textWidth)) 167 return; 168 169 context->save(); 170 context->clip(contentRect); 171 context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedRoundedRectOpacity : replacementTextRoundedRectOpacity); 172 context->setFillColor(m_missingPluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : Color::white, style()->colorSpace()); 173 context->fillPath(path); 174 175 const FontMetrics& fontMetrics = font.fontMetrics(); 176 float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2); 177 float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent()); 178 context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedTextOpacity : replacementTextTextOpacity); 179 context->setFillColor(Color::black, style()->colorSpace()); 180 context->drawBidiText(font, run, FloatPoint(labelX, labelY)); <======= 181 context->restore(); 182 }
212 void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty) 213 { 214 if (style()->visibility() != VISIBLE) 215 return; 216 ASSERT(m_fileChooser); 217 218 // Push a clip. 219 if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) { 220 IntRect clipRect(tx + borderLeft(), ty + borderTop(), 221 width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop() + buttonShadowHeight); 222 if (clipRect.isEmpty()) 223 return; 224 paintInfo.context->save(); 225 paintInfo.context->clip(clipRect); 226 } 227 228 if (paintInfo.phase == PaintPhaseForeground) { 229 const String& displayedFilename = fileTextValue(); 230 unsigned length = displayedFilename.length(); 231 const UChar* string = displayedFilename.characters(); 232 TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !style()->isLeftToRightDirection(), style()->unicodeBidi() == Override); 233 234 // Determine where the filename should be placed 235 int contentLeft = tx + borderLeft() + paddingLeft(); 236 int buttonAndIconWidth = m_button->renderBox()->width() + afterButtonSpacing 237 + (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0); 238 int textX; 239 if (style()->isLeftToRightDirection()) 240 textX = contentLeft + buttonAndIconWidth; 241 else 242 textX = contentLeft + contentWidth() - buttonAndIconWidth - style()->font().width(textRun); 243 // We want to match the button's baseline 244 RenderButton* buttonRenderer = toRenderButton(m_button->renderer()); 245 int textY = buttonRenderer->absoluteBoundingBoxRect().y() 246 + buttonRenderer->marginTop() + buttonRenderer->borderTop() + buttonRenderer->paddingTop() 247 + buttonRenderer->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine); 248 249 paintInfo.context->setFillColor(style()->visitedDependentColor(CSSPropertyColor), style()->colorSpace()); 250 251 // Draw the filename 252 paintInfo.context->drawBidiText(style()->font(), textRun, IntPoint(textX, textY)); <========== 253 254 if (m_fileChooser->icon()) { 255 // Determine where the icon should be placed 256 int iconY = ty + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2; 257 int iconX; 258 if (style()->isLeftToRightDirection()) 259 iconX = contentLeft + m_button->renderBox()->width() + afterButtonSpacing; 260 else 261 iconX = contentLeft + contentWidth() - m_button->renderBox()->width() - afterButtonSpacing - iconWidth; 262 263 // Draw the file icon 264 m_fileChooser->icon()->paint(paintInfo.context, IntRect(iconX, iconY, iconWidth, iconHeight)); 265 } 266 } 267 268 // Paint the children. 269 RenderBlock::paintObject(paintInfo, tx, ty); 270 271 // Pop the clip. 272 if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) 273 paintInfo.context->restore(); 274 }
358 void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, int listIndex) 359 { 360 SelectElement* select = toSelectElement(static_cast<Element*>(node())); 361 const Vector<Element*>& listItems = select->listItems(); 362 Element* element = listItems[listIndex]; 363 OptionElement* optionElement = toOptionElement(element); 364 365 RenderStyle* itemStyle = element->renderStyle(); 366 if (!itemStyle) 367 itemStyle = style(); 368 369 if (itemStyle->visibility() == HIDDEN) 370 return; 371 372 String itemText; 373 if (optionElement) 374 itemText = optionElement->textIndentedToRespectGroupLabel(); 375 else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) 376 itemText = optionGroupElement->groupLabelText(); 377 378 Color textColor = element->renderStyle() ? element->renderStyle()->visitedDependentColor(CSSPropertyColor) : style()->visitedDependentColor(CSSPropertyColor); 379 if (optionElement && optionElement->selected()) { 380 if (frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) 381 textColor = theme()->activeListBoxSelectionForegroundColor(); 382 // Honor the foreground color for disabled items 383 else if (!element->disabled()) 384 textColor = theme()->inactiveListBoxSelectionForegroundColor(); 385 } 386 387 ColorSpace colorSpace = itemStyle->colorSpace(); 388 paintInfo.context->setFillColor(textColor, colorSpace); 389 390 unsigned length = itemText.length(); 391 const UChar* string = itemText.characters(); 392 TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override); 393 Font itemFont = style()->font(); 394 IntRect r = itemBoundingBoxRect(tx, ty, listIndex); 395 r.move(itemOffsetForAlignment(textRun, itemStyle, itemFont, r)); 396 397 if (isOptionGroupElement(element)) { 398 FontDescription d = itemFont.fontDescription(); 399 d.setWeight(d.bolderWeight()); 400 itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); 401 itemFont.update(document()->styleSelector()->fontSelector()); 402 } 403 404 // Draw the item text 405 if (itemStyle->visibility() != HIDDEN) 406 paintInfo.context->drawBidiText(itemFont, textRun, r.location()); 407 }
630 void RenderTextControl::paintPlaceholder(PaintInfo& paintInfo, int tx, int ty) 631 { 632 if (style()->visibility() != VISIBLE) 633 return; 634 635 IntRect clipRect(tx + borderLeft(), ty + borderTop(), width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop()); 636 if (clipRect.isEmpty()) 637 return; 638 639 paintInfo.context->save(); 640 641 paintInfo.context->clip(clipRect); 642 643 RefPtr<RenderStyle> placeholderStyle = getCachedPseudoStyle(INPUT_PLACEHOLDER); 644 if (!placeholderStyle) 645 placeholderStyle = style(); 646 647 paintInfo.context->setFillColor(placeholderStyle->visitedDependentColor(CSSPropertyColor), placeholderStyle->colorSpace()); 648 649 String placeholderText = static_cast<HTMLTextFormControlElement*>(node())->strippedPlaceholder(); 650 TextRun textRun(placeholderText.characters(), placeholderText.length(), false, 0, 0, TextRun::AllowTrailingExpansion, !placeholderStyle->isLeftToRightDirection(), placeholderStyle->unicodeBidi() == Override); 651 652 RenderBox* textRenderer = innerTextElement() ? innerTextElement()->renderBox() : 0; 653 if (textRenderer) { 654 IntPoint textPoint; 655 textPoint.setY(ty + textBlockInsetTop() + placeholderStyle->fontMetrics().ascent()); 656 if (placeholderStyle->isLeftToRightDirection()) 657 textPoint.setX(tx + textBlockInsetLeft()); 658 else 659 textPoint.setX(tx + width() - textBlockInsetRight() - style()->font().width(textRun)); 660 661 paintInfo.context->drawBidiText(placeholderStyle->font(), textRun, textPoint); <========== 662 } 663 paintInfo.context->restore(); 664 }
=========================================================================================
=========================================================================================
395 void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point) 396 { 397 if (paintingDisabled()) 398 return; 399 400 // FIXME: This ownership should be reversed. We should pass BidiRunList 401 // to BidiResolver in createBidiRunsForLine. 402 BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; 403 BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); 404 405 WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; 406 407 bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, BidiContext::create(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); 408 409 bidiResolver.setPosition(TextRunIterator(&run, 0)); 410 bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); 411 412 if (!bidiRuns.runCount()) 413 return; 414 415 FloatPoint currPoint = point; 416 BidiCharacterRun* bidiRun = bidiRuns.firstRun(); 417 while (bidiRun) { 418 419 TextRun subrun = run; 420 subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start()); 421 subrun.setRTL(bidiRun->level() % 2); 422 subrun.setDirectionalOverride(bidiRun->dirOverride(false)); 423 424 font.drawText(this, subrun, currPoint); 425 426 bidiRun = bidiRun->next(); 427 // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here. 428 if (bidiRun) 429 currPoint.move(font.width(subrun), 0); <============= 430 } 431 432 bidiRuns.deleteRuns(); 433 }
168 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 169 { 170 #if ENABLE(SVG_FONTS) 171 if (primaryFont()->isSVGFont()) 172 return floatWidthUsingSVGFont(run); 173 #endif 174 175 CodePath codePathToUse = codePath(run); 176 if (codePathToUse != Complex) { 177 // If the complex text implementation cannot return fallback fonts, avoid 178 // returning them for simple text as well. 179 static bool returnFallbackFonts = canReturnFallbackFontsForComplexText(); 180 return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow || (glyphOverflow && glyphOverflow->computeBounds) ? glyphOverflow : 0); 181 } 182 183 return floatWidthForComplexText(run, fallbackFonts, glyphOverflow); 184 }186 float Font::width(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const 187 { 188 #if !ENABLE(SVG_FONTS) 189 UNUSED_PARAM(extraCharsAvailable); 190 #else 191 if (primaryFont()->isSVGFont()) 192 return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName); 193 #endif 194 195 charsConsumed = run.length(); 196 glyphName = ""; 197 198 if (codePath(run) != Complex) 199 return floatWidthForSimpleText(run, 0); 200 201 return floatWidthForComplexText(run); 202 }
1076 float Font::floatWidthForComplexText(const TextRun& run, 1077 HashSet<const SimpleFontData*>*, GlyphOverflow*) const 1078 { 1079 TextRunWalker walker(run, 0, 0, this); 1080 walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); 1081 return walker.widthOfFullRun(); 1082 }
675 float TextRunWalker::widthOfFullRun() 676 { 677 float widthSum = 0; 678 while (nextScriptRun()) 679 widthSum += width(); 680 681 return widthSum; 682 }
629 // Advance to the next script run, returning false when the end of the 630 // TextRun has been reached. 631 bool TextRunWalker::nextScriptRun() 632 { 633 if (m_iterateBackwards) { 634 // In right-to-left mode we need to render the shaped glyph backwards and 635 // also render the script runs themselves backwards. So given a TextRun: 636 // AAAAAAACTTTTTTT (A = Arabic, C = Common, T = Thai) 637 // we render: 638 // TTTTTTCAAAAAAA 639 // (and the glyphs in each A, C and T section are backwards too) 640 if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), 641 m_run.length(), &m_indexOfNextScriptRun)) 642 return false; 643 } else { 644 if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), 645 m_run.length(), &m_indexOfNextScriptRun)) 646 return false; 647 648 // It is actually wrong to consider script runs at all in this code. 649 // Other WebKit code (e.g. Mac) segments complex text just by finding 650 // the longest span of text covered by a single font. 651 // But we currently need to call hb_utf16_script_run_next anyway to fill 652 // in the harfbuzz data structures to e.g. pick the correct script's shaper. 653 // So we allow that to run first, then do a second pass over the range it 654 // found and take the largest subregion that stays within a single font. 655 const FontData* glyphData = m_font->glyphDataForCharacter( 656 m_item.string[m_item.item.pos], false).fontData; 657 unsigned endOfRun; 658 for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) { 659 const FontData* nextGlyphData = m_font->glyphDataForCharacter( 660 m_item.string[m_item.item.pos + endOfRun], false).fontData; 661 if (nextGlyphData != glyphData) 662 break; 663 } 664 m_item.item.length = endOfRun; 665 m_indexOfNextScriptRun = m_item.item.pos + endOfRun; 666 } 667 668 setupFontForScriptRun(); 669 shapeGlyphs(); 670 setGlyphPositions(rtl()); 671 672 return true; 673 }
727 void TextRunWalker::setupFontForScriptRun() 728 { 729 const FontData* fontData = m_font->glyphDataForCharacter(m_run[0], false).fontData; 730 const FontPlatformData& platformData = 731 fontData->fontDataForCharacter(' ')->platformData(); 732 const FontPlatformData* complexPlatformData = setupComplexFont(m_item.item.script, platformData); 733 734 m_item.face = complexPlatformData->harfbuzzFace(); 735 m_item.font->userData = const_cast<FontPlatformData*>(complexPlatformData); 736 737 int size = complexPlatformData->size(); 738 m_item.font->x_ppem = size; 739 m_item.font->y_ppem = size; 740 // x_ and y_scale are the conversion factors from font design space (fEmSize) to 1/64th of device pixels in 16.16 format. 741 const int devicePixelFraction = 64; 742 const int multiplyFor16Dot16 = 1 << 16; 743 int scale = devicePixelFraction * size * multiplyFor16Dot16 / complexPlatformData->emSizeInFontUnits(); 744 m_item.font->x_scale = scale; 745 m_item.font->y_scale = scale; 746 }