зеркало из https://github.com/mozilla/gecko-dev.git
Bug 454059 - Generate hyperlinks in PDF output for HTML link elements. r=mstange,mattwoodrow
Differential Revision: https://phabricator.services.mozilla.com/D114208
This commit is contained in:
Родитель
63f05b6d5a
Коммит
d4614f8d3f
|
@ -3991,6 +3991,20 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
|||
return;
|
||||
}
|
||||
|
||||
// If we're generating a display list for printing, include Link items for
|
||||
// frames that correspond to HTML link elements so that we can have active
|
||||
// links in saved PDF output. Note that the state of "within a link" is
|
||||
// set on the display-list builder, such that all descendants of the link
|
||||
// element will generate display-list links.
|
||||
// TODO: we should be able to optimize this so as to avoid creating links
|
||||
// for the same destination that entirely overlap each other, which adds
|
||||
// nothing useful to the final PDF.
|
||||
Maybe<nsDisplayListBuilder::Linkifier> linkifier;
|
||||
if (aBuilder->IsForPrinting()) {
|
||||
linkifier.emplace(aBuilder, aChild);
|
||||
linkifier->MaybeAppendLink(aBuilder, aChild, aLists.Content());
|
||||
}
|
||||
|
||||
nsIFrame* child = aChild;
|
||||
auto* placeholder = child->IsPlaceholderFrame()
|
||||
? static_cast<nsPlaceholderFrame*>(child)
|
||||
|
|
|
@ -554,6 +554,47 @@ nsRect nsDisplayListBuilder::OutOfFlowDisplayData::ComputeVisibleRectForFrame(
|
|||
return visible;
|
||||
}
|
||||
|
||||
nsDisplayListBuilder::Linkifier::Linkifier(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame) {
|
||||
// Links don't nest, so if the builder already has a destination, no need to
|
||||
// check for a link element here.
|
||||
if (!aBuilder->mLinkSpec.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the element that we need to check for link-ness, bailing out if
|
||||
// we can't find one.
|
||||
Element* elem = Element::FromNodeOrNull(aFrame->GetContent());
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have actually found a link and it has a usable spec.
|
||||
nsCOMPtr<nsIURI> linkURI;
|
||||
if (!elem->IsLink(getter_AddRefs(linkURI))) {
|
||||
return;
|
||||
}
|
||||
if (NS_FAILED(linkURI->GetSpec(aBuilder->mLinkSpec)) ||
|
||||
aBuilder->mLinkSpec.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record that we need to reset the builder's state on destruction.
|
||||
mBuilderToReset = aBuilder;
|
||||
}
|
||||
|
||||
void nsDisplayListBuilder::Linkifier::MaybeAppendLink(
|
||||
nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList) {
|
||||
// Note that we may generate a link here even if the constructor bailed out
|
||||
// without updating aBuilder->LinkSpec(), because it may have been set by
|
||||
// an ancestor that was associated with a link element.
|
||||
if (!aBuilder->mLinkSpec.IsEmpty()) {
|
||||
auto* link = MakeDisplayItem<nsDisplayLink>(
|
||||
aBuilder, aFrame, aBuilder->mLinkSpec.get(), aFrame->GetRect());
|
||||
aList->AppendToTop(link);
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
nsDisplayListBuilderMode aMode,
|
||||
bool aBuildCaret,
|
||||
|
|
|
@ -1824,6 +1824,25 @@ class nsDisplayListBuilder {
|
|||
void AddScrollFrameToNotify(nsIScrollableFrame* aScrollFrame);
|
||||
void NotifyAndClearScrollFrames();
|
||||
|
||||
// Helper class to find what link spec (if any) to associate with a frame,
|
||||
// recording it in the builder, and generate the corresponding DisplayItem.
|
||||
class Linkifier {
|
||||
public:
|
||||
Linkifier(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
|
||||
|
||||
~Linkifier() {
|
||||
if (mBuilderToReset) {
|
||||
mBuilderToReset->mLinkSpec.Truncate(0);
|
||||
}
|
||||
}
|
||||
|
||||
void MaybeAppendLink(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsDisplayList* aList);
|
||||
|
||||
private:
|
||||
nsDisplayListBuilder* mBuilderToReset = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
bool MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
|
||||
const nsRect& aVisibleRect,
|
||||
|
@ -2002,6 +2021,7 @@ class nsDisplayListBuilder {
|
|||
// filter. Otherwise nullptr.
|
||||
const ActiveScrolledRoot* mFilterASR;
|
||||
std::unordered_set<nsIScrollableFrame*> mScrollFramesToNotify;
|
||||
nsCString mLinkSpec; // Destination of link currently being emitted, if any.
|
||||
bool mContainsBlendMode;
|
||||
bool mIsBuildingScrollbar;
|
||||
bool mCurrentScrollbarWillHaveLayer;
|
||||
|
|
Загрузка…
Ссылка в новой задаче