TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFragment& fragment) const { ASSERT(style); ASSERT(textRenderer()); RenderText* text = textRenderer(); ASSERT(text); TextRun run(text->characters() + fragment.characterOffset , fragment.length , false /* allowTabs */ , 0 /* xPos, only relevant with allowTabs=true */ , 0 /* padding, only relevant for justified text, not relevant for SVG */ , TextRun::AllowTrailingExpansion , direction() , m_dirOverride || style->rtlOrdering() == VisualOrder /* directionalOverride */); if (textRunNeedsRenderingContext(style->font())) run.setRenderingContext(SVGTextRunRenderingContext::create(text)); run.disableRoundingHacks(); // We handle letter & word spacing ourselves. run.disableSpacing(); // Propagate the maximum length of the characters buffer to the TextRun, even when we're only processing a substring. run.setCharactersLength(text->textLength() - fragment.characterOffset); ASSERT(run.charactersLength() >= run.length()); return run; }
TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFragment& fragment) const { ASSERT(style); ASSERT(textRenderer()); RenderText* text = textRenderer(); ASSERT(text); TextRun run(text->characters() + fragment.positionListOffset , fragment.length , false /* allowTabs */ , 0 /* xPos, only relevant with allowTabs=true */ , 0 /* padding, only relevant for justified text, not relevant for SVG */ , TextRun::AllowTrailingExpansion , direction() == RTL , m_dirOverride || style->visuallyOrdered() /* directionalOverride */); #if ENABLE(SVG_FONTS) RenderObject* parentRenderer = parent()->renderer(); ASSERT(parentRenderer); run.setReferencingRenderObject(parentRenderer); #endif // Disable any word/character rounding. run.disableRoundingHacks(); // We handle letter & word spacing ourselves. run.disableSpacing(); return run; }
static PangoLayout* getPangoLayoutForAtk(AtkText* textObject) { AccessibilityObject* coreObject = core(textObject); HostWindow* hostWindow = coreObject->document()->view()->hostWindow(); if (!hostWindow) return 0; PlatformPageClient webView = hostWindow->platformPageClient(); if (!webView) return 0; GString* str = g_string_new(NULL); AccessibilityRenderObject* accObject = static_cast<AccessibilityRenderObject*>(coreObject); if (!accObject) return 0; RenderText* renderText = toRenderText(accObject->renderer()); if (!renderText) return 0; // Create a string with the layout as it appears on the screen InlineTextBox* box = renderText->firstTextBox(); while (box) { gchar *text = convertUniCharToUTF8(renderText->characters(), renderText->textLength(), box->start(), box->end()); g_string_append(str, text); g_string_append(str, "\n"); box = box->nextTextBox(); } PangoLayout* layout = gtk_widget_create_pango_layout(static_cast<GtkWidget*>(webView), g_string_free(str, FALSE)); g_object_set_data_full(G_OBJECT(textObject), "webkit-accessible-pango-layout", layout, g_object_unref); return layout; }
static gchar* textForRenderer(RenderObject* renderer) { GString* resultText = g_string_new(0); if (!renderer) return g_string_free(resultText, FALSE); // For RenderBlocks, piece together the text from the RenderText objects they contain. for (RenderObject* object = renderer->firstChild(); object; object = object->nextSibling()) { if (object->isBR()) { g_string_append(resultText, "\n"); continue; } RenderText* renderText; if (object->isText()) renderText = toRenderText(object); else { // List item's markers will be treated in an special way // later on this function, so ignore them here. if (object->isReplaced() && !renderer->isListItem()) g_string_append_unichar(resultText, objectReplacementCharacter); // We need to check children, if any, to consider when // current object is not a text object but some of its // children are, in order not to miss those portions of // text by not properly handling those situations if (object->firstChild()) g_string_append(resultText, textForRenderer(object)); continue; } InlineTextBox* box = renderText ? renderText->firstTextBox() : 0; while (box) { // WebCore introduces line breaks in the text that do not reflect // the layout you see on the screen, replace them with spaces. String text = String(renderText->characters(), renderText->textLength()).replace("\n", " "); g_string_append(resultText, text.substring(box->start(), box->end() - box->start() + 1).utf8().data()); // Newline chars in the source result in separate text boxes, so check // before adding a newline in the layout. See bug 25415 comment #78. // If the next sibling is a BR, we'll add the newline when we examine that child. if (!box->nextOnLineExists() && !(object->nextSibling() && object->nextSibling()->isBR())) { // If there was a '\n' in the last position of the // current text box, it would have been converted to a // space in String::replace(), so remove it first. if (renderText->characters()[box->end()] == '\n') g_string_erase(resultText, resultText->len - 1, -1); g_string_append(resultText, "\n"); } box = box->nextTextBox(); } } // Insert the text of the marker for list item in the right place, if present if (renderer->isListItem()) { String markerText = toRenderListItem(renderer)->markerTextWithSuffix(); if (renderer->style()->direction() == LTR) g_string_prepend(resultText, markerText.utf8().data()); else g_string_append(resultText, markerText.utf8().data()); } return g_string_free(resultText, FALSE); }
static int placePositionedBoxesHorizontally(InlineFlowBox* flow, int x, int& leftPosition, int& rightPosition, int& leftAlign, int& rightAlign, bool& needsWordSpacing, int xPos, bool positioned) { int mn = INT_MAX; int mx = INT_MIN; int amn = INT_MAX; int amx = INT_MIN; int startx = x; bool seenPositionedElement = false; flow->setXPos(x); for (InlineBox* curr = flow->firstChild(); curr; curr = curr->nextOnLine()) { if (curr->object()->isText()) { mn = min(mn, x); amn = min(amn, x); InlineTextBox* text = static_cast<InlineTextBox*>(curr); RenderText* rt = static_cast<RenderText*>(text->object()); if (rt->textLength()) { if (needsWordSpacing && DeprecatedChar(rt->characters()[text->start()]).isSpace()) x += rt->style(flow->isFirstLineStyle())->font().wordSpacing(); needsWordSpacing = !DeprecatedChar(rt->characters()[text->end()]).isSpace(); } text->setXPos(x); x += text->width(); mx = max(mx, x); amx = max(amx, x); } else if (curr->object()->isInlineFlow()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); if (flow->object()->element()->hasTagName(aTag)) { x = placePositionedBoxesHorizontally(flow, x, mn, mx, amn, amx, needsWordSpacing, xPos, false); } else { SVGTextPositioningElement* text = static_cast<SVGTextPositioningElement*>(flow->object()->element()); x += (int)(text->dx()->getFirst().value()); if (text->x()->numberOfItems() > 0) x = (int)(text->x()->getFirst().value() - xPos); if (text->x()->numberOfItems() > 0 || text->y()->numberOfItems() > 0 || text->dx()->numberOfItems() > 0 || text->dy()->numberOfItems() > 0) { seenPositionedElement = true; needsWordSpacing = false; int ignoreX, ignoreY; x = placePositionedBoxesHorizontally(flow, x, mn, mx, ignoreX, ignoreY, needsWordSpacing, xPos, true); } else if (seenPositionedElement) { int ignoreX, ignoreY; x = placePositionedBoxesHorizontally(flow, x, mn, mx, ignoreX, ignoreY, needsWordSpacing, xPos, false); } else x = placePositionedBoxesHorizontally(flow, x, mn, mx, amn, amx, needsWordSpacing, xPos, false); } } } if (mn > mx) mn = mx = startx; if (amn > amx) amn = amx = startx; int width = mx - mn; flow->setWidth(width); int awidth = amx - amn; int dx = 0; if (positioned) { switch (flow->object()->style()->svgStyle()->textAnchor()) { case TA_MIDDLE: translateBox(flow, dx = -awidth / 2, 0, true); break; case TA_END: translateBox(flow, dx = -awidth, 0, true); break; case TA_START: default: break; } if (dx) { x += dx; mn += dx; mx += dx; } } leftPosition = min(leftPosition, mn); rightPosition = max(rightPosition, mx); leftAlign = min(leftAlign, amn); rightAlign = max(rightAlign, amx); return x; }