[webkit-changes] [WebKit/WebKit] 664af9: REGRESSION (261984 at main): Copied tables from some ...

Wenson Hsieh noreply at github.com
Tue Aug 8 14:32:19 PDT 2023


  Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 664af9c1e8d722f89b18f8783a1737d799a2fafc
      https://github.com/WebKit/WebKit/commit/664af9c1e8d722f89b18f8783a1737d799a2fafc
  Author: Wenson Hsieh <wenson_hsieh at apple.com>
  Date:   2023-08-08 (Tue, 08 Aug 2023)

  Changed paths:
    M Source/WebCore/PAL/pal/spi/ios/UIKitSPI.h
    M Source/WebCore/editing/cocoa/AttributedString.h
    M Source/WebCore/editing/cocoa/AttributedString.mm
    M Source/WebCore/editing/cocoa/HTMLConverter.mm
    M Source/WebCore/platform/cocoa/MIMETypeRegistryCocoa.mm
    M Source/WebKit/Shared/Cocoa/WebCoreArgumentCodersCocoa.serialization.in
    M Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewGetContents.mm

  Log Message:
  -----------
  REGRESSION (261984 at main): Copied tables from some web pages don't properly paste into Numbers
https://bugs.webkit.org/show_bug.cgi?id=259928
rdar://112030767

Reviewed by Megan Gardner.

When copying a table in Quip and pasting into the Numbers app, tables are programmatically written
to the pasteboard as HTML; upon paste, UIFoundation uses `nsattributedstringagent` to convert this
pasted markup into an `NSAttributedString`, by loading the markup in a `WKWebView` and asking it to
`-_getContentsAsAttributedStringWithCompletionHandler:`. This exercises the `HTMLConverter` codepath
in WebCore, which implements the correct logic for representing tables and lists in the markup as
`-textBlocks` and `-textLists`, respectively, on `NSParagraphStyle`; for tables, we list multiple
`NSTextTableBlock`s that all point to the same `NSTextTable` object. For instance, two adjacent
cells in the same table would be represented as:

```
"NSParagraphStyle" => {
    textBlocks => [ NSTextTableBlock 0x6000006e7100, table=<NSTextTable 0x6000003f27d0>, {0, 0} ],
    …
}
"NSParagraphStyle" => {
    textBlocks => [ NSTextTableBlock 0x6000006e6d80, table=<NSTextTable 0x6000003f27d0>, {0, 1} ],
    …
}
```

Similarly, lists are represented by having multiple paragraph styles with the same `NSTextList`s.
Two adjacent items in the same list, for instance, will have paragraph styles whose `-textLists`
array contains the exact same list (i.e. equal pointers):

```
"NSParagraphStyle" => {
    textLists => [ NSTextList 0x600002676400 format <{disc}> ],
    …
}
"NSParagraphStyle" => {
    textLists => [ NSTextList 0x600002676400 format <{disc}> ],
    …
}
```

Prior to the changes in 261984 at main, we used a single `NSKeyedArchiver`/`NSKeyedUnarchiver` to
encode/decode an `NSAttributedString` when sending this data from the web process to the UI process
for writing to the pasteboard. This meant that Foundation's internal object caching mechanism in the
keyed archiver would ensure that multiple `NSParagraphStyle` instances that all reference the same
`NSTextList` or `NSTextTable` upon encoding would still reference the same list or table upon
decoding, thereby preserving the table/list structure when writing to the pasteboard.

However, after 261984 at main, we now use a different keyed (un)archiver when encoding/decoding each
individual attribute; as a result, different `NSParagraphStyle` instances that reference the same
`NSTextList` or `NSTextTable` no longer correspond to the same object in the archiver's backing map.
This means that in the two above examples, we'd end up with two 2x1 tables (each with only 1 cell
populated), and two single-item lists, respectively.

To fix this, we add some logic to plumb unique identifiers corresponding to tables or lists for each
`NSTextBlock` or `NSTextList` in `-[NSParagraphStyle textBlocks]` and `-[NSParagraph textLists]`,
which are propagated along with the rest of the attributes upon encoding. When decoding, we use
these unique identifiers to ensure that all paragraph styles that previously referenced the same
table or list will continue to do so after decoding.

Tests:  WKWebView.AttributedStringFromTable
        WKWebView.AttributedStringFromList

* Source/WebCore/PAL/pal/spi/ios/UIKitSPI.h:

Move various UIKit SPI and IPI declarations out of the implementation file in `HTMLConverter.mm`
and into `UIKitSPI.h` instead, so that these declarations can be used in both `AttributedString.mm`
and `HTMLConverter.mm`.

* Source/WebCore/editing/cocoa/AttributedString.h:

Instead of encoding a single `RetainPtr<NSParagraphStyle>`, send a struct containing an
`RetainPtr<NSParagraphStyle>`, a list of `TextTableID` representing each text block, and a list of
`TextListID`. Note that `tableIDs` is a list of optional identifiers, since a `textBlock` may not
necessarily correspond to a table cell, in which case we use represent it via `nullopt`. `textLists`
doesn't have this same constraint since each entry corresponds directly to an `NSTextList`.

* Source/WebCore/editing/cocoa/AttributedString.mm:
(WebCore::reconstructStyle):

Add a helper method to take `HashMap`s of tables and lists by ID, and (only if necessary) create a
copy of the decoded `NSParagraphStyle` whose referenced tables and lists match those that were
previously referenced when decoding earlier parts of the attributed string.

(WebCore::toNSObject):
(WebCore::toNSDictionary):

Maintain maps of tables and lists by unique ID over the whole lifetime of decoding the string.

(WebCore::AttributedString::documentAttributesAsNSDictionary const):
(WebCore::AttributedString::nsAttributedString const):
(WebCore::extractListIDs):
(WebCore::extractTableIDs):
(WebCore::extractValue):
(WebCore::extractDictionary):
(WebCore::AttributedString::fromNSAttributedStringAndDocumentAttributes):

Implement the opposite half of the above logic, by collecting identical `NSTextList`s and
`NSTextTable`s that are referenced by `NSParagraphStyle`s during encoding. This allows us to build a
list of unique IDs that correspond to each table or list, which we send over IPC and use during
decoding to preserve references to the same objects when deserializing paragraph styles.

* Source/WebCore/editing/cocoa/HTMLConverter.mm:
* Source/WebCore/platform/cocoa/MIMETypeRegistryCocoa.mm:
(WebCore::extensionsForMIMETypeMap):

Drive-by fix: suppress a new deprecation warning.

* Source/WebKit/Shared/Cocoa/WebCoreArgumentCodersCocoa.serialization.in:
* Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewGetContents.mm:
(-[WKWebView _contentsAsAttributedString]):

Add a couple of API tests to exercise attributed string conversion for tables and lists.
Importantly, these tests verify that table/list structure is preserved in the decoded string.

Canonical link: https://commits.webkit.org/266700@main




More information about the webkit-changes mailing list