Changeset 285862 in webkit
- Timestamp:
- Nov 16, 2021, 8:37:05 AM (5 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
-
ChangeLog (modified) (1 diff)
-
dom/ImageOverlay.cpp (modified) (11 diffs)
-
html/shadow/imageOverlay.css (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r285861 r285862 1 2021-11-16 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Add support for injecting and rendering text recognition blocks 4 https://bugs.webkit.org/show_bug.cgi?id=233044 5 6 Reviewed by Aditya Keerthi. 7 8 Adds support for rendering text recognition blocks, which appear as opaque div elements over images. See below 9 for more details; no change in behavior, since nothing currently generates TextRecognitionBlockData yet. 10 11 * dom/ImageOverlay.cpp: 12 (WebCore::ImageOverlay::imageOverlayDataDetectorClass): 13 (WebCore::ImageOverlay::imageOverlayBlockClass): 14 (WebCore::ImageOverlay::isDataDetectorResult): 15 (WebCore::ImageOverlay::updateSubtree): 16 17 Add support for creating text recognition block containers in the UA shadow root, if needed. 18 19 (WebCore::ImageOverlay::fitElementToQuad): 20 21 Factor out logic to adjust the width, height and transforms on a given element to fit the given quad, and return 22 rotated bounding rect info; we use this in three places below. 23 24 (WebCore::ImageOverlay::updateWithTextRecognitionResult): 25 26 Add support for adjusting the size and transforms on each of the block containers created above. 27 28 (WebCore::ImageOverlay::imageOverlayDataDetectorClassName): Deleted. 29 30 Rename this to just `imageOverlayDataDetectorClass()` to match the other static helper functions. 31 32 * html/shadow/imageOverlay.css: 33 (div#image-overlay): 34 (div.image-overlay-line): 35 (div.image-overlay-line, div.image-overlay-block): 36 (div.image-overlay-block): 37 (div.image-overlay-line, .image-overlay-text): 38 1 39 2021-11-16 Andreu Botella <andreu@andreubotella.com> 2 40 -
trunk/Source/WebCore/dom/ImageOverlay.cpp
r285725 r285862 64 64 } 65 65 66 static const AtomString& imageOverlayDataDetectorClass Name()66 static const AtomString& imageOverlayDataDetectorClass() 67 67 { 68 68 static MainThreadNeverDestroyed<const AtomString> className("image-overlay-data-detector-result", AtomString::ConstructFromLiteral); … … 81 81 { 82 82 static MainThreadNeverDestroyed<const AtomString> className("image-overlay-text", AtomString::ConstructFromLiteral); 83 return className; 84 } 85 86 static const AtomString& imageOverlayBlockClass() 87 { 88 static MainThreadNeverDestroyed<const AtomString> className("image-overlay-block", AtomString::ConstructFromLiteral); 83 89 return className; 84 90 } … … 107 113 bool isDataDetectorResult(const HTMLElement& element) 108 114 { 109 return imageOverlayHost(element) && element.hasClass() && element.classNames().contains(imageOverlayDataDetectorClass Name());115 return imageOverlayHost(element) && element.hasClass() && element.classNames().contains(imageOverlayDataDetectorClass()); 110 116 } 111 117 … … 192 198 Vector<LineElements> lines; 193 199 Vector<Ref<HTMLDivElement>> dataDetectors; 200 Vector<Ref<HTMLDivElement>> blocks; 194 201 }; 195 202 … … 230 237 231 238 if (elements.root) { 232 for (auto& lineOrDataDetector: childrenOfType<HTMLDivElement>(*elements.root)) {233 if (! lineOrDataDetector.hasClass())239 for (auto& childElement : childrenOfType<HTMLDivElement>(*elements.root)) { 240 if (!childElement.hasClass()) 234 241 continue; 235 242 236 if (lineOrDataDetector.classList().contains(imageOverlayLineClass())) { 237 LineElements lineElements { lineOrDataDetector, { } }; 238 for (auto& text : childrenOfType<HTMLDivElement>(lineOrDataDetector)) 239 lineElements.children.append(text); 240 elements.lines.append(WTFMove(lineElements)); 241 } else if (lineOrDataDetector.classList().contains(imageOverlayDataDetectorClassName())) 242 elements.dataDetectors.append(lineOrDataDetector); 243 auto& classes = childElement.classList(); 244 if (classes.contains(imageOverlayDataDetectorClass())) { 245 elements.dataDetectors.append(childElement); 246 continue; 247 } 248 249 if (classes.contains(imageOverlayBlockClass())) { 250 elements.blocks.append(childElement); 251 continue; 252 } 253 254 ASSERT(classes.contains(imageOverlayLineClass())); 255 LineElements lineElements { childElement, { } }; 256 for (auto& text : childrenOfType<HTMLDivElement>(childElement)) 257 lineElements.children.append(text); 258 elements.lines.append(WTFMove(lineElements)); 243 259 } 244 260 … … 248 264 249 265 if (result.lines.size() != elements.lines.size()) 266 return false; 267 268 if (result.blocks.size() != elements.blocks.size()) 250 269 return false; 251 270 … … 260 279 return false; 261 280 } 281 } 282 283 for (size_t index = 0; index < result.blocks.size(); ++index) { 284 if (result.blocks[index].text != elements.blocks[index]->textContent()) 285 return false; 262 286 } 263 287 … … 311 335 for (auto& dataDetector : result.dataDetectors) { 312 336 auto dataDetectorContainer = DataDetection::createElementForImageOverlay(document.get(), dataDetector); 313 dataDetectorContainer->classList().add(imageOverlayDataDetectorClass Name());337 dataDetectorContainer->classList().add(imageOverlayDataDetectorClass()); 314 338 rootContainer->appendChild(dataDetectorContainer); 315 339 elements.dataDetectors.uncheckedAppend(WTFMove(dataDetectorContainer)); 316 340 } 317 341 #endif // ENABLE(DATA_DETECTION) 342 343 elements.blocks.reserveInitialCapacity(result.blocks.size()); 344 for (auto& block : result.blocks) { 345 auto blockContainer = HTMLDivElement::create(document.get()); 346 blockContainer->classList().add(imageOverlayBlockClass()); 347 rootContainer->appendChild(blockContainer); 348 blockContainer->appendChild(Text::create(document.get(), makeString('\n', block.text))); 349 elements.blocks.uncheckedAppend(WTFMove(blockContainer)); 350 } 318 351 319 352 if (document->quirks().needsToForceUserSelectWhenInstallingImageOverlay()) … … 329 362 330 363 return elements; 364 } 365 366 static RotatedRect fitElementToQuad(HTMLElement& container, const FloatQuad& quad) 367 { 368 auto bounds = rotatedBoundingRectWithMinimumAngleOfRotation(quad, 0.01); 369 container.setInlineStyleProperty(CSSPropertyWidth, bounds.size.width(), CSSUnitType::CSS_PX); 370 container.setInlineStyleProperty(CSSPropertyHeight, bounds.size.height(), CSSUnitType::CSS_PX); 371 container.setInlineStyleProperty(CSSPropertyTransform, makeString( 372 "translate("_s, 373 std::round(bounds.center.x() - (bounds.size.width() / 2)), "px, "_s, 374 std::round(bounds.center.y() - (bounds.size.height() / 2)), "px) "_s, 375 bounds.angleInRadians ? makeString("rotate("_s, bounds.angleInRadians, "rad) "_s) : emptyString() 376 )); 377 return bounds; 331 378 } 332 379 … … 363 410 continue; 364 411 365 auto lineBounds = rotatedBoundingRectWithMinimumAngleOfRotation(lineQuad, 0.01); 366 lineContainer->setInlineStyleProperty(CSSPropertyWidth, lineBounds.size.width(), CSSUnitType::CSS_PX); 367 lineContainer->setInlineStyleProperty(CSSPropertyHeight, lineBounds.size.height(), CSSUnitType::CSS_PX); 368 lineContainer->setInlineStyleProperty(CSSPropertyTransform, makeString( 369 "translate("_s, 370 std::round(lineBounds.center.x() - (lineBounds.size.width() / 2)), "px, "_s, 371 std::round(lineBounds.center.y() - (lineBounds.size.height() / 2)), "px) "_s, 372 lineBounds.angleInRadians ? makeString("rotate("_s, lineBounds.angleInRadians, "rad) "_s) : emptyString() 373 )); 374 412 auto lineBounds = fitElementToQuad(lineContainer.get(), lineQuad); 375 413 auto offsetAlongHorizontalAxis = [&](const FloatPoint& quadPoint1, const FloatPoint& quadPoint2) { 376 414 auto intervalLength = lineBounds.size.width(); … … 452 490 continue; 453 491 492 auto firstQuad = dataDetector.normalizedQuads.first(); 493 if (firstQuad.isEmpty()) 494 continue; 495 454 496 // FIXME: We should come up with a way to coalesce the bounding quads into one or more rotated rects with the same angle of rotation. 455 auto targetQuad = convertToContainerCoordinates(dataDetector.normalizedQuads.first()); 456 auto targetBounds = rotatedBoundingRectWithMinimumAngleOfRotation(targetQuad, 0.01); 457 dataDetectorContainer->setInlineStyleProperty(CSSPropertyWidth, targetBounds.size.width(), CSSUnitType::CSS_PX); 458 dataDetectorContainer->setInlineStyleProperty(CSSPropertyHeight, targetBounds.size.height(), CSSUnitType::CSS_PX); 459 dataDetectorContainer->setInlineStyleProperty(CSSPropertyTransform, makeString( 460 "translate("_s, 461 std::round(targetBounds.center.x() - (targetBounds.size.width() / 2)), "px, "_s, 462 std::round(targetBounds.center.y() - (targetBounds.size.height() / 2)), "px) "_s, 463 targetBounds.angleInRadians ? makeString("rotate("_s, targetBounds.angleInRadians, "rad) "_s) : emptyString() 464 )); 497 fitElementToQuad(dataDetectorContainer.get(), convertToContainerCoordinates(firstQuad)); 465 498 } 466 499 #endif // ENABLE(DATA_DETECTION) 500 501 ASSERT(result.blocks.size() == elements.blocks.size()); 502 for (size_t index = 0; index < result.blocks.size(); ++index) { 503 auto& block = result.blocks[index]; 504 if (block.normalizedQuad.isEmpty()) 505 continue; 506 507 auto blockContainer = elements.blocks[index]; 508 auto bounds = fitElementToQuad(blockContainer.get(), convertToContainerCoordinates(block.normalizedQuad)); 509 // FIXME: We'll need a smarter algorithm here that chooses the largest font size for the container without 510 // vertically overflowing the container. 511 blockContainer->setInlineStyleProperty(CSSPropertyFontSize, std::round(0.8 * bounds.size.height()), CSSUnitType::CSS_PX); 512 } 467 513 468 514 if (RefPtr frame = document->frame()) -
trunk/Source/WebCore/html/shadow/imageOverlay.css
r282769 r285862 31 31 text-shadow: none; 32 32 text-align: center; 33 font-family: system-ui; 34 } 35 36 div.image-overlay-line { 33 37 white-space: nowrap; 34 38 line-height: 100%; 35 font-family: system-ui;36 39 font-size: 1024px; /* This large font size is chosen to minimize gaps when painting selection quads. */ 37 40 } 38 41 39 div.image-overlay-line, .image-overlay-text { 42 div.image-overlay-line, div.image-overlay-block { 43 pointer-events: auto; 44 } 45 46 div.image-overlay-block { 47 background-color: rgba(255, 255, 255, 0.75); 48 border-radius: calc(clamp(2px, 0.1em, 12px)); 49 box-shadow: rgba(100, 100, 100, 0.2) 3px 4px 8px 4px; 50 color: rgb(90, 90, 90); 51 font-weight: bold; 52 display: flex; 53 justify-content: center; 54 align-content: center; 55 flex-direction: column; 56 -webkit-backdrop-filter: blur(8px); 57 } 58 59 div.image-overlay-line, .image-overlay-text, div.image-overlay-block { 40 60 position: absolute; 41 61 overflow: hidden; 42 }43 44 div.image-overlay-line {45 pointer-events: auto;46 62 } 47 63
Note:
See TracChangeset
for help on using the changeset viewer.