Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PdfStructTreeBuilder_h_
#define PdfStructTreeBuilder_h_
#include "mozilla/HashTable.h"
#include "mozilla/MozPromise.h"
#include "mozilla/PairHash.h"
class nsIFrame;
namespace SkPDF {
struct StructureElementNode;
}
namespace mozilla {
namespace dom {
class BrowsingContext;
}
namespace a11y {
class Accessible;
/**
* Uses the Gecko accessibility tree to build a PDF structure tree that can be
* used with Skia's SkPDF backend.
* The functionality provided here needs to be accessed from several places in
* the layout, graphics, printing, PDF and accessibility code. Rather than
* propagating an instance through all of these modules, we maintain a registry
* of instances associated with BrowsingContexts. Static methods are used to
* access or act on the appropriate instance.
*/
class PdfStructTreeBuilder {
public:
/**
* Initialize for a document. This must first be called for the top document
* being built, followed by any nested OOP iframes.
*/
static void Init(dom::BrowsingContext* aBrowsingContext);
static PdfStructTreeBuilder* Get(uint64_t aBrowsingContextId);
/**
* Indicate that building is finished for this document. This only needs to be
* called for the top document. This destroys the instance associated with the
* document.
*/
static void Done(uint64_t aBrowsingContextId);
/**
* SkPDF uses global int ids, but Gecko accessibility uses document specific
* uint64_t ids. Get the SkPDF id for a given Gecko Accessible identifier.
*/
static int GetPdfId(uint64_t aBrowsingContextId, uint64_t aAccId);
using GlobalAccessibleId = std::pair<uint64_t, uint64_t>;
/**
* Get information suitable for identifying an Accessible via
* DrawTarget::AccessibleId.
*/
static GlobalAccessibleId GetAccId(nsIFrame* aFrame);
using ReadyPromise = MozPromise<Ok, Ok, true>;
/**
* Return a promise which is resolved when this builder is ready.
* BuildStructTree should not be called before this promise resolves.
*/
already_AddRefed<ReadyPromise> GetReadyPromise() {
RefPtr<ReadyPromise> promise = mReadyPromise;
return promise.forget();
}
/**
* Build the PDF structure tree!
*/
bool BuildStructTree(SkPDF::StructureElementNode& aRoot);
private:
explicit PdfStructTreeBuilder(uint64_t aBrowsingContextId);
void InitInternal(dom::BrowsingContext* aBrowsingContext);
int GeneratePdfId(Accessible* aAcc);
void BuildStructSubtree(Accessible* aAcc, SkPDF::StructureElementNode& aPdf);
int GetPdfIdInternal(uint64_t aBrowsingContextId, uint64_t aAccId) const;
// We can't take a reference to an Accessible, so we store the BrowsingContext
// id instead and get the document Accessible from the BrowsingContext.
uint64_t mRootBrowsingContextId;
// The number of out-of-process iframes we are waiting for.
size_t mPendingOopIframes = 0;
RefPtr<ReadyPromise::Private> mReadyPromise;
int mLastPdfId = 0;
// Maps {browsingContextId, accessibleId} to SkPDF id.
mozilla::HashMap<GlobalAccessibleId, int, PairHasher<uint64_t, uint64_t>>
mAccToPdf;
// Needed so nsTArray::EmplaceBack can access our private constructor.
friend class nsTArrayElementTraits<mozilla::a11y::PdfStructTreeBuilder>;
};
} // namespace a11y
} // namespace mozilla
#endif