Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 { | 227 { |
| 228 ASSERT(isPotentialClusterRoot(block)); | 228 ASSERT(isPotentialClusterRoot(block)); |
| 229 return isIndependentDescendant(block) || mightBeWiderOrNarrowerDescendant(bl ock) || block->isTable(); | 229 return isIndependentDescendant(block) || mightBeWiderOrNarrowerDescendant(bl ock) || block->isTable(); |
| 230 } | 230 } |
| 231 | 231 |
| 232 FastTextAutosizer::FastTextAutosizer(const Document* document) | 232 FastTextAutosizer::FastTextAutosizer(const Document* document) |
| 233 : m_document(document) | 233 : m_document(document) |
| 234 , m_frameWidth(0) | 234 , m_frameWidth(0) |
| 235 , m_layoutWidth(0) | 235 , m_layoutWidth(0) |
| 236 , m_baseMultiplier(0) | 236 , m_baseMultiplier(0) |
| 237 , m_pageAutosizingStatus(PageAutosizingStatusUnknown) | 237 , m_pageNeedsAutosizing(false) |
| 238 , m_previouslyAutosized(false) | |
| 239 , m_updatePageInfoDeferred(false) | |
| 238 , m_firstBlock(0) | 240 , m_firstBlock(0) |
| 239 #ifndef NDEBUG | 241 #ifndef NDEBUG |
| 240 , m_renderViewInfoPrepared(false) | |
| 241 , m_blocksThatHaveBegunLayout() | 242 , m_blocksThatHaveBegunLayout() |
| 242 #endif | 243 #endif |
| 243 , m_superclusters() | 244 , m_superclusters() |
| 244 , m_clusterStack() | 245 , m_clusterStack() |
| 245 , m_fingerprintMapper() | 246 , m_fingerprintMapper() |
| 246 { | 247 { |
| 247 } | 248 } |
| 248 | 249 |
| 249 void FastTextAutosizer::record(const RenderBlock* block) | 250 void FastTextAutosizer::record(const RenderBlock* block) |
| 250 { | 251 { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 #ifndef NDEBUG | 284 #ifndef NDEBUG |
| 284 m_blocksThatHaveBegunLayout.add(block); | 285 m_blocksThatHaveBegunLayout.add(block); |
| 285 #endif | 286 #endif |
| 286 if (Cluster* cluster = maybeCreateCluster(block)) | 287 if (Cluster* cluster = maybeCreateCluster(block)) |
| 287 m_clusterStack.append(adoptPtr(cluster)); | 288 m_clusterStack.append(adoptPtr(cluster)); |
| 288 } | 289 } |
| 289 } | 290 } |
| 290 | 291 |
| 291 void FastTextAutosizer::beginLayout(RenderBlock* block) | 292 void FastTextAutosizer::beginLayout(RenderBlock* block) |
| 292 { | 293 { |
| 293 ASSERT(enabled() && m_pageAutosizingStatus == PageNeedsAutosizing); | 294 ASSERT(enabled() && m_pageNeedsAutosizing); |
| 294 #ifndef NDEBUG | 295 #ifndef NDEBUG |
| 295 m_blocksThatHaveBegunLayout.add(block); | 296 m_blocksThatHaveBegunLayout.add(block); |
| 296 #endif | 297 #endif |
| 297 | 298 |
| 298 if (!m_firstBlock) { | 299 if (!m_firstBlock) { |
| 299 m_firstBlock = block; | 300 m_firstBlock = block; |
| 300 prepareClusterStack(block->parent()); | 301 prepareClusterStack(block->parent()); |
| 301 } else if (block == currentCluster()->m_root) { | 302 } else if (block == currentCluster()->m_root) { |
| 302 // Ignore beginLayout on the same block twice. | 303 // Ignore beginLayout on the same block twice. |
| 303 // This can happen with paginated overflow. | 304 // This can happen with paginated overflow. |
| 304 return; | 305 return; |
| 305 } | 306 } |
| 306 | 307 |
| 307 if (Cluster* cluster = maybeCreateCluster(block)) { | 308 if (Cluster* cluster = maybeCreateCluster(block)) { |
| 308 m_clusterStack.append(adoptPtr(cluster)); | 309 m_clusterStack.append(adoptPtr(cluster)); |
| 309 if (block->isTable()) | 310 if (block->isTable()) |
| 310 inflateTable(toRenderTable(block)); | 311 inflateTable(toRenderTable(block)); |
| 311 } | 312 } |
| 312 | 313 |
| 313 if (block->childrenInline() && block->firstChild()) | 314 if (block->childrenInline() && block->firstChild()) |
| 314 inflate(block); | 315 inflate(block); |
| 315 } | 316 } |
| 316 | 317 |
| 317 void FastTextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMark er* listItemMarker) | 318 void FastTextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMark er* listItemMarker) |
| 318 { | 319 { |
| 319 if (!enabled() || m_pageAutosizingStatus != PageNeedsAutosizing) | 320 if (!enabled() || !m_pageNeedsAutosizing) |
| 320 return; | 321 return; |
| 321 ASSERT(listItem && listItemMarker); | 322 ASSERT(listItem && listItemMarker); |
| 322 #ifndef NDEBUG | 323 #ifndef NDEBUG |
| 323 m_blocksThatHaveBegunLayout.add(listItem); | 324 m_blocksThatHaveBegunLayout.add(listItem); |
| 324 #endif | 325 #endif |
| 325 // Force the LI to be inside the DBCAT when computing the multiplier. | 326 // Force the LI to be inside the DBCAT when computing the multiplier. |
| 326 // This guarantees that the DBCAT has entered layout, so we can ask for its width. | 327 // This guarantees that the DBCAT has entered layout, so we can ask for its width. |
| 327 // It also makes sense because the list marker is autosized like a text node . | 328 // It also makes sense because the list marker is autosized like a text node . |
| 328 float multiplier = clusterMultiplier(currentCluster()); | 329 float multiplier = clusterMultiplier(currentCluster()); |
| 329 | 330 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 } | 373 } |
| 373 } | 374 } |
| 374 } | 375 } |
| 375 } | 376 } |
| 376 } | 377 } |
| 377 } | 378 } |
| 378 } | 379 } |
| 379 | 380 |
| 380 void FastTextAutosizer::endLayout(RenderBlock* block) | 381 void FastTextAutosizer::endLayout(RenderBlock* block) |
| 381 { | 382 { |
| 382 ASSERT(enabled() && m_pageAutosizingStatus == PageNeedsAutosizing); | 383 ASSERT(enabled() && m_pageNeedsAutosizing); |
| 383 | 384 |
| 384 if (block == m_firstBlock) { | 385 if (block == m_firstBlock) { |
| 385 m_firstBlock = 0; | 386 m_firstBlock = 0; |
| 386 m_pageAutosizingStatus = PageAutosizingStatusUnknown; | |
| 387 m_clusterStack.clear(); | 387 m_clusterStack.clear(); |
| 388 m_superclusters.clear(); | 388 m_superclusters.clear(); |
| 389 #ifndef NDEBUG | 389 #ifndef NDEBUG |
| 390 m_blocksThatHaveBegunLayout.clear(); | 390 m_blocksThatHaveBegunLayout.clear(); |
| 391 #endif | 391 #endif |
| 392 } else if (currentCluster()->m_root == block) { | 392 } else if (currentCluster()->m_root == block) { |
| 393 m_clusterStack.removeLast(); | 393 m_clusterStack.removeLast(); |
| 394 } | 394 } |
| 395 } | 395 } |
| 396 | 396 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 418 } | 418 } |
| 419 | 419 |
| 420 bool FastTextAutosizer::enabled() | 420 bool FastTextAutosizer::enabled() |
| 421 { | 421 { |
| 422 if (!m_document->settings() || !m_document->page() || m_document->printing() ) | 422 if (!m_document->settings() || !m_document->page() || m_document->printing() ) |
| 423 return false; | 423 return false; |
| 424 | 424 |
| 425 return m_document->settings()->textAutosizingEnabled(); | 425 return m_document->settings()->textAutosizingEnabled(); |
| 426 } | 426 } |
| 427 | 427 |
| 428 void FastTextAutosizer::updateRenderViewInfo() | 428 void FastTextAutosizer::updatePageInfoInAllFrames() |
| 429 { | 429 { |
| 430 if (!enabled()) | |
| 431 return; | |
| 432 | |
| 433 ASSERT(m_document->frame()->isMainFrame()); | |
| 434 | |
| 435 for (LocalFrame* frame = m_document->frame(); frame; frame = frame->tree().t raverseNext()) { | |
| 436 if (FastTextAutosizer* textAutosizer = frame->document()->fastTextAutosi zer()) | |
| 437 textAutosizer->updatePageInfo(); | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 void FastTextAutosizer::updatePageInfo() | |
| 442 { | |
| 443 if (!enabled() || m_updatePageInfoDeferred) | |
| 444 return; | |
| 445 | |
| 446 int previousFrameWidth = m_frameWidth; | |
| 447 int previousLayoutWidth = m_layoutWidth; | |
| 448 float previousBaseMultiplier = m_baseMultiplier; | |
| 449 | |
| 430 RenderView* renderView = toRenderView(m_document->renderer()); | 450 RenderView* renderView = toRenderView(m_document->renderer()); |
| 431 bool horizontalWritingMode = isHorizontalWritingMode(renderView->style()->wr itingMode()); | 451 bool horizontalWritingMode = isHorizontalWritingMode(renderView->style()->wr itingMode()); |
| 432 | 452 |
| 433 LocalFrame* mainFrame = m_document->page()->mainFrame(); | 453 LocalFrame* mainFrame = m_document->page()->mainFrame(); |
| 434 IntSize frameSize = m_document->settings()->textAutosizingWindowSizeOverride (); | 454 IntSize frameSize = m_document->settings()->textAutosizingWindowSizeOverride (); |
| 435 if (frameSize.isEmpty()) | 455 if (frameSize.isEmpty()) |
| 436 frameSize = mainFrame->view()->unscaledVisibleContentSize(IncludeScrollb ars); | 456 frameSize = mainFrame->view()->unscaledVisibleContentSize(IncludeScrollb ars); |
| 437 m_frameWidth = horizontalWritingMode ? frameSize.width() : frameSize.height( ); | 457 m_frameWidth = horizontalWritingMode ? frameSize.width() : frameSize.height( ); |
| 438 | 458 |
| 439 IntSize layoutSize = m_document->page()->mainFrame()->view()->layoutSize(); | 459 IntSize layoutSize = m_document->page()->mainFrame()->view()->layoutSize(); |
| 440 m_layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize.heig ht(); | 460 m_layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize.heig ht(); |
| 441 | 461 |
| 442 // Compute the base font scale multiplier based on device and accessibility settings. | 462 // Compute the base font scale multiplier based on device and accessibility settings. |
| 443 m_baseMultiplier = m_document->settings()->accessibilityFontScaleFactor(); | 463 m_baseMultiplier = m_document->settings()->accessibilityFontScaleFactor(); |
| 444 // If the page has a meta viewport or @viewport, don't apply the device scal e adjustment. | 464 // If the page has a meta viewport or @viewport, don't apply the device scal e adjustment. |
| 445 const ViewportDescription& viewportDescription = m_document->page()->mainFra me()->document()->viewportDescription(); | 465 const ViewportDescription& viewportDescription = m_document->page()->mainFra me()->document()->viewportDescription(); |
| 446 if (!viewportDescription.isSpecifiedByAuthor()) { | 466 if (!viewportDescription.isSpecifiedByAuthor()) { |
| 447 float deviceScaleAdjustment = m_document->settings()->deviceScaleAdjustm ent(); | 467 float deviceScaleAdjustment = m_document->settings()->deviceScaleAdjustm ent(); |
| 448 m_baseMultiplier *= deviceScaleAdjustment; | 468 m_baseMultiplier *= deviceScaleAdjustment; |
| 449 } | 469 } |
| 450 | 470 |
| 451 m_pageAutosizingStatus = m_frameWidth && (m_baseMultiplier * (static_cast<fl oat>(m_layoutWidth) / m_frameWidth) > 1.0f) | 471 m_pageNeedsAutosizing = !!m_frameWidth |
| 452 ? PageNeedsAutosizing : PageDoesNotNeedAutosizing; | 472 && (m_baseMultiplier * (static_cast<float>(m_layoutWidth) / m_frameWidth ) > 1.0f); |
| 453 | 473 |
| 454 #ifndef NDEBUG | 474 // If we are no longer autosizing the page, we won't do anything during the next layout. |
| 455 m_renderViewInfoPrepared = true; | 475 // Set all the multipliers back to 1 now. |
| 456 #endif | 476 if (!m_pageNeedsAutosizing && m_previouslyAutosized) |
| 477 resetMultipliers(); | |
| 478 | |
| 479 // If page info has changed, multipliers may have changed. Force a layout to recompute them. | |
| 480 if (m_pageNeedsAutosizing | |
| 481 && (m_frameWidth != previousFrameWidth | |
| 482 || m_layoutWidth != previousLayoutWidth | |
| 483 || m_baseMultiplier != previousBaseMultiplier)) | |
| 484 setAllTextNeedsLayout(); | |
| 485 } | |
| 486 | |
| 487 void FastTextAutosizer::resetMultipliers() | |
| 488 { | |
| 489 RenderObject* renderer = m_document->renderer(); | |
| 490 while (renderer) { | |
| 491 if (RenderStyle* style = renderer->style()) { | |
| 492 if (style->textAutosizingMultiplier() != 1) | |
| 493 applyMultiplier(renderer, 1, true /* relayout */); | |
| 494 } | |
| 495 renderer = renderer->nextInPreOrder(); | |
| 496 } | |
| 497 m_previouslyAutosized = false; | |
| 498 } | |
| 499 | |
| 500 void FastTextAutosizer::setAllTextNeedsLayout() | |
| 501 { | |
| 502 RenderObject* renderer = m_document->renderer(); | |
| 503 while (renderer) { | |
| 504 if (renderer->isText()) | |
| 505 renderer->setNeedsLayout(); | |
| 506 renderer = renderer->nextInPreOrder(); | |
| 507 } | |
| 457 } | 508 } |
| 458 | 509 |
| 459 bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider) | 510 bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider) |
| 460 { | 511 { |
| 461 Cluster hypotheticalCluster(root, true, 0); | 512 Cluster hypotheticalCluster(root, true, 0); |
| 462 return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider); | 513 return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider); |
| 463 } | 514 } |
| 464 | 515 |
| 465 bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R enderBlock* widthProvider) | 516 bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R enderBlock* widthProvider) |
| 466 { | 517 { |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 if (ancestors.count(block) == blocks.size()) | 665 if (ancestors.count(block) == blocks.size()) |
| 615 return block; | 666 return block; |
| 616 } | 667 } |
| 617 } | 668 } |
| 618 ASSERT_NOT_REACHED(); | 669 ASSERT_NOT_REACHED(); |
| 619 return 0; | 670 return 0; |
| 620 } | 671 } |
| 621 | 672 |
| 622 float FastTextAutosizer::clusterMultiplier(Cluster* cluster) | 673 float FastTextAutosizer::clusterMultiplier(Cluster* cluster) |
| 623 { | 674 { |
| 624 ASSERT(m_renderViewInfoPrepared); | |
| 625 if (!cluster->m_multiplier) { | 675 if (!cluster->m_multiplier) { |
| 626 if (cluster->m_root->isTable() | 676 if (cluster->m_root->isTable() |
| 627 || isIndependentDescendant(cluster->m_root) | 677 || isIndependentDescendant(cluster->m_root) |
| 628 || isWiderOrNarrowerDescendant(cluster)) { | 678 || isWiderOrNarrowerDescendant(cluster)) { |
| 629 | 679 |
| 630 if (cluster->m_supercluster) { | 680 if (cluster->m_supercluster) { |
| 631 cluster->m_multiplier = superclusterMultiplier(cluster); | 681 cluster->m_multiplier = superclusterMultiplier(cluster); |
| 632 } else if (clusterHasEnoughTextToAutosize(cluster)) { | 682 } else if (clusterHasEnoughTextToAutosize(cluster)) { |
| 633 cluster->m_multiplier = multiplierFromBlock(clusterWidthProvider (cluster->m_root)); | 683 cluster->m_multiplier = multiplierFromBlock(clusterWidthProvider (cluster->m_root)); |
| 634 // Do not inflate table descendants above the table's multiplier . See inflateTable(...) for details. | 684 // Do not inflate table descendants above the table's multiplier . See inflateTable(...) for details. |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 783 if (leaf) | 833 if (leaf) |
| 784 return leaf; | 834 return leaf; |
| 785 } | 835 } |
| 786 child = (firstOrLast == First) ? child->nextSibling() : child->previousS ibling(); | 836 child = (firstOrLast == First) ? child->nextSibling() : child->previousS ibling(); |
| 787 } | 837 } |
| 788 --depth; | 838 --depth; |
| 789 | 839 |
| 790 return 0; | 840 return 0; |
| 791 } | 841 } |
| 792 | 842 |
| 793 void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier ) | 843 void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier , bool relayout) |
| 794 { | 844 { |
| 795 ASSERT(renderer); | 845 ASSERT(renderer); |
| 796 RenderStyle* currentStyle = renderer->style(); | 846 RenderStyle* currentStyle = renderer->style(); |
| 797 if (currentStyle->textAutosizingMultiplier() == multiplier) | 847 if (currentStyle->textAutosizingMultiplier() == multiplier) |
| 798 return; | 848 return; |
| 799 | 849 |
| 800 // We need to clone the render style to avoid breaking style sharing. | 850 // We need to clone the render style to avoid breaking style sharing. |
| 801 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle); | 851 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle); |
| 802 style->setTextAutosizingMultiplier(multiplier); | 852 style->setTextAutosizingMultiplier(multiplier); |
| 803 style->setUnique(); | 853 style->setUnique(); |
| 804 renderer->setStyleInternal(style.release()); | |
| 805 | 854 |
| 806 if (renderer->isRenderBlock()) | 855 if (relayout) { |
| 807 toRenderBlock(renderer)->invalidateLineHeight(); | 856 renderer->setStyle(style.release()); |
|
pdr.
2014/03/25 04:23:41
This can cause us to go back through quite a bit o
skobes
2014/03/25 18:25:26
There's no way for setStyleInternal to trigger a l
| |
| 857 } else { | |
| 858 renderer->setStyleInternal(style.release()); | |
| 859 if (renderer->isRenderBlock()) | |
| 860 toRenderBlock(renderer)->invalidateLineHeight(); | |
|
pdr.
2014/03/25 04:23:41
Is this lineheight change supposed to be part of t
skobes
2014/03/25 18:25:26
This patch is branched from the lineheight change.
| |
| 861 } | |
| 862 | |
| 863 if (multiplier != 1) | |
| 864 m_previouslyAutosized = true; | |
| 808 } | 865 } |
| 809 | 866 |
| 810 bool FastTextAutosizer::isWiderOrNarrowerDescendant(Cluster* cluster) | 867 bool FastTextAutosizer::isWiderOrNarrowerDescendant(Cluster* cluster) |
| 811 { | 868 { |
| 812 if (!cluster->m_parent || !mightBeWiderOrNarrowerDescendant(cluster->m_root) ) | 869 if (!cluster->m_parent || !mightBeWiderOrNarrowerDescendant(cluster->m_root) ) |
| 813 return true; | 870 return true; |
| 814 | 871 |
| 815 const RenderBlock* parentDeepestBlockContainingAllText = deepestBlockContain ingAllText(cluster->m_parent); | 872 const RenderBlock* parentDeepestBlockContainingAllText = deepestBlockContain ingAllText(cluster->m_parent); |
| 816 ASSERT(m_blocksThatHaveBegunLayout.contains(cluster->m_root)); | 873 ASSERT(m_blocksThatHaveBegunLayout.contains(cluster->m_root)); |
| 817 ASSERT(m_blocksThatHaveBegunLayout.contains(parentDeepestBlockContainingAllT ext)); | 874 ASSERT(m_blocksThatHaveBegunLayout.contains(parentDeepestBlockContainingAllT ext)); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 908 return *m_blocksForFingerprint.get(fingerprint); | 965 return *m_blocksForFingerprint.get(fingerprint); |
| 909 } | 966 } |
| 910 | 967 |
| 911 FastTextAutosizer::LayoutScope::LayoutScope(RenderBlock* block) | 968 FastTextAutosizer::LayoutScope::LayoutScope(RenderBlock* block) |
| 912 : m_textAutosizer(block->document().fastTextAutosizer()) | 969 : m_textAutosizer(block->document().fastTextAutosizer()) |
| 913 , m_block(block) | 970 , m_block(block) |
| 914 { | 971 { |
| 915 if (!m_textAutosizer) | 972 if (!m_textAutosizer) |
| 916 return; | 973 return; |
| 917 | 974 |
| 918 if (!m_textAutosizer->enabled()) { | 975 if (m_textAutosizer->enabled() && m_textAutosizer->m_pageNeedsAutosizing) |
| 919 m_textAutosizer = 0; | |
| 920 return; | |
| 921 } | |
| 922 | |
| 923 if (m_textAutosizer->m_pageAutosizingStatus == PageAutosizingStatusUnknown) | |
| 924 m_textAutosizer->updateRenderViewInfo(); | |
| 925 | |
| 926 if (m_textAutosizer->m_pageAutosizingStatus == PageNeedsAutosizing) | |
| 927 m_textAutosizer->beginLayout(m_block); | 976 m_textAutosizer->beginLayout(m_block); |
| 928 else | 977 else |
| 929 m_textAutosizer = 0; | 978 m_textAutosizer = 0; |
| 930 } | 979 } |
| 931 | 980 |
| 932 FastTextAutosizer::LayoutScope::~LayoutScope() | 981 FastTextAutosizer::LayoutScope::~LayoutScope() |
| 933 { | 982 { |
| 934 if (m_textAutosizer) | 983 if (m_textAutosizer) |
| 935 m_textAutosizer->endLayout(m_block); | 984 m_textAutosizer->endLayout(m_block); |
| 936 } | 985 } |
| 937 | 986 |
| 938 } // namespace WebCore | 987 } // namespace WebCore |
| OLD | NEW |