Diff
Modified: trunk/Source/WebCore/ChangeLog (285118 => 285119)
--- trunk/Source/WebCore/ChangeLog 2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/ChangeLog 2021-11-01 19:22:20 UTC (rev 285119)
@@ -1,3 +1,23 @@
+2021-11-01 Alan Bujtas <[email protected]>
+
+ [LFC][IFC] Start using ubidi to find bidi boundaries
+ https://bugs.webkit.org/show_bug.cgi?id=232552
+
+ Reviewed by Antti Koivisto.
+
+ In this patch, we start using ubidi to find the bidi boundaries in the paragraph content.
+ We also set the bidi levels on the associated inline item range. Later we'll be using these levels
+ to compute the visual order (after line breaking).
+ (see breakAndComputeBidiLevels for details)
+
+ * layout/formattingContexts/inline/InlineItem.h:
+ (WebCore::Layout::InlineItem::setBidiLevel):
+ * layout/formattingContexts/inline/InlineItemsBuilder.cpp:
+ (WebCore::Layout::InlineItemsBuilder::breakAndComputeBidiLevels):
+ * layout/formattingContexts/inline/InlineTextItem.cpp:
+ (WebCore::Layout::InlineTextItem::splitAt):
+ * layout/formattingContexts/inline/InlineTextItem.h:
+
2021-11-01 Chris Dumez <[email protected]>
Crash under HIDDevice::HIDDevice()
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineItem.h (285118 => 285119)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItem.h 2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItem.h 2021-11-01 19:22:20 UTC (rev 285119)
@@ -34,6 +34,8 @@
namespace WebCore {
namespace Layout {
+class InlineItemsBuilder;
+
class InlineItem {
public:
enum class Type : uint8_t {
@@ -65,6 +67,10 @@
bool isInlineBoxEnd() const { return type() == Type::InlineBoxEnd; }
private:
+ friend class InlineItemsBuilder;
+
+ void setBidiLevel(UBiDiLevel bidiLevel) { m_bidiLevel = bidiLevel; }
+
const Box* m_layoutBox { nullptr };
Type m_type { };
UBiDiLevel m_bidiLevel { UBIDI_DEFAULT_LTR };
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp (285118 => 285119)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp 2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp 2021-11-01 19:22:20 UTC (rev 285119)
@@ -29,6 +29,7 @@
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "InlineSoftLineBreakItem.h"
+#include <wtf/Scope.h>
namespace WebCore {
namespace Layout {
@@ -83,7 +84,7 @@
{
InlineItems inlineItems;
collectInlineItems(inlineItems);
- breakInlineItemsAtBidiBoundaries(inlineItems);
+ breakAndComputeBidiLevels(inlineItems);
return inlineItems;
}
@@ -133,9 +134,74 @@
}
}
-void InlineItemsBuilder::breakInlineItemsAtBidiBoundaries(InlineItems&)
+void InlineItemsBuilder::breakAndComputeBidiLevels(InlineItems& inlineItems)
{
- // FIXME: Use ubidi to split the content at bidi boundaries.
+ if (m_paragraphContentBuilder.isEmpty())
+ return;
+ ASSERT(!inlineItems.isEmpty());
+
+ // 1. Setup the bidi boundary loop by calling ubidi_setPara with the paragraph text.
+ // 2. Call ubidi_getLogicalRun to advance to the next bidi boundary until we hit the end of the content.
+ // 3. Set the computed bidi level on the associated inline items. Split them as needed.
+ UBiDi* ubidi = ubidi_open();
+
+ auto closeUBiDiOnExit = makeScopeExit([&] {
+ ubidi_close(ubidi);
+ });
+
+ UBiDiLevel bidiLevel = UBIDI_DEFAULT_LTR;
+ bool useHeuristicBaseDirection = root().style().unicodeBidi() == EUnicodeBidi::Plaintext;
+ if (!useHeuristicBaseDirection)
+ bidiLevel = root().style().isLeftToRightDirection() ? UBIDI_LTR : UBIDI_RTL;
+
+ UErrorCode error = U_ZERO_ERROR;
+ ubidi_setPara(ubidi, m_paragraphContentBuilder.characters16(), m_paragraphContentBuilder.length(), bidiLevel, nullptr, &error);
+ if (U_FAILURE(error)) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ size_t currentInlineItemIndex = 0;
+ for (size_t currentPosition = 0; currentPosition < m_paragraphContentBuilder.length();) {
+ UBiDiLevel level;
+ int32_t endPosition = currentPosition;
+ ubidi_getLogicalRun(ubidi, currentPosition, &endPosition, &level);
+
+ auto setBidiLevelOnRange = [&] {
+ // We should always have inline item(s) associated with a bidi range.
+ ASSERT(currentInlineItemIndex < inlineItems.size());
+
+ while (currentInlineItemIndex < inlineItems.size()) {
+ auto& inlineItem = inlineItems[currentInlineItemIndex];
+ if (!inlineItem.isText()) {
+ // FIXME: This fails with multiple inline boxes as they don't advance position.
+ inlineItem.setBidiLevel(level);
+ ++currentInlineItemIndex;
+ continue;
+ }
+ auto& inlineTextItem = downcast<InlineTextItem>(inlineItem);
+ inlineTextItem.setBidiLevel(level);
+
+ auto inlineTextItemEnd = inlineTextItem.end();
+ auto bidiEnd = endPosition - m_contentOffsetMap.get(&inlineTextItem.layoutBox());
+ if (bidiEnd == inlineTextItemEnd) {
+ ++currentInlineItemIndex;
+ break;
+ }
+ if (bidiEnd < inlineTextItemEnd) {
+ if (currentInlineItemIndex == inlineItems.size() - 1)
+ inlineItems.append(inlineTextItem.splitAt(bidiEnd));
+ else
+ inlineItems.insert(currentInlineItemIndex + 1, inlineTextItem.splitAt(bidiEnd));
+ ++currentInlineItemIndex;
+ break;
+ }
+ ++currentInlineItemIndex;
+ }
+ };
+ setBidiLevelOnRange();
+ currentPosition = endPosition;
+ }
}
void InlineItemsBuilder::handleTextContent(const InlineTextBox& inlineTextBox, InlineItems& inlineItems)
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h (285118 => 285119)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h 2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h 2021-11-01 19:22:20 UTC (rev 285119)
@@ -42,7 +42,7 @@
private:
void collectInlineItems(InlineItems&);
- void breakInlineItemsAtBidiBoundaries(InlineItems&);
+ void breakAndComputeBidiLevels(InlineItems&);
void handleTextContent(const InlineTextBox&, InlineItems&);
void handleInlineBoxStart(const Box&, InlineItems&);
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp (285118 => 285119)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp 2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp 2021-11-01 19:22:20 UTC (rev 285119)
@@ -71,6 +71,15 @@
return { inlineTextBox(), end() - length, length, bidiLevel(), hasTrailingSoftHyphen(), isWordSeparator(), width, m_textItemType };
}
+InlineTextItem InlineTextItem::splitAt(size_t position)
+{
+ RELEASE_ASSERT(length() > 1);
+ RELEASE_ASSERT(position > start() && position < end());
+ auto rightSide = right(end() - position, { });
+ m_length = length() - rightSide.length();
+ return rightSide;
+}
+
bool InlineTextItem::isZeroWidthSpaceSeparator() const
{
// FIXME: We should check for more zero width content and not just U+200B.
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h (285118 => 285119)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h 2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h 2021-11-01 19:22:20 UTC (rev 285119)
@@ -33,6 +33,8 @@
namespace WebCore {
namespace Layout {
+class InlineItemsBuilder;
+
using InlineItems = Vector<InlineItem>;
class InlineTextItem : public InlineItem {
@@ -59,8 +61,11 @@
static bool shouldPreserveSpacesAndTabs(const InlineTextItem&);
private:
+ friend class InlineItemsBuilder;
using InlineItem::TextItemType;
+ InlineTextItem splitAt(size_t position);
+
InlineTextItem(const InlineTextBox&, unsigned start, unsigned length, UBiDiLevel, bool hasTrailingSoftHyphen, bool isWordSeparator, std::optional<InlineLayoutUnit> width, TextItemType);
explicit InlineTextItem(const InlineTextBox&, UBiDiLevel);
};