Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 664af9c1e8d722f89b18f8783a1737d799a2fafc
      
https://github.com/WebKit/WebKit/commit/664af9c1e8d722f89b18f8783a1737d799a2fafc
  Author: Wenson Hsieh <wenson_hs...@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@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@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@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


_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to