Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 664af9c1e8d722f89b18f8783a1737d799a2fafc
https://github.com/WebKit/WebKit/commit/664af9c1e8d722f89b18f8783a1737d799a2fafc
Author: Wenson Hsieh <[email protected]>
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
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes