Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Noemi Erli 2018-09-14 06:47:16 +03:00
commit 9aeeb8fc28
286 changed files with 7775 additions and 3466 deletions

View File

@ -607,7 +607,7 @@ html|input.urlbar-input[textoverflow="start"]:not([focused]) {
mask-image: linear-gradient(to right, transparent var(--urlbar-scheme-size), black calc(var(--urlbar-scheme-size) + 3ch));
}
html|input.urlbar-input:not([focused]) {
html|input.urlbar-input {
mask-repeat: no-repeat;
}

View File

@ -71,7 +71,6 @@ let ACTORS = {
ClickHandler: {
child: {
module: "resource:///actors/ClickHandlerChild.jsm",
group: "browsers",
events: {
"click": {capture: true, mozSystemGroup: true},
},

View File

@ -44,6 +44,13 @@ var ContentClick = {
return;
}
// If the browser is not in a place where we can open links, bail out.
// This can happen in osx sheets, dialogs, etc. that are not browser
// windows. Specifically the payments UI is in an osx sheet.
if (window.openLinkIn === undefined) {
return;
}
// Mark the page as a user followed link. This is done so that history can
// distinguish automatic embed visits from user activated ones. For example
// pages loaded in frames are embed visits and lost with the session, while

View File

@ -479,13 +479,14 @@
/* Shift the url-bar text fading to stop the recommendation overlapping */
#urlbar[cfr-recommendation-state] html|input.urlbar-input {
/* A mask-image is usually only defined for the url bar when text overflows.
We need to re-define the mask image here so that it shows up correctly when
we transition to or from an `expanded` state (in which the right end of the
url bar may be obscured without overflow). */
mask-image: linear-gradient(to left, transparent, black 3ch);
transition: mask-position-x ease-in-out var(--cfr-animation-duration);
}
#urlbar[cfr-recommendation-state="expanded"] html|input.urlbar-input {
/* A mask-image is only defined for the url bar when text overflows. When
expanded, the right end of the url bar may be obscured without overflow so
we need to redefine the mask-image here, as well as the mask-position-x. */
mask-image: linear-gradient(to left, transparent, black 3ch);
mask-position-x: calc(var(--cfr-label-width) * -1);
}

View File

@ -3580,7 +3580,7 @@ Element::RequestFullscreen(CallerType aCallerType, ErrorResult& aError)
// Note that requests for fullscreen inside a web app's origin are exempt
// from this restriction.
if (const char* error = GetFullscreenError(aCallerType)) {
OwnerDoc()->DispatchFullscreenError(error);
OwnerDoc()->DispatchFullscreenError(error, this);
return;
}

View File

@ -113,11 +113,6 @@
#define NS_XULCONTROLLERS_CID \
{ 0x1f5c1721, 0x7dc3, 0x11d3, { 0xbf, 0x87, 0x0, 0x10, 0x5a, 0x1b, 0x6, 0x27 } }
// {BFD05264-834C-11d2-8EAC-00805F29F371}
#define NS_XULSORTSERVICE_CID \
{ 0xbfd05264, 0x834c, 0x11d2, { 0x8e, 0xac, 0x0, 0x80, 0x5f, 0x29, 0xf3, 0x71 } }
// {3D262D00-8B5A-11d2-8EB0-00805F29F370}
#define NS_XULTEMPLATEBUILDER_CID \
{ 0x3d262d00, 0x8b5a, 0x11d2, { 0x8e, 0xb0, 0x0, 0x80, 0x5f, 0x29, 0xf3, 0x70 } }

View File

@ -4371,6 +4371,7 @@ nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget,
const nsAString& aEventName,
CanBubble aCanBubble,
Cancelable aCancelable,
Composed aComposed,
Trusted aTrusted,
Event** aEvent,
EventTarget** aTargetOut)
@ -4385,7 +4386,7 @@ nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget,
return err.StealNSResult();
}
event->InitEvent(aEventName, aCanBubble, aCancelable);
event->InitEvent(aEventName, aCanBubble, aCancelable, aComposed);
event->SetTrusted(aTrusted == Trusted::eYes);
event->SetTarget(target);
@ -4401,10 +4402,11 @@ nsContentUtils::DispatchTrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
const nsAString& aEventName,
CanBubble aCanBubble,
Cancelable aCancelable,
Composed aComposed,
bool* aDefaultAction)
{
return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
Trusted::eYes, aDefaultAction);
aComposed, Trusted::eYes, aDefaultAction);
}
// static
@ -4416,7 +4418,7 @@ nsContentUtils::DispatchUntrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
bool* aDefaultAction)
{
return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
Trusted::eNo, aDefaultAction);
Composed::eDefault, Trusted::eNo, aDefaultAction);
}
// static
@ -4425,6 +4427,7 @@ nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget,
const nsAString& aEventName,
CanBubble aCanBubble,
Cancelable aCancelable,
Composed aComposed,
Trusted aTrusted,
bool* aDefaultAction,
ChromeOnlyDispatch aOnlyChromeDispatch)
@ -4432,7 +4435,8 @@ nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget,
RefPtr<Event> event;
nsCOMPtr<EventTarget> target;
nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
aCancelable, aTrusted, getter_AddRefs(event),
aCancelable, aComposed, aTrusted,
getter_AddRefs(event),
getter_AddRefs(target));
NS_ENSURE_SUCCESS(rv, rv);
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch =
@ -4496,7 +4500,8 @@ nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
RefPtr<Event> event;
nsCOMPtr<EventTarget> target;
nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
aCancelable, Trusted::eYes,
aCancelable, Composed::eDefault,
Trusted::eYes,
getter_AddRefs(event),
getter_AddRefs(target));
NS_ENSURE_SUCCESS(rv, rv);
@ -4543,7 +4548,8 @@ nsContentUtils::DispatchEventOnlyToChrome(nsIDocument* aDoc,
bool* aDefaultAction)
{
return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
Trusted::eYes, aDefaultAction, ChromeOnlyDispatch::eYes);
Composed::eDefault, Trusted::eYes, aDefaultAction,
ChromeOnlyDispatch::eYes);
}
/* static */

View File

@ -203,6 +203,7 @@ class nsContentUtils
typedef mozilla::dom::Element Element;
typedef mozilla::Cancelable Cancelable;
typedef mozilla::CanBubble CanBubble;
typedef mozilla::Composed Composed;
typedef mozilla::ChromeOnlyDispatch ChromeOnlyDispatch;
typedef mozilla::EventMessage EventMessage;
typedef mozilla::TimeDuration TimeDuration;
@ -1345,6 +1346,7 @@ public:
* @param aEventName The name of the event.
* @param aCanBubble Whether the event can bubble.
* @param aCancelable Is the event cancelable.
* @param aCopmosed Is the event composed.
* @param aDefaultAction Set to true if default action should be taken,
* see EventTarget::DispatchEvent.
*/
@ -1353,8 +1355,21 @@ public:
const nsAString& aEventName,
CanBubble,
Cancelable,
Composed aComposed = Composed::eDefault,
bool* aDefaultAction = nullptr);
static nsresult DispatchTrustedEvent(nsIDocument* aDoc,
nsISupports* aTarget,
const nsAString& aEventName,
CanBubble aCanBubble,
Cancelable aCancelable,
bool* aDefaultAction)
{
return DispatchTrustedEvent(aDoc, aTarget, aEventName,
aCanBubble, aCancelable,
Composed::eDefault, aDefaultAction);
}
/**
* This method creates and dispatches a trusted event using an event message.
* @param aDoc The document which will be used to create the event.
@ -3339,6 +3354,7 @@ private:
const nsAString& aEventName,
CanBubble,
Cancelable,
Composed,
Trusted,
bool* aDefaultAction = nullptr,
ChromeOnlyDispatch = ChromeOnlyDispatch::eNo);

View File

@ -3361,6 +3361,13 @@ nsIDocument::LocalizationLinkAdded(Element* aLinkElement)
AutoTArray<nsString, 1> resourceIds;
resourceIds.AppendElement(href);
mDocumentL10n->AddResourceIds(resourceIds);
} else if (mReadyState == READYSTATE_COMPLETE) {
// Otherwise, if the document has already been parsed
// we need to lazily initialize the localization.
AutoTArray<nsString, 1> resourceIds;
resourceIds.AppendElement(href);
InitializeLocalization(resourceIds);
mDocumentL10n->TriggerInitialDocumentTranslation();
} else {
// Otherwise, we're still parsing the document.
// In that case, add it to the pending list. This list
@ -8555,11 +8562,11 @@ NotifyPageHide(nsIDocument* aDocument, void* aData)
}
static void
DispatchFullscreenChange(nsIDocument* aTarget)
DispatchFullscreenChange(nsIDocument* aDocument, nsINode* aTarget)
{
if (nsPresContext* presContext = aTarget->GetPresContext()) {
auto pendingEvent =
MakeUnique<PendingFullscreenEvent>(FullscreenEventType::Change, aTarget);
if (nsPresContext* presContext = aDocument->GetPresContext()) {
auto pendingEvent = MakeUnique<PendingFullscreenEvent>(
FullscreenEventType::Change, aDocument, aTarget);
presContext->RefreshDriver()->
ScheduleFullscreenEvent(std::move(pendingEvent));
}
@ -10709,13 +10716,13 @@ GetFullscreenLeaf(nsIDocument* aDoc)
static bool
ResetFullscreen(nsIDocument* aDocument, void* aData)
{
if (aDocument->FullscreenStackTop()) {
if (Element* fsElement = aDocument->FullscreenStackTop()) {
NS_ASSERTION(CountFullscreenSubDocuments(aDocument) <= 1,
"Should have at most 1 fullscreen subdocument.");
aDocument->CleanupFullscreenState();
NS_ASSERTION(!aDocument->FullscreenStackTop(),
"Should reset fullscreen");
DispatchFullscreenChange(aDocument);
DispatchFullscreenChange(aDocument, fsElement);
aDocument->EnumerateSubDocuments(ResetFullscreen, nullptr);
}
return true;
@ -10816,35 +10823,38 @@ nsIDocument::RestorePreviousFullscreenState()
}
nsCOMPtr<nsIDocument> fullScreenDoc = GetFullscreenLeaf(this);
AutoTArray<nsIDocument*, 8> exitDocs;
AutoTArray<Element*, 8> exitElements;
nsIDocument* doc = fullScreenDoc;
// Collect all subdocuments.
for (; doc != this; doc = doc->GetParentDocument()) {
exitDocs.AppendElement(doc);
Element* fsElement = doc->FullscreenStackTop();
MOZ_ASSERT(fsElement, "Parent document of "
"a fullscreen document without fullscreen element?");
exitElements.AppendElement(fsElement);
}
MOZ_ASSERT(doc == this, "Must have reached this doc");
// Collect all ancestor documents which we are going to change.
for (; doc; doc = doc->GetParentDocument()) {
MOZ_ASSERT(!doc->mFullscreenStack.IsEmpty(),
"Ancestor of fullscreen document must also be in fullscreen");
Element* fsElement = doc->FullscreenStackTop();
if (doc != this) {
Element* top = doc->FullscreenStackTop();
if (top->IsHTMLElement(nsGkAtoms::iframe)) {
if (static_cast<HTMLIFrameElement*>(top)->FullscreenFlag()) {
if (auto* iframe = HTMLIFrameElement::FromNode(fsElement)) {
if (iframe->FullscreenFlag()) {
// If this is an iframe, and it explicitly requested
// fullscreen, don't rollback it automatically.
break;
}
}
}
exitDocs.AppendElement(doc);
exitElements.AppendElement(fsElement);
if (doc->mFullscreenStack.Length() > 1) {
break;
}
}
nsIDocument* lastDoc = exitDocs.LastElement();
nsIDocument* lastDoc = exitElements.LastElement()->OwnerDoc();
if (!lastDoc->GetParentDocument() &&
lastDoc->mFullscreenStack.Length() == 1) {
// If we are fully exiting fullscreen, don't touch anything here,
@ -10857,8 +10867,8 @@ nsIDocument::RestorePreviousFullscreenState()
UnlockPointer();
// All documents listed in the array except the last one are going to
// completely exit from the fullscreen state.
for (auto i : IntegerRange(exitDocs.Length() - 1)) {
exitDocs[i]->CleanupFullscreenState();
for (auto i : IntegerRange(exitElements.Length() - 1)) {
exitElements[i]->OwnerDoc()->CleanupFullscreenState();
}
// The last document will either rollback one fullscreen element, or
// completely exit from the fullscreen state as well.
@ -10873,8 +10883,8 @@ nsIDocument::RestorePreviousFullscreenState()
// Dispatch the fullscreenchange event to all document listed. Note
// that the loop order is reversed so that events are dispatched in
// the tree order as indicated in the spec.
for (nsIDocument* d : Reversed(exitDocs)) {
DispatchFullscreenChange(d);
for (Element* e : Reversed(exitElements)) {
DispatchFullscreenChange(e->OwnerDoc(), e);
}
MOZ_ASSERT(newFullscreenDoc, "If we were going to exit from fullscreen on "
@ -10925,11 +10935,11 @@ nsIDocument::AsyncRequestFullscreen(UniquePtr<FullscreenRequest> aRequest)
}
void
nsIDocument::DispatchFullscreenError(const char* aMessage)
nsIDocument::DispatchFullscreenError(const char* aMessage, nsINode* aTarget)
{
if (nsPresContext* presContext = GetPresContext()) {
auto pendingEvent =
MakeUnique<PendingFullscreenEvent>(FullscreenEventType::Error, this);
auto pendingEvent = MakeUnique<PendingFullscreenEvent>(
FullscreenEventType::Error, this, aTarget);
presContext->RefreshDriver()->
ScheduleFullscreenEvent(std::move(pendingEvent));
}
@ -11164,27 +11174,27 @@ nsIDocument::FullscreenElementReadyCheck(Element* aElement,
return false;
}
if (!aElement->IsInComposedDoc()) {
DispatchFullscreenError("FullscreenDeniedNotInDocument");
DispatchFullscreenError("FullscreenDeniedNotInDocument", aElement);
return false;
}
if (aElement->OwnerDoc() != this) {
DispatchFullscreenError("FullscreenDeniedMovedDocument");
DispatchFullscreenError("FullscreenDeniedMovedDocument", aElement);
return false;
}
if (!GetWindow()) {
DispatchFullscreenError("FullscreenDeniedLostWindow");
DispatchFullscreenError("FullscreenDeniedLostWindow", aElement);
return false;
}
if (const char* msg = GetFullscreenError(this, aCallerType)) {
DispatchFullscreenError(msg);
DispatchFullscreenError(msg, aElement);
return false;
}
if (!IsVisible()) {
DispatchFullscreenError("FullscreenDeniedHidden");
DispatchFullscreenError("FullscreenDeniedHidden", aElement);
return false;
}
if (HasFullscreenSubDocument(this)) {
DispatchFullscreenError("FullscreenDeniedSubDocFullScreen");
DispatchFullscreenError("FullscreenDeniedSubDocFullScreen", aElement);
return false;
}
//XXXsmaug Note, we don't follow the latest fullscreen spec here.
@ -11194,11 +11204,11 @@ nsIDocument::FullscreenElementReadyCheck(Element* aElement,
FullscreenStackTop())) {
// If this document is fullscreen, only grant fullscreen requests from
// a descendant of the current fullscreen element.
DispatchFullscreenError("FullscreenDeniedNotDescendant");
DispatchFullscreenError("FullscreenDeniedNotDescendant", aElement);
return false;
}
if (!nsContentUtils::IsChromeDoc(this) && !IsInActiveTab(this)) {
DispatchFullscreenError("FullscreenDeniedNotFocusedTab");
DispatchFullscreenError("FullscreenDeniedNotFocusedTab", aElement);
return false;
}
// Deny requests when a windowed plugin is focused.
@ -11208,7 +11218,7 @@ nsIDocument::FullscreenElementReadyCheck(Element* aElement,
return false;
}
if (nsContentUtils::HasPluginWithUncontrolledEventDispatch(fm->GetFocusedElement())) {
DispatchFullscreenError("FullscreenDeniedFocusedPlugin");
DispatchFullscreenError("FullscreenDeniedFocusedPlugin", aElement);
return false;
}
return true;
@ -11388,7 +11398,7 @@ nsIDocument::RequestFullscreen(UniquePtr<FullscreenRequest> aRequest)
if (!elem->IsHTMLElement() && !elem->IsXULElement() &&
!elem->IsSVGElement(nsGkAtoms::svg) &&
!elem->IsMathMLElement(nsGkAtoms::math)) {
DispatchFullscreenError("FullscreenDeniedNotHTMLSVGOrMathML");
DispatchFullscreenError("FullscreenDeniedNotHTMLSVGOrMathML", elem);
return;
}
@ -11531,7 +11541,7 @@ nsIDocument::ApplyFullscreen(const FullscreenRequest& aRequest)
// reversed so that events are dispatched in the tree order as
// indicated in the spec.
for (nsIDocument* d : Reversed(changed)) {
DispatchFullscreenChange(d);
DispatchFullscreenChange(d, d->FullscreenStackTop());
}
return true;
}

View File

@ -1858,7 +1858,7 @@ public:
* Dispatch fullscreenerror event and report the failure message to
* the console.
*/
void DispatchFullscreenError(const char* aMessage);
void DispatchFullscreenError(const char* aMessage, nsINode* aTarget);
void RequestPointerLock(Element* aElement, mozilla::dom::CallerType);
bool SetPointerLock(Element* aElement, int aCursorStyle);

View File

@ -491,7 +491,8 @@ Event::EnsureWebAccessibleRelatedTarget(EventTarget* aRelatedTarget)
void
Event::InitEvent(const nsAString& aEventTypeArg,
mozilla::CanBubble aCanBubbleArg,
mozilla::Cancelable aCancelableArg)
mozilla::Cancelable aCancelableArg,
mozilla::Composed aComposedArg)
{
// Make sure this event isn't already being dispatched.
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
@ -507,6 +508,9 @@ Event::InitEvent(const nsAString& aEventTypeArg,
mEvent->mFlags.mBubbles = aCanBubbleArg == CanBubble::eYes;
mEvent->mFlags.mCancelable = aCancelableArg == Cancelable::eYes;
if (aComposedArg != Composed::eDefault) {
mEvent->mFlags.mComposed = aComposedArg == Composed::eYes;
}
mEvent->mFlags.mDefaultPrevented = false;
mEvent->mFlags.mDefaultPreventedByContent = false;

View File

@ -158,7 +158,8 @@ public:
void InitEvent(const nsAString& aEventTypeArg,
mozilla::CanBubble,
mozilla::Cancelable);
mozilla::Cancelable,
mozilla::Composed = mozilla::Composed::eDefault);
void SetTarget(EventTarget* aTarget);
virtual void DuplicatePrivateData();

View File

@ -26,11 +26,15 @@ enum class FullscreenEventType
class PendingFullscreenEvent
{
public:
PendingFullscreenEvent(FullscreenEventType aType, nsIDocument* aDoc)
: mDocument(aDoc)
PendingFullscreenEvent(FullscreenEventType aType,
nsIDocument* aDocument,
nsINode* aTarget)
: mDocument(aDocument)
, mTarget(aTarget)
, mType(aType)
{
MOZ_ASSERT(aDoc);
MOZ_ASSERT(aDocument);
MOZ_ASSERT(aTarget);
}
nsIDocument* Document() const { return mDocument; }
@ -50,13 +54,16 @@ public:
name = NS_LITERAL_STRING("fullscreenerror");
break;
}
nsINode* target =
mTarget->GetComposedDoc() == mDocument ? mTarget : mDocument;
Unused << nsContentUtils::DispatchTrustedEvent(
mDocument, mDocument, name,
CanBubble::eYes, Cancelable::eNo, nullptr);
mDocument, target, name,
CanBubble::eYes, Cancelable::eNo, Composed::eYes);
}
private:
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsINode> mTarget;
FullscreenEventType mType;
#ifdef DEBUG
bool mDispatched = false;

View File

@ -4147,7 +4147,7 @@ HTMLMediaElement::DispatchEventsWhenPlayWasNotAllowed()
}
#if defined(MOZ_WIDGET_ANDROID)
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(OwnerDoc(),
new AsyncEventDispatcher(this,
NS_LITERAL_STRING("MozAutoplayMediaBlocked"),
CanBubble::eYes,
ChromeOnlyDispatch::eYes);

View File

@ -276,7 +276,7 @@ TextTrackManager::UpdateCueDisplay()
nsCOMPtr<nsIContent> overlay = videoFrame->GetCaptionOverlay();
nsCOMPtr<nsIContent> controls = videoFrame->GetVideoControls();
if (!overlay || !controls) {
if (!overlay) {
return;
}

View File

@ -18,6 +18,7 @@ Test DOM full-screen API.
</style>
</head>
<body>
<div id="fullscreen-element"></div>
<script type="application/javascript">
/** Test for Bug 545812 **/
@ -50,29 +51,27 @@ function sendMouseClick(element) {
synthesizeMouseAtCenter(element, {});
}
function fullScreenElement() {
return document.getElementById('full-screen-element');
}
const FULLSCREEN_ELEMENT = document.getElementById("fullscreen-element");
function enter1(event) {
is(event.target, document, "Event target should be full-screen document #1");
is(event.target, FULLSCREEN_ELEMENT,
"Event target should be the fullscreen element #1");
ok(document.fullscreen, "Document should be in fullscreen");
is(document.fullscreenElement, fullScreenElement(),
is(document.fullscreenElement, FULLSCREEN_ELEMENT,
"Full-screen element should be div element.");
ok(document.fullscreenElement.matches(":fullscreen"),
"FSE should match :fullscreen");
var fse = fullScreenElement();
addFullscreenChangeContinuation("exit", exit1);
fse.remove();
FULLSCREEN_ELEMENT.remove();
is(document.fullscreenElement, null,
"Full-screen element should be null after removing.");
document.body.appendChild(fse);
is(document.fullscreenElement, null,
"Full-screen element should still be null after re-adding former FSE.");
}
function exit1(event) {
is(event.target, document, "Event target should be full-screen document #2");
document.body.appendChild(FULLSCREEN_ELEMENT);
is(document.fullscreenElement, null,
"Full-screen element should still be null after re-adding former FSE.");
is(event.target, document, "Event target should be the document #2");
ok(!document.fullscreen, "Document should not be in fullscreen");
is(document.fullscreenElement, null, "Full-screen element should be null.");
iframe = document.createElement("iframe");
@ -83,7 +82,8 @@ function exit1(event) {
}
function enter2(event) {
is(event.target, document, "Event target should be full-screen document #3");
is(event.target, iframe,
"Event target should be the fullscreen iframe #3");
is(document.fullscreenElement, iframe,
"Full-screen element should be iframe element.");
is(iframe.contentDocument.fullscreenElement, iframe.contentDocument.body,
@ -103,31 +103,30 @@ function exit2(event) {
"Full-screen element in subframe should be null");
addFullscreenChangeContinuation("enter", enter3);
fullScreenElement().requestFullscreen();
FULLSCREEN_ELEMENT.requestFullscreen();
}
function enter3(event) {
is(event.target, document, "Event target should be full-screen document #3");
is(document.fullscreenElement, fullScreenElement(),
is(event.target, FULLSCREEN_ELEMENT,
"Event target should be the fullscreen element #3");
is(document.fullscreenElement, FULLSCREEN_ELEMENT,
"Full-screen element should be div.");
// Transplant the FSE into subdoc. Should exit full-screen.
addFullscreenChangeContinuation("exit", exit3);
var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
var fse = fullScreenElement();
_innerFrame.contentDocument.body.appendChild(fse);
_innerFrame.contentDocument.body.appendChild(FULLSCREEN_ELEMENT);
is(document.fullscreenElement, null,
"Full-screen element transplanted, should be null.");
is(iframe.contentDocument.fullscreenElement, null,
"Full-screen element in outer frame should be null.");
is(_innerFrame.contentDocument.fullscreenElement, null,
"Full-screen element in inner frame should be null.");
document.body.appendChild(fse);
}
function exit3(event) {
is(event.target, document, "Event target should be full-screen document #4");
document.body.appendChild(FULLSCREEN_ELEMENT);
is(event.target, document, "Event target should be the document #3");
is(document.fullscreenElement, null, "Full-screen element should be null.");
document.body.removeChild(iframe);
iframe = null;
@ -145,14 +144,15 @@ function error1(event) {
container = document.createElement("div");
inDocElement = document.createElement("div");
container.appendChild(inDocElement);
fullScreenElement().appendChild(container);
FULLSCREEN_ELEMENT.appendChild(container);
addFullscreenChangeContinuation("enter", enter4);
inDocElement.requestFullscreen();
}
function enter4(event) {
is(event.target, document, "Event target should be full-screen document #5");
is(event.target, inDocElement,
"Event target should be the fullscreen element #4");
is(document.fullscreenElement, inDocElement, "FSE should be inDocElement.");
// Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
@ -168,11 +168,11 @@ function exit_to_arg_test_1(event) {
addFullscreenChangeContinuation("enter", enter_from_arg_test_1);
var threw = false;
try {
fullScreenElement().requestFullscreen(123);
FULLSCREEN_ELEMENT.requestFullscreen(123);
} catch (e) {
threw = true;
// trigger normal fullscreen so that we continue
fullScreenElement().requestFullscreen();
FULLSCREEN_ELEMENT.requestFullscreen();
}
ok(!threw, "requestFullscreen with bogus arg (123) shouldn't throw exception");
}
@ -190,11 +190,11 @@ function exit_to_arg_test_2(event) {
addFullscreenChangeContinuation("enter", enter_from_arg_test_2);
var threw = false;
try {
fullScreenElement().requestFullscreen({ vrDisplay: null });
FULLSCREEN_ELEMENT.requestFullscreen({ vrDisplay: null });
} catch (e) {
threw = true;
// trigger normal fullscreen so that we continue
fullScreenElement().requestFullscreen();
FULLSCREEN_ELEMENT.requestFullscreen();
}
ok(!threw, "requestFullscreen with { vrDisplay: null } shouldn't throw exception");
}
@ -211,7 +211,7 @@ function exit4(event) {
"Should be back in non-full-screen mode (fifth time)");
SpecialPowers.pushPrefEnv({"set":[["full-screen-api.allow-trusted-requests-only", true]]}, function() {
addFullscreenErrorContinuation(error2);
fullScreenElement().requestFullscreen();
FULLSCREEN_ELEMENT.requestFullscreen();
});
}
@ -219,8 +219,10 @@ function error2(event) {
ok(!document.fullscreenElement,
"Should still be in normal mode, because calling context isn't trusted.");
button = document.createElement("button");
button.onclick = function(){fullScreenElement().requestFullscreen();}
fullScreenElement().appendChild(button);
button.onclick = function() {
FULLSCREEN_ELEMENT.requestFullscreen();
};
FULLSCREEN_ELEMENT.appendChild(button);
addFullscreenChangeContinuation("enter", enter5);
sendMouseClick(button);
}
@ -239,7 +241,7 @@ function exit5(event) {
["full-screen-api.enabled", false]]}, function() {
is(document.fullscreenEnabled, false, "document.fullscreenEnabled should be false if full-screen-api.enabled is false");
addFullscreenErrorContinuation(error3);
fullScreenElement().requestFullscreen();
FULLSCREEN_ELEMENT.requestFullscreen();
});
}
@ -256,7 +258,7 @@ function error3(event) {
function begin() {
testNamespaces(() => {
addFullscreenChangeContinuation("enter", enter1);
fullScreenElement().requestFullscreen();
FULLSCREEN_ELEMENT.requestFullscreen();
});
}
@ -312,6 +314,5 @@ function testNamespaces(followupTestFn) {
}
</script>
</pre>
<div id="full-screen-element"></div>
</body>
</html>

View File

@ -12,10 +12,11 @@ function is(a, b, msg) {
}
let fullscreenEvents = [];
let iframeDoc;
let iframe, iframeDoc;
function begin() {
iframeDoc = document.querySelector("iframe").contentDocument;
iframe = document.querySelector("iframe");
iframeDoc = iframe.contentDocument;
document.addEventListener("fullscreenchange", evt => {
fullscreenEvents.push(evt);
});
@ -29,9 +30,9 @@ function begin() {
function assertFullscreenEvents(action) {
is(fullscreenEvents.length, 2,
"Two documents should have event dispatched for " + action);
is(fullscreenEvents[0].target, document,
is(fullscreenEvents[0].target, iframe,
"Root document should have the event dispatched first after " + action);
is(fullscreenEvents[1].target, iframeDoc,
is(fullscreenEvents[1].target, iframeDoc.body,
"Inner document should have the event dispatched second after " + action);
}

View File

@ -1021,6 +1021,10 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
controlBar = controls.parentNode.getElementById("controlBar");
}
controlBarShown = controlBar ? !!controlBar.clientHeight : false;
} else {
// There is no controls element. This only happen to UA Widget because
// it is created lazily.
controlBarShown = false;
}
// Determine if we need to compute the display states of the cues. This could

View File

@ -265,6 +265,12 @@ partial interface Element {
void requestFullscreen();
[Throws, BinaryName="requestFullscreen", NeedsCallerType]
void mozRequestFullScreen();
// Events handlers
[Func="nsDocument::IsUnprefixedFullscreenEnabled"]
attribute EventHandler onfullscreenchange;
[Func="nsDocument::IsUnprefixedFullscreenEnabled"]
attribute EventHandler onfullscreenerror;
};
// https://w3c.github.io/pointerlock/#extensions-to-the-element-interface

View File

@ -346,9 +346,11 @@ nsXBLBinding::GenerateAnonymousContent()
point->AppendInsertedChild(child, false);
} else {
NodeInfo *ni = child->NodeInfo();
if (ni->NamespaceID() != kNameSpaceID_XUL ||
(!ni->Equals(nsGkAtoms::_template) &&
!ni->Equals(nsGkAtoms::observes))) {
if (!child->TextIsOnlyWhitespace() &&
(ni->NamespaceID() != kNameSpaceID_XUL ||
(!ni->Equals(nsGkAtoms::_template) &&
!ni->Equals(nsGkAtoms::observes)))
) {
// Compatibility hack. For some reason the original XBL
// implementation dropped the content of a binding if any child of
// the bound element didn't match any of the <children> in the

View File

@ -18,6 +18,7 @@ if CONFIG['MOZ_XUL']:
EXPORTS += [
'nsXULCommandDispatcher.h',
'nsXULElement.h',
'nsXULSortService.h',
]
EXPORTS.mozilla.dom += [
@ -44,7 +45,6 @@ if CONFIG['MOZ_XUL']:
XPIDL_SOURCES += [
'nsIController.idl',
'nsIControllers.idl',
'nsIXULSortService.idl',
]
XPIDL_MODULE = 'xul'

View File

@ -1,42 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
webidl Element;
/**
* A service used to sort the contents of a XUL widget.
*/
[scriptable, uuid(F29270C8-3BE5-4046-9B57-945A84DFF132)]
interface nsIXULSortService : nsISupports
{
const unsigned long SORT_COMPARECASE = 0x0001;
const unsigned long SORT_INTEGER = 0x0100;
/**
* Sort the contents of the widget containing <code>aNode</code>
* using <code>aSortKey</code> as the comparison key, and
* <code>aSortDirection</code> as the direction.
*
* @param aNode A node in the XUL widget whose children are to be sorted.
* @param aSortKey The value to be used as the comparison key.
* @param aSortHints One or more hints as to how to sort:
*
* ascending: to sort the contents in ascending order
* descending: to sort the contents in descending order
* comparecase: perform case sensitive comparisons
* integer: treat values as integers, non-integers are compared as strings
* twostate: don't allow the natural (unordered state)
*/
void sort(in Element aNode,
in AString aSortKey,
in AString aSortHints);
};
%{C++
nsresult
NS_NewXULSortService(nsIXULSortService **result);
%}

View File

@ -7,6 +7,7 @@
This file provides the implementation for the sort service manager.
*/
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsIServiceManager.h"
@ -19,39 +20,63 @@
#include "nsXULSortService.h"
#include "nsXULElement.h"
#include "nsICollation.h"
#include "nsTArray.h"
#include "nsUnicharUtils.h"
NS_IMPL_ISUPPORTS(XULSortServiceImpl, nsIXULSortService)
#include "mozilla/dom/Element.h"
void
XULSortServiceImpl::SetSortHints(Element* aElement, nsSortState* aSortState)
const unsigned long SORT_COMPARECASE = 0x0001;
const unsigned long SORT_INTEGER = 0x0100;
enum nsSortState_direction {
nsSortState_descending,
nsSortState_ascending,
nsSortState_natural
};
// the sort state holds info about the current sort
struct MOZ_STACK_CLASS nsSortState final
{
// set sort and sortDirection attributes when is sort is done
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::sort,
aSortState->sort, true);
bool initialized;
MOZ_INIT_OUTSIDE_CTOR bool invertSort;
nsAutoString direction;
if (aSortState->direction == nsSortState_descending)
direction.AssignLiteral("descending");
else if (aSortState->direction == nsSortState_ascending)
direction.AssignLiteral("ascending");
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
direction, true);
uint32_t sortHints;
// for trees, also set the sort info on the currently sorted column
if (aElement->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
if (aSortState->sortKeys.Length() >= 1) {
nsAutoString sortkey;
aSortState->sortKeys[0]->ToString(sortkey);
SetSortColumnHints(aElement, sortkey, direction);
}
MOZ_INIT_OUTSIDE_CTOR nsSortState_direction direction;
nsAutoString sort;
nsTArray<RefPtr<nsAtom>> sortKeys;
nsCOMPtr<nsIContent> lastContainer;
MOZ_INIT_OUTSIDE_CTOR bool lastWasFirst, lastWasLast;
nsSortState()
: initialized(false),
sortHints(0)
{
}
}
};
void
XULSortServiceImpl::SetSortColumnHints(nsIContent *content,
const nsAString &sortResource,
const nsAString &sortDirection)
// information about a particular item to be sorted
struct contentSortInfo {
nsCOMPtr<nsIContent> content;
nsCOMPtr<nsIContent> parent;
void swap(contentSortInfo& other)
{
content.swap(other.content);
parent.swap(other.parent);
}
};
/**
* Set sortActive and sortDirection attributes on a tree column when a sort
* is done. The column to change is the one with a sort attribute that
* matches the sort key. The sort attributes are removed from the other
* columns.
*/
static void
SetSortColumnHints(nsIContent *content,
const nsAString &sortResource,
const nsAString &sortDirection)
{
// set sort info on current column. This ensures that the
// column header sort indicator is updated properly.
@ -81,15 +106,51 @@ XULSortServiceImpl::SetSortColumnHints(nsIContent *content,
}
}
nsresult
XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
nsSortState* aSortState,
nsTArray<contentSortInfo>& aSortItems)
/**
* Set sort and sortDirection attributes when a sort is done.
*/
static void
SetSortHints(Element* aElement, nsSortState* aSortState)
{
// set sort and sortDirection attributes when is sort is done
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::sort,
aSortState->sort, true);
nsAutoString direction;
if (aSortState->direction == nsSortState_descending)
direction.AssignLiteral("descending");
else if (aSortState->direction == nsSortState_ascending)
direction.AssignLiteral("ascending");
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
direction, true);
// for trees, also set the sort info on the currently sorted column
if (aElement->IsXULElement(nsGkAtoms::tree)) {
if (aSortState->sortKeys.Length() >= 1) {
nsAutoString sortkey;
aSortState->sortKeys[0]->ToString(sortkey);
SetSortColumnHints(aElement, sortkey, direction);
}
}
}
/**
* Determine the list of items which need to be sorted. This is determined
* in the following way:
* - for elements that have a content builder, get its list of generated
* results
* - otherwise, for trees, get the child treeitems
* - otherwise, get the direct children
*/
static nsresult
GetItemsToSort(nsIContent *aContainer,
nsSortState* aSortState,
nsTArray<contentSortInfo>& aSortItems)
{
// Get the children. For trees, get the treechildren element and
// use that as the parent
RefPtr<Element> treechildren;
if (aContainer->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
if (aContainer->IsXULElement(nsGkAtoms::tree)) {
nsXULContentUtils::FindChildByTag(aContainer,
kNameSpaceID_XUL,
nsGkAtoms::treechildren,
@ -113,8 +174,43 @@ XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
return NS_OK;
}
/**
* Compares aLeft and aRight and returns < 0, 0, or > 0. The sort
* hints are checked for case matching and integer sorting.
*/
static int32_t
CompareValues(const nsAString& aLeft,
const nsAString& aRight,
uint32_t aSortHints)
{
if (aSortHints & SORT_INTEGER) {
nsresult err;
int32_t leftint = PromiseFlatString(aLeft).ToInteger(&err);
if (NS_SUCCEEDED(err)) {
int32_t rightint = PromiseFlatString(aRight).ToInteger(&err);
if (NS_SUCCEEDED(err)) {
return leftint - rightint;
}
}
// if they aren't integers, just fall through and compare strings
}
int
if (aSortHints & SORT_COMPARECASE) {
return ::Compare(aLeft, aRight);
}
nsICollation* collation = nsXULContentUtils::GetCollation();
if (collation) {
int32_t result;
collation->CompareString(nsICollation::kCollationCaseInSensitive,
aLeft, aRight, &result);
return result;
}
return ::Compare(aLeft, aRight, nsCaseInsensitiveStringComparator());
}
static int
testSortCallback(const void *data1, const void *data2, void *privateData)
{
/// Note: testSortCallback is a small C callback stub for NS_QuickSort
@ -138,7 +234,7 @@ testSortCallback(const void *data1, const void *data2, void *privateData)
sortState->sortKeys[t], rightstr);
}
sortOrder = XULSortServiceImpl::CompareValues(leftstr, rightstr, sortState->sortHints);
sortOrder = CompareValues(leftstr, rightstr, sortState->sortHints);
}
if (sortState->direction == nsSortState_descending)
@ -147,8 +243,31 @@ testSortCallback(const void *data1, const void *data2, void *privateData)
return sortOrder;
}
nsresult
XULSortServiceImpl::SortContainer(nsIContent *aContainer, nsSortState* aSortState)
/**
* Given a list of sortable items, reverse the list. This is done
* when simply changing the sort direction for the same key.
*/
static nsresult
InvertSortInfo(nsTArray<contentSortInfo>& aData,
int32_t aStart, int32_t aNumItems)
{
if (aNumItems > 1) {
// reverse the items in the array starting from aStart
int32_t upPoint = (aNumItems + 1) / 2 + aStart;
int32_t downPoint = (aNumItems - 2) / 2 + aStart;
int32_t half = aNumItems / 2;
while (half-- > 0) {
aData[downPoint--].swap(aData[upPoint++]);
}
}
return NS_OK;
}
/**
* Sort a container using the supplied sort state details.
*/
static nsresult
SortContainer(nsIContent *aContainer, nsSortState* aSortState)
{
nsTArray<contentSortInfo> items;
nsresult rv = GetItemsToSort(aContainer, aSortState, items);
@ -215,28 +334,22 @@ XULSortServiceImpl::SortContainer(nsIContent *aContainer, nsSortState* aSortStat
return NS_OK;
}
nsresult
XULSortServiceImpl::InvertSortInfo(nsTArray<contentSortInfo>& aData,
int32_t aStart, int32_t aNumItems)
{
if (aNumItems > 1) {
// reverse the items in the array starting from aStart
int32_t upPoint = (aNumItems + 1) / 2 + aStart;
int32_t downPoint = (aNumItems - 2) / 2 + aStart;
int32_t half = aNumItems / 2;
while (half-- > 0) {
aData[downPoint--].swap(aData[upPoint++]);
}
}
return NS_OK;
}
nsresult
XULSortServiceImpl::InitializeSortState(Element* aRootElement,
Element* aContainer,
const nsAString& aSortKey,
const nsAString& aSortHints,
nsSortState* aSortState)
/**
* Initialize sort information from attributes specified on the container,
* the sort key and sort direction.
*
* @param aRootElement the element that contains sort attributes
* @param aContainer the container to sort, usually equal to aRootElement
* @param aSortKey space separated list of sort keys
* @param aSortDirection direction to sort in
* @param aSortState structure filled in with sort data
*/
static nsresult
InitializeSortState(Element* aRootElement,
Element* aContainer,
const nsAString& aSortKey,
const nsAString& aSortHints,
nsSortState* aSortState)
{
// used as an optimization for the content builder
if (aContainer != aSortState->lastContainer.get()) {
@ -263,9 +376,9 @@ XULSortServiceImpl::InitializeSortState(Element* aRootElement,
while (hintsTokenizer.hasMoreTokens()) {
const nsDependentSubstring& token(hintsTokenizer.nextToken());
if (token.EqualsLiteral("comparecase"))
aSortState->sortHints |= nsIXULSortService::SORT_COMPARECASE;
aSortState->sortHints |= SORT_COMPARECASE;
else if (token.EqualsLiteral("integer"))
aSortState->sortHints |= nsIXULSortService::SORT_INTEGER;
aSortState->sortHints |= SORT_INTEGER;
else if (token.EqualsLiteral("descending"))
aSortState->direction = nsSortState_descending;
else if (token.EqualsLiteral("ascending"))
@ -305,42 +418,10 @@ XULSortServiceImpl::InitializeSortState(Element* aRootElement,
return NS_OK;
}
int32_t
XULSortServiceImpl::CompareValues(const nsAString& aLeft,
const nsAString& aRight,
uint32_t aSortHints)
{
if (aSortHints & SORT_INTEGER) {
nsresult err;
int32_t leftint = PromiseFlatString(aLeft).ToInteger(&err);
if (NS_SUCCEEDED(err)) {
int32_t rightint = PromiseFlatString(aRight).ToInteger(&err);
if (NS_SUCCEEDED(err)) {
return leftint - rightint;
}
}
// if they aren't integers, just fall through and compare strings
}
if (aSortHints & SORT_COMPARECASE) {
return ::Compare(aLeft, aRight);
}
nsICollation* collation = nsXULContentUtils::GetCollation();
if (collation) {
int32_t result;
collation->CompareString(nsICollation::kCollationCaseInSensitive,
aLeft, aRight, &result);
return result;
}
return ::Compare(aLeft, aRight, nsCaseInsensitiveStringComparator());
}
NS_IMETHODIMP
XULSortServiceImpl::Sort(Element* aNode,
const nsAString& aSortKey,
const nsAString& aSortHints)
nsresult
mozilla::XULWidgetSort(Element* aNode,
const nsAString& aSortKey,
const nsAString& aSortHints)
{
nsSortState sortState;
nsresult rv = InitializeSortState(aNode, aNode,
@ -353,11 +434,3 @@ XULSortServiceImpl::Sort(Element* aNode,
return rv;
}
nsresult
NS_NewXULSortService(nsIXULSortService** sortService)
{
*sortService = new XULSortServiceImpl();
NS_ADDREF(*sortService);
return NS_OK;
}

View File

@ -10,146 +10,34 @@
#ifndef nsXULSortService_h
#define nsXULSortService_h
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsIContent.h"
#include "nsIXULSortService.h"
#include "nsCycleCollectionParticipant.h"
#include "nsAString.h"
#include "nsError.h"
enum nsSortState_direction {
nsSortState_descending,
nsSortState_ascending,
nsSortState_natural
};
namespace mozilla {
// the sort state holds info about the current sort
struct nsSortState
{
bool initialized;
MOZ_INIT_OUTSIDE_CTOR bool invertSort;
namespace dom {
class Element;
} // namespace dom
uint32_t sortHints;
/**
* Sort the contents of the widget containing <code>aNode</code>
* using <code>aSortKey</code> as the comparison key, and
* <code>aSortDirection</code> as the direction.
*
* @param aNode A node in the XUL widget whose children are to be sorted.
* @param aSortKey The value to be used as the comparison key.
* @param aSortHints One or more hints as to how to sort:
*
* ascending: to sort the contents in ascending order
* descending: to sort the contents in descending order
* comparecase: perform case sensitive comparisons
* integer: treat values as integers, non-integers are compared as strings
* twostate: don't allow the natural (unordered state)
*/
nsresult XULWidgetSort(dom::Element* aNode,
const nsAString& aSortKey,
const nsAString& aSortHints);
MOZ_INIT_OUTSIDE_CTOR nsSortState_direction direction;
nsAutoString sort;
nsTArray<RefPtr<nsAtom>> sortKeys;
nsCOMPtr<nsIContent> lastContainer;
MOZ_INIT_OUTSIDE_CTOR bool lastWasFirst, lastWasLast;
nsSortState()
: initialized(false),
sortHints(0)
{
}
void Traverse(nsCycleCollectionTraversalCallback &cb) const
{
cb.NoteXPCOMChild(lastContainer);
}
};
// information about a particular item to be sorted
struct contentSortInfo {
nsCOMPtr<nsIContent> content;
nsCOMPtr<nsIContent> parent;
void swap(contentSortInfo& other)
{
content.swap(other.content);
parent.swap(other.parent);
}
};
////////////////////////////////////////////////////////////////////////
// ServiceImpl
//
// This is the sort service.
//
class XULSortServiceImpl : public nsIXULSortService
{
protected:
XULSortServiceImpl(void) {}
virtual ~XULSortServiceImpl(void) {}
friend nsresult NS_NewXULSortService(nsIXULSortService** mgr);
private:
public:
// nsISupports
NS_DECL_ISUPPORTS
// nsISortService
NS_DECL_NSIXULSORTSERVICE
/**
* Set sort and sortDirection attributes when a sort is done.
*/
void
SetSortHints(mozilla::dom::Element* aElement, nsSortState* aSortState);
/**
* Set sortActive and sortDirection attributes on a tree column when a sort
* is done. The column to change is the one with a sort attribute that
* matches the sort key. The sort attributes are removed from the other
* columns.
*/
void
SetSortColumnHints(nsIContent *content,
const nsAString &sortResource,
const nsAString &sortDirection);
/**
* Determine the list of items which need to be sorted. This is determined
* in the following way:
* - for elements that have a content builder, get its list of generated
* results
* - otherwise, for trees, get the child treeitems
* - otherwise, get the direct children
*/
nsresult
GetItemsToSort(nsIContent *aContainer,
nsSortState* aSortState,
nsTArray<contentSortInfo>& aSortItems);
/**
* Sort a container using the supplied sort state details.
*/
nsresult
SortContainer(nsIContent *aContainer, nsSortState* aSortState);
/**
* Given a list of sortable items, reverse the list. This is done
* when simply changing the sort direction for the same key.
*/
nsresult
InvertSortInfo(nsTArray<contentSortInfo>& aData,
int32_t aStart, int32_t aNumItems);
/**
* Initialize sort information from attributes specified on the container,
* the sort key and sort direction.
*
* @param aRootElement the element that contains sort attributes
* @param aContainer the container to sort, usually equal to aRootElement
* @param aSortKey space separated list of sort keys
* @param aSortDirection direction to sort in
* @param aSortState structure filled in with sort data
*/
static nsresult
InitializeSortState(mozilla::dom::Element* aRootElement,
mozilla::dom::Element* aContainer,
const nsAString& aSortKey,
const nsAString& aSortDirection,
nsSortState* aSortState);
/**
* Compares aLeft and aRight and returns < 0, 0, or > 0. The sort
* hints are checked for case matching and integer sorting.
*/
static int32_t CompareValues(const nsAString& aLeft,
const nsAString& aRight,
uint32_t aSortHints);
};
} // namespace mozilla
#endif // nsXULSortService_h

View File

@ -1,3 +1,22 @@
Overview of changes leading to 1.9.0
Monday, September 10, 2018
====================================
- Added 'cmap' API to hb_face_t.
- Face-builder API.
- hb-ot-font re-creation should be much leaner now, as the
font tables it uses are cached on hb_face_t now.
- Internal source header file name changes:
hb-*-private.hh is renamed to hb-*.hh.
New API:
+HB_UNICODE_MAX
+hb_face_collect_unicodes()
+hb_face_collect_variation_selectors()
+hb_face_collect_variation_unicodes()
+hb_face_builder_create()
+hb_face_builder_add_table()
Overview of changes leading to 1.8.8
Tuesday, August 14, 2018
====================================

View File

@ -1,7 +1,7 @@
This directory contains the HarfBuzz source from the upstream repo:
https://github.com/harfbuzz/harfbuzz
Current version: 1.8.8 [commit 63be5dcdde61275822d931b2924425478bc1dac1]
Current version: 1.9.0 [commit 54d332dd9b0263821376161cdffb60ffb3c7847f]
UPDATING:

View File

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[1.8.8],
[1.9.0],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])

View File

@ -1,28 +1,28 @@
# Base and default-included sources and headers
HB_BASE_sources = \
hb-atomic-private.hh \
hb-blob-private.hh \
hb-atomic.hh \
hb-blob.hh \
hb-blob.cc \
hb-buffer-private.hh \
hb-buffer.hh \
hb-buffer-serialize.cc \
hb-buffer.cc \
hb-common.cc \
hb-debug.hh \
hb-dsalgs.hh \
hb-face-private.hh \
hb-face.hh \
hb-face.cc \
hb-font-private.hh \
hb-font.hh \
hb-font.cc \
hb-iter-private.hh \
hb-map-private.hh \
hb-iter.hh \
hb-map.hh \
hb-map.cc \
hb-machinery-private.hh \
hb-mutex-private.hh \
hb-machinery.hh \
hb-mutex.hh \
hb-null.hh \
hb-object-private.hh \
hb-open-file-private.hh \
hb-open-type-private.hh \
hb-object.hh \
hb-open-file.hh \
hb-open-type.hh \
hb-ot-color-cbdt-table.hh \
hb-ot-cmap-table.hh \
hb-ot-glyf-table.hh \
@ -38,23 +38,23 @@ HB_BASE_sources = \
hb-ot-post-macroman.hh \
hb-ot-post-table.hh \
hb-ot-tag.cc \
hb-private.hh \
hb-set-digest-private.hh \
hb-set-private.hh \
hb.hh \
hb-set-digest.hh \
hb-set.hh \
hb-set.cc \
hb-shape.cc \
hb-shape-plan-private.hh \
hb-shape-plan.hh \
hb-shape-plan.cc \
hb-shaper-list.hh \
hb-shaper-impl-private.hh \
hb-shaper-private.hh \
hb-shaper-impl.hh \
hb-shaper.hh \
hb-shaper.cc \
hb-static.cc \
hb-string-array.hh \
hb-unicode-private.hh \
hb-unicode.hh \
hb-unicode.cc \
hb-vector-private.hh \
hb-utf-private.hh \
hb-vector.hh \
hb-utf.hh \
hb-warning.cc \
$(NULL)
@ -89,61 +89,63 @@ HB_FALLBACK_sources = \
HB_OT_sources = \
hb-aat-layout.cc \
hb-aat-layout-common-private.hh \
hb-aat-layout-common.hh \
hb-aat-layout-ankr-table.hh \
hb-aat-layout-bsln-table.hh \
hb-aat-layout-feat-table.hh \
hb-aat-layout-kerx-table.hh \
hb-aat-layout-morx-table.hh \
hb-aat-layout-trak-table.hh \
hb-aat-layout-private.hh \
hb-aat-layout.hh \
hb-aat-ltag-table.hh \
hb-ot-face.hh \
hb-ot-face.cc \
hb-ot-font.cc \
hb-ot-layout.cc \
hb-ot-layout-base-table.hh \
hb-ot-layout-common-private.hh \
hb-ot-layout-common.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
hb-ot-layout-gsubgpos-private.hh \
hb-ot-layout-gsubgpos.hh \
hb-ot-layout-gsub-table.hh \
hb-ot-layout-jstf-table.hh \
hb-ot-layout-private.hh \
hb-ot-layout.hh \
hb-ot-color.cc \
hb-ot-color-colr-table.hh \
hb-ot-color-cpal-table.hh \
hb-ot-color-sbix-table.hh \
hb-ot-color-svg-table.hh \
hb-ot-map.cc \
hb-ot-map-private.hh \
hb-ot-map.hh \
hb-ot-math.cc \
hb-ot-math-table.hh \
hb-ot-shape.cc \
hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-arabic-fallback.hh \
hb-ot-shape-complex-arabic-private.hh \
hb-ot-shape-complex-arabic.hh \
hb-ot-shape-complex-arabic-table.hh \
hb-ot-shape-complex-arabic-win1256.hh \
hb-ot-shape-complex-default.cc \
hb-ot-shape-complex-hangul.cc \
hb-ot-shape-complex-hebrew.cc \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-indic-private.hh \
hb-ot-shape-complex-indic.hh \
hb-ot-shape-complex-indic-table.cc \
hb-ot-shape-complex-khmer-private.hh \
hb-ot-shape-complex-khmer.hh \
hb-ot-shape-complex-khmer.cc \
hb-ot-shape-complex-myanmar-private.hh \
hb-ot-shape-complex-myanmar.hh \
hb-ot-shape-complex-myanmar.cc \
hb-ot-shape-complex-thai.cc \
hb-ot-shape-complex-tibetan.cc \
hb-ot-shape-complex-use.cc \
hb-ot-shape-complex-use-private.hh \
hb-ot-shape-complex-use.hh \
hb-ot-shape-complex-use-table.cc \
hb-ot-shape-complex-private.hh \
hb-ot-shape-normalize-private.hh \
hb-ot-shape-complex.hh \
hb-ot-shape-normalize.hh \
hb-ot-shape-normalize.cc \
hb-ot-shape-fallback-private.hh \
hb-ot-shape-fallback.hh \
hb-ot-shape-fallback.cc \
hb-ot-shape-private.hh \
hb-ot-shape.hh \
hb-ot-var.cc \
hb-ot-var-avar-table.hh \
hb-ot-var-fvar-table.hh \
@ -207,16 +209,17 @@ HB_ICU_headers = hb-icu.h
HB_SUBSET_sources = \
hb-static.cc \
hb-subset.cc \
hb-subset.hh \
hb-subset-glyf.cc \
hb-subset-glyf.hh \
hb-subset-input.cc \
hb-subset-input.hh \
hb-subset-plan.cc \
hb-subset-plan.hh \
$(NULL)
HB_SUBSET_headers = \
hb-subset.h \
hb-subset-glyf.hh \
hb-subset-plan.hh \
hb-subset-private.hh \
$(NULL)
HB_GOBJECT_DIST_sources = hb-gobject-structs.cc

View File

@ -23,14 +23,14 @@ grep -v 'hb[.]h:' |
grep . >&2 && stat=1
echo 'Checking that source files #include "hb-*private.hh" first (or none)'
echo 'Checking that source files #include a private header first (or none)'
for x in $HBSOURCES; do
test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1
grep '#.*\<include\>' "$x" /dev/null | head -n 1
done |
grep -v '"hb-.*private[.]hh"' |
grep -v 'hb-private[.]hh:' |
grep -v '"hb-.*[.]hh"' |
grep -v 'hb[.]hh' |
grep . >&2 && stat=1

View File

@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-indic-private.hh"
#include "hb-ot-shape-complex-indic.hh"
int
main (void)

View File

@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-khmer-private.hh"
#include "hb-ot-shape-complex-khmer.hh"
int
main (void)

View File

@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-myanmar-private.hh"
#include "hb-ot-shape-complex-myanmar.hh"
int
main (void)

View File

@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-use-private.hh"
#include "hb-ot-shape-complex-use.hh"
int
main (void)

View File

@ -102,7 +102,7 @@ for h in headers:
print (" * %s" % (l.strip()))
print (" */")
print ()
print ('#include "hb-ot-shape-complex-indic-private.hh"')
print ('#include "hb-ot-shape-complex-indic.hh"')
print ()
# Shorten values

View File

@ -394,7 +394,7 @@ for h in headers:
print (" * %s" % (l.strip()))
print (" */")
print ()
print ('#include "hb-ot-shape-complex-use-private.hh"')
print ('#include "hb-ot-shape-complex-use.hh"')
print ()
total = 0

View File

@ -25,7 +25,7 @@
#ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH
#define HB_AAT_LAYOUT_ANKR_TABLE_HH
#include "hb-aat-layout-common-private.hh"
#include "hb-aat-layout-common.hh"
/*
* ankr -- Anchor Point

View File

@ -25,7 +25,7 @@
#ifndef HB_AAT_LAYOUT_BSLN_TABLE_HH
#define HB_AAT_LAYOUT_BSLN_TABLE_HH
#include "hb-aat-layout-common-private.hh"
#include "hb-aat-layout-common.hh"
/*
* bsln -- Baseline

View File

@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_COMMON_PRIVATE_HH
#define HB_AAT_LAYOUT_COMMON_PRIVATE_HH
#ifndef HB_AAT_LAYOUT_COMMON_HH
#define HB_AAT_LAYOUT_COMMON_HH
#include "hb-aat-layout-private.hh"
#include "hb-aat-layout.hh"
namespace AAT {
@ -641,4 +641,4 @@ struct hb_aat_apply_context_t :
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */
#endif /* HB_AAT_LAYOUT_COMMON_HH */

View File

@ -25,7 +25,7 @@
#ifndef HB_AAT_LAYOUT_FEAT_TABLE_HH
#define HB_AAT_LAYOUT_FEAT_TABLE_HH
#include "hb-aat-layout-common-private.hh"
#include "hb-aat-layout-common.hh"
/*
* feat -- Feature Name

View File

@ -28,8 +28,8 @@
#ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
#define HB_AAT_LAYOUT_KERX_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-aat-layout-common-private.hh"
#include "hb-open-type.hh"
#include "hb-aat-layout-common.hh"
#include "hb-aat-layout-ankr-table.hh"
/*

View File

@ -27,9 +27,9 @@
#ifndef HB_AAT_LAYOUT_MORX_TABLE_HH
#define HB_AAT_LAYOUT_MORX_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-aat-layout-common-private.hh"
#include "hb-ot-layout-common-private.hh"
#include "hb-open-type.hh"
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout-common.hh"
/*
* morx -- Extended Glyph Metamorphosis

View File

@ -28,9 +28,9 @@
#ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH
#define HB_AAT_LAYOUT_TRAK_TABLE_HH
#include "hb-aat-layout-common-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-open-type-private.hh"
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
/*
* trak -- Tracking

View File

@ -24,12 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
#include "hb-ot-layout-private.hh"
#include "hb-ot-layout-gsubgpos-private.hh"
#include "hb-aat-layout-private.hh"
#include "hb-ot-face.hh"
#include "hb-aat-layout.hh"
#include "hb-aat-layout-ankr-table.hh"
#include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-feat-table.hh" // Just so we compile it; unused otherwise.
@ -51,25 +49,12 @@ _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
*blob = hb_blob_get_empty ();
return Null(AAT::morx);
}
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
const AAT::morx& morx = *(layout->table.morx.get ());
const AAT::morx& morx = *(hb_ot_face_data (face)->morx.get ());
if (blob)
*blob = layout->table.morx.get_blob ();
*blob = hb_ot_face_data (face)->morx.get_blob ();
return morx;
}
// static inline void
// _hb_aat_layout_create (hb_face_t *face)
// {
// hb_blob_t *morx_blob = hb_sanitize_context_t ().reference_table<AAT::morx> (face);
// morx_blob->as<AAT::morx> ();
// if (0)
// {
// morx_blob->as<AAT::Lookup<OT::GlyphID> > ()->get_value (1, face->get_num_glyphs ());
// }
// }
void
hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
{

View File

@ -24,14 +24,14 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_PRIVATE_HH
#define HB_AAT_LAYOUT_PRIVATE_HH
#ifndef HB_AAT_LAYOUT_HH
#define HB_AAT_LAYOUT_HH
#include "hb-private.hh"
#include "hb.hh"
#include "hb-font-private.hh"
#include "hb-buffer-private.hh"
#include "hb-open-type-private.hh"
#include "hb-font.hh"
#include "hb-buffer.hh"
#include "hb-open-type.hh"
HB_INTERNAL void
@ -40,4 +40,4 @@ hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer);
#endif /* HB_AAT_LAYOUT_PRIVATE_HH */
#endif /* HB_AAT_LAYOUT_HH */

View File

@ -25,7 +25,7 @@
#ifndef HB_AAT_LTAG_TABLE_HH
#define HB_AAT_LTAG_TABLE_HH
#include "hb-aat-layout-common-private.hh"
#include "hb-aat-layout-common.hh"
/*
* ltag -- Language Tag

View File

@ -29,10 +29,10 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_ATOMIC_PRIVATE_HH
#define HB_ATOMIC_PRIVATE_HH
#ifndef HB_ATOMIC_HH
#define HB_ATOMIC_HH
#include "hb-private.hh"
#include "hb.hh"
/*
@ -98,7 +98,7 @@ static inline void _hb_memory_barrier (void)
{
#if !defined(MemoryBarrier)
/* MinGW has a convoluted history of supporting MemoryBarrier. */
long dummy = 0;
LONG dummy = 0;
InterlockedExchange (&dummy, 1);
#else
MemoryBarrier ();
@ -106,7 +106,8 @@ static inline void _hb_memory_barrier (void)
}
#define _hb_memory_barrier() _hb_memory_barrier ()
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((unsigned *) (AI), (V))
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V))
static_assert ((sizeof (LONG) == sizeof (int)), "");
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
@ -278,4 +279,4 @@ struct hb_atomic_ptr_t
};
#endif /* HB_ATOMIC_PRIVATE_HH */
#endif /* HB_ATOMIC_HH */

View File

@ -30,8 +30,8 @@
#define _POSIX_C_SOURCE 200809L
#endif
#include "hb-private.hh"
#include "hb-blob-private.hh"
#include "hb.hh"
#include "hb-blob.hh"
#ifdef HAVE_SYS_MMAN_H
#ifdef HAVE_UNISTD_H

View File

@ -26,10 +26,10 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BLOB_PRIVATE_HH
#define HB_BLOB_PRIVATE_HH
#ifndef HB_BLOB_HH
#define HB_BLOB_HH
#include "hb-private.hh"
#include "hb.hh"
/*
@ -62,6 +62,10 @@ struct hb_blob_t
{
return unlikely (!data) ? &Null(Type) : reinterpret_cast<const Type *> (data);
}
inline hb_bytes_t as_bytes (void) const
{
return hb_bytes_t (data, length);
}
public:
hb_object_header_t header;
@ -79,4 +83,4 @@ struct hb_blob_t
DECLARE_NULL_INSTANCE (hb_blob_t);
#endif /* HB_BLOB_PRIVATE_HH */
#endif /* HB_BLOB_HH */

View File

@ -29,7 +29,7 @@
#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
#define HB_BUFFER_DESERIALIZE_JSON_HH
#include "hb-private.hh"
#include "hb.hh"
#line 36 "hb-buffer-deserialize-json.hh"

View File

@ -27,7 +27,7 @@
#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
#define HB_BUFFER_DESERIALIZE_JSON_HH
#include "hb-private.hh"
#include "hb.hh"
%%{

View File

@ -29,7 +29,7 @@
#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
#define HB_BUFFER_DESERIALIZE_TEXT_HH
#include "hb-private.hh"
#include "hb.hh"
#line 36 "hb-buffer-deserialize-text.hh"

View File

@ -27,7 +27,7 @@
#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
#define HB_BUFFER_DESERIALIZE_TEXT_HH
#include "hb-private.hh"
#include "hb.hh"
%%{

View File

@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-buffer-private.hh"
#include "hb-buffer.hh"
static const char *serialize_formats[] = {

View File

@ -27,8 +27,8 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-buffer-private.hh"
#include "hb-utf-private.hh"
#include "hb-buffer.hh"
#include "hb-utf.hh"
/**

View File

@ -27,11 +27,11 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BUFFER_PRIVATE_HH
#define HB_BUFFER_PRIVATE_HH
#ifndef HB_BUFFER_HH
#define HB_BUFFER_HH
#include "hb-private.hh"
#include "hb-unicode-private.hh"
#include "hb.hh"
#include "hb-unicode.hh"
#ifndef HB_BUFFER_MAX_LEN_FACTOR
@ -119,7 +119,7 @@ struct hb_buffer_t
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
static const unsigned int CONTEXT_LENGTH = 5;
enum { CONTEXT_LENGTH = 5 };
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
@ -386,4 +386,4 @@ _next_cluster (hb_buffer_t *buffer, unsigned int start)
#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ())
#endif /* HB_BUFFER_PRIVATE_HH */
#endif /* HB_BUFFER_HH */

View File

@ -26,9 +26,9 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb.hh"
#include "hb-machinery-private.hh"
#include "hb-machinery.hh"
#include <locale.h>
#ifdef HAVE_XLOCALE_H
@ -731,8 +731,9 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv)
#ifdef USE_XLOCALE
#ifdef HB_USE_ATEXIT
static void free_static_C_locale (void);
#endif
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<HB_LOCALE_T>::value,
hb_C_locale_lazy_loader_t>

View File

@ -28,8 +28,8 @@
#define HB_SHAPER coretext
#include "hb-private.hh"
#include "hb-shaper-impl-private.hh"
#include "hb.hh"
#include "hb-shaper-impl.hh"
#include "hb-coretext.h"
#include <math.h>

View File

@ -27,8 +27,8 @@
#ifndef HB_DEBUG_HH
#define HB_DEBUG_HH
#include "hb-private.hh"
#include "hb-atomic-private.hh"
#include "hb.hh"
#include "hb-atomic.hh"
#include "hb-dsalgs.hh"

View File

@ -22,9 +22,9 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#include "hb-private.hh"
#include "hb.hh"
#define HB_SHAPER directwrite
#include "hb-shaper-impl-private.hh"
#include "hb-shaper-impl.hh"
#include <DWrite_1.h>

View File

@ -27,7 +27,7 @@
#ifndef HB_DSALGS_HH
#define HB_DSALGS_HH
#include "hb-private.hh"
#include "hb.hh"
/* Void! For when we need a expression-type of void. */
@ -492,6 +492,15 @@ template <typename Type>
struct hb_auto_t : Type
{
hb_auto_t (void) { Type::init (); }
/* Explicitly allow the following only for pointer and references,
* to avoid any accidental copies.
*
* Apparently if we template for all types, then gcc seems to
* capture a reference argument in the type, but clang doesn't,
* causing unwanted copies and bugs that come with it. Ideally
* we should use C++11-style rvalue reference &&t1. */
template <typename T1> explicit hb_auto_t (T1 *t1) { Type::init (t1); }
template <typename T1> explicit hb_auto_t (T1 &t1) { Type::init (t1); }
~hb_auto_t (void) { Type::fini (); }
private: /* Hide */
void init (void) {}
@ -502,6 +511,9 @@ struct hb_bytes_t
{
inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
inline hb_bytes_t (const void *bytes_, unsigned int len_) : bytes ((const char *) bytes_), len (len_) {}
inline void free (void) { ::free ((void *) bytes); bytes = nullptr; len = 0; }
inline int cmp (const hb_bytes_t &a) const
{

View File

@ -26,11 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb.hh"
#include "hb-face-private.hh"
#include "hb-blob-private.hh"
#include "hb-open-file-private.hh"
#include "hb-face.hh"
#include "hb-blob.hh"
#include "hb-open-file.hh"
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
/**
@ -512,3 +514,208 @@ hb_face_get_table_tags (const hb_face_t *face,
return ot_face.get_table_tags (start_offset, table_count, table_tags);
}
/*
* Character set.
*/
/**
* hb_face_collect_unicodes:
* @face: font face.
* @out: set to add Unicode characters covered by @face to.
*
* Since: 1.9.0
*/
void
hb_face_collect_unicodes (hb_face_t *face,
hb_set_t *out)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
hb_ot_face_data (face)->cmap->collect_unicodes (out);
}
/**
* hb_face_collect_variation_selectors:
* @face: font face.
* @out: set to add Variation Selector characters covered by @face to.
*
*
*
* Since: 1.9.0
*/
void
hb_face_collect_variation_selectors (hb_face_t *face,
hb_set_t *out)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
hb_ot_face_data (face)->cmap->collect_variation_selectors (out);
}
/**
* hb_face_collect_variation_unicodes:
* @face: font face.
* @out: set to add Unicode characters for @variation_selector covered by @face to.
*
*
*
* Since: 1.9.0
*/
void
hb_face_collect_variation_unicodes (hb_face_t *face,
hb_codepoint_t variation_selector,
hb_set_t *out)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
hb_ot_face_data (face)->cmap->collect_variation_unicodes (variation_selector, out);
}
/*
* face-builder: A face that has add_table().
*/
struct hb_face_builder_data_t
{
struct table_entry_t
{
inline int cmp (const hb_tag_t *t) const
{
if (*t < tag) return -1;
if (*t > tag) return -1;
return 0;
}
hb_tag_t tag;
hb_blob_t *blob;
};
hb_vector_t<table_entry_t, 32> tables;
};
static hb_face_builder_data_t *
_hb_face_builder_data_create (void)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
if (unlikely (!data))
return nullptr;
data->tables.init ();
return data;
}
static void
_hb_face_builder_data_destroy (void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
for (unsigned int i = 0; i < data->tables.len; i++)
hb_blob_destroy (data->tables[i].blob);
data->tables.fini ();
free (data);
}
static hb_blob_t *
_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
{
unsigned int table_count = data->tables.len;
unsigned int face_length = table_count * 16 + 12;
for (unsigned int i = 0; i < table_count; i++)
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
char *buf = (char *) malloc (face_length);
if (unlikely (!buf))
return nullptr;
hb_serialize_context_t c (buf, face_length);
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
bool ret = f->serialize_single (&c,
sfnt_tag,
tags_supplier,
blobs_supplier,
table_count);
c.end_serialize ();
if (unlikely (!ret))
{
free (buf);
return nullptr;
}
return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
}
static hb_blob_t *
_hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
if (!tag)
return _hb_face_builder_data_reference_blob (data);
hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
if (entry)
return hb_blob_reference (entry->blob);
return nullptr;
}
/**
* hb_face_builder_create:
*
* Creates a #hb_face_t that can be used with hb_face_builder_add_table().
* After tables are added to the face, it can be compiled to a binary
* font file by calling hb_face_reference_blob().
*
* Return value: (transfer full) New face.
*
* Since: 1.9.0
**/
hb_face_t *
hb_face_builder_create (void)
{
hb_face_builder_data_t *data = _hb_face_builder_data_create ();
if (unlikely (!data)) return hb_face_get_empty ();
return hb_face_create_for_tables (_hb_face_builder_reference_table,
data,
_hb_face_builder_data_destroy);
}
/**
* hb_face_builder_add_table:
*
* Add table for @tag with data provided by @blob to the face. @face must
* be created using hb_face_builder_create().
*
* Since: 1.9.0
**/
hb_bool_t
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
{
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return false;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
entry->tag = tag;
entry->blob = hb_blob_reference (blob);
return true;
}

View File

@ -33,6 +33,7 @@
#include "hb-common.h"
#include "hb-blob.h"
#include "hb-set.h"
HB_BEGIN_DECLS
@ -120,6 +121,38 @@ hb_face_get_table_tags (const hb_face_t *face,
unsigned int *table_count, /* IN/OUT */
hb_tag_t *table_tags /* OUT */);
/*
* Character set.
*/
HB_EXTERN void
hb_face_collect_unicodes (hb_face_t *face,
hb_set_t *out);
HB_EXTERN void
hb_face_collect_variation_selectors (hb_face_t *face,
hb_set_t *out);
HB_EXTERN void
hb_face_collect_variation_unicodes (hb_face_t *face,
hb_codepoint_t variation_selector,
hb_set_t *out);
/*
* Builder face.
*/
HB_EXTERN hb_face_t *
hb_face_builder_create (void);
HB_EXTERN hb_bool_t
hb_face_builder_add_table (hb_face_t *face,
hb_tag_t tag,
hb_blob_t *blob);
HB_END_DECLS
#endif /* HB_FACE_H */

View File

@ -26,13 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_FACE_PRIVATE_HH
#define HB_FACE_PRIVATE_HH
#ifndef HB_FACE_HH
#define HB_FACE_HH
#include "hb-private.hh"
#include "hb.hh"
#include "hb-shaper-private.hh"
#include "hb-shape-plan-private.hh"
#include "hb-shaper.hh"
#include "hb-shape-plan.hh"
/*
@ -105,4 +105,4 @@ DECLARE_NULL_INSTANCE (hb_face_t);
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#endif /* HB_FACE_PRIVATE_HH */
#endif /* HB_FACE_HH */

View File

@ -25,7 +25,7 @@
*/
#define HB_SHAPER fallback
#include "hb-shaper-impl-private.hh"
#include "hb-shaper-impl.hh"
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face)

View File

@ -26,10 +26,10 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb.hh"
#include "hb-font-private.hh"
#include "hb-machinery-private.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
/*

View File

@ -26,13 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_FONT_PRIVATE_HH
#define HB_FONT_PRIVATE_HH
#ifndef HB_FONT_HH
#define HB_FONT_HH
#include "hb-private.hh"
#include "hb.hh"
#include "hb-face-private.hh"
#include "hb-shaper-private.hh"
#include "hb-face.hh"
#include "hb-shaper.hh"
/*
@ -601,4 +601,4 @@ DECLARE_NULL_INSTANCE (hb_font_t);
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#endif /* HB_FONT_PRIVATE_HH */
#endif /* HB_FONT_HH */

View File

@ -27,12 +27,12 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb.hh"
#include "hb-ft.h"
#include "hb-font-private.hh"
#include "hb-machinery-private.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
@ -417,7 +417,9 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
return true;
}
#ifdef HB_USE_ATEXIT
static void free_static_ft_funcs (void);
#endif
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
{
@ -682,8 +684,9 @@ hb_ft_font_create_referenced (FT_Face ft_face)
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
#ifdef HB_USE_ATEXIT
static void free_static_ft_library (void);
#endif
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<FT_Library>::value,
hb_ft_library_lazy_loader_t>

View File

@ -26,12 +26,12 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb.hh"
#include "hb-glib.h"
#include "hb-unicode-private.hh"
#include "hb-machinery-private.hh"
#include "hb-unicode.hh"
#include "hb-machinery.hh"
#if !GLIB_CHECK_VERSION(2,29,14)
@ -366,8 +366,9 @@ hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
#ifdef HB_USE_ATEXIT
static void free_static_glib_funcs (void);
#endif
static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
{

View File

@ -25,7 +25,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb.hh"
/* g++ didn't like older gtype.h gcc-only code path. */
#include <glib.h>

View File

@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb.hh"
/* g++ didn't like older gtype.h gcc-only code path. */
#include <glib.h>

View File

@ -27,7 +27,7 @@
*/
#define HB_SHAPER graphite2
#include "hb-shaper-impl-private.hh"
#include "hb-shaper-impl.hh"
#include "hb-graphite2.h"

View File

@ -27,12 +27,12 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb.hh"
#include "hb-icu.h"
#include "hb-unicode-private.hh"
#include "hb-machinery-private.hh"
#include "hb-unicode.hh"
#include "hb-machinery.hh"
#include <unicode/uchar.h>
#include <unicode/unorm2.h>
@ -343,8 +343,9 @@ hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return utf32_len;
}
#ifdef HB_USE_ATEXIT
static void free_static_icu_funcs (void);
#endif
static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
{

View File

@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_ITER_PRIVATE_HH
#define HB_ITER_PRIVATE_HH
#ifndef HB_ITER_HH
#define HB_ITER_HH
#include "hb-private.hh"
#include "hb.hh"
/* Unified iterator object.
@ -146,4 +146,4 @@ m (void)
}
}
#endif /* HB_ITER_PRIVATE_HH */
#endif /* HB_ITER_HH */

View File

@ -26,13 +26,14 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_MACHINERY_PRIVATE_HH
#define HB_MACHINERY_PRIVATE_HH
#ifndef HB_MACHINERY_HH
#define HB_MACHINERY_HH
#include "hb-private.hh"
#include "hb-blob-private.hh"
#include "hb.hh"
#include "hb-blob.hh"
#include "hb-iter-private.hh"
#include "hb-iter.hh"
#include "hb-vector.hh"
/*
@ -98,8 +99,8 @@ static inline Type& StructAfter(TObject &X)
#define DEFINE_SIZE_STATIC(size) \
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
static const unsigned int static_size = (size); \
static const unsigned int min_size = (size); \
enum { static_size = (size) }; \
enum { min_size = (size) }; \
inline unsigned int get_size (void) const { return (size); }
#define DEFINE_SIZE_UNION(size, _member) \
@ -111,9 +112,13 @@ static inline Type& StructAfter(TObject &X)
static const unsigned int min_size = (size)
#define DEFINE_SIZE_ARRAY(size, array) \
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof (array[0])); \
DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
static const unsigned int min_size = (size)
enum { min_size = (size) }; \
#define DEFINE_SIZE_ARRAY_SIZED(size, array) \
DEFINE_SIZE_ARRAY(size, array); \
inline unsigned int get_size (void) const { return (size - array[0].min_size + array.get_size ()); }
#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
@ -128,7 +133,7 @@ static inline Type& StructAfter(TObject &X)
template <typename Context, typename Return, unsigned int MaxDebugDepth>
struct hb_dispatch_context_t
{
static const unsigned int max_debug_depth = MaxDebugDepth;
enum { max_debug_depth = MaxDebugDepth };
typedef Return return_t;
template <typename T, typename F>
inline bool may_dispatch (const T *obj, const F *format) { return true; }
@ -138,6 +143,68 @@ struct hb_dispatch_context_t
/*
* Sanitize
*
*
* === Introduction ===
*
* The sanitize machinery is at the core of our zero-cost font loading. We
* mmap() font file into memory and create a blob out of it. Font subtables
* are returned as a readonly sub-blob of the main font blob. These table
* blobs are then sanitized before use, to ensure invalid memory access does
* not happen. The toplevel sanitize API use is like, eg. to load the 'head'
* table:
*
* hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face);
*
* The blob then can be converted to a head table struct with:
*
* const head *head_table = head_blob->as<head> ();
*
* What the reference_table does is, to call hb_face_reference_table() to load
* the table blob, sanitize it and return either the sanitized blob, or empty
* blob if sanitization failed. The blob->as() function returns the null
* object of its template type argument if the blob is empty. Otherwise, it
* just casts the blob contents to the desired type.
*
* Sanitizing a blob of data with a type T works as follows (with minor
* simplification):
*
* - Cast blob content to T*, call sanitize() method of it,
* - If sanitize succeeded, return blob.
* - Otherwise, if blob is not writable, try making it writable,
* or copy if cannot be made writable in-place,
* - Call sanitize() again. Return blob if sanitize succeeded.
* - Return empty blob otherwise.
*
*
* === The sanitize() contract ===
*
* The sanitize() method of each object type shall return true if it's safe to
* call other methods of the object, and false otherwise.
*
* Note that what sanitize() checks for might align with what the specification
* describes as valid table data, but does not have to be. In particular, we
* do NOT want to be pedantic and concern ourselves with validity checks that
* are irrelevant to our use of the table. On the contrary, we want to be
* lenient with error handling and accept invalid data to the extent that it
* does not impose extra burden on us.
*
* Based on the sanitize contract, one can see that what we check for depends
* on how we use the data in other table methods. Ie. if other table methods
* assume that offsets do NOT point out of the table data block, then that's
* something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way). On
* the other hand, if other methods do such checks themselves, then sanitize()
* does not have to bother with them (glyf/local work this way). The choice
* depends on the table structure and sanitize() performance. For example, to
* check glyf/loca offsets in sanitize() would cost O(num-glyphs). We try hard
* to avoid such costs during font loading. By postponing such checks to the
* actual glyph loading, we reduce the sanitize cost to O(1) and total runtime
* cost to O(used-glyphs). As such, this is preferred.
*
* The same argument can be made re GSUB/GPOS/GDEF, but there, the table
* structure is so complicated that by checking all offsets at sanitize() time,
* we make the code much simpler in other methods, as offsets and referenced
* objectes do not need to be validated at each use site.
*/
/* This limits sanitizing time on really broken fonts. */
@ -375,12 +442,19 @@ struct hb_serialize_context_t
{
this->start = (char *) start_;
this->end = this->start + size;
reset ();
}
inline void reset (void)
{
this->ran_out_of_room = false;
this->head = this->start;
this->debug_depth = 0;
}
inline bool err (bool e) { return this->ran_out_of_room = this->ran_out_of_room || e; }
/* To be called around main operation. */
template <typename Type>
inline Type *start_serialize (void)
{
@ -391,7 +465,6 @@ struct hb_serialize_context_t
return start_embed<Type> ();
}
inline void end_serialize (void)
{
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
@ -401,15 +474,20 @@ struct hb_serialize_context_t
this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
}
template <typename Type>
inline Type *copy (void)
inline unsigned int length (void) const { return this->head - this->start; }
inline void align (unsigned int alignment)
{
assert (!this->ran_out_of_room);
unsigned int len = this->head - this->start;
void *p = malloc (len);
if (p)
memcpy (p, this->start, len);
return reinterpret_cast<Type *> (p);
unsigned int l = length () % alignment;
if (l)
allocate_size<void> (alignment - l);
}
template <typename Type>
inline Type *start_embed (void) const
{
Type *ret = reinterpret_cast<Type *> (this->head);
return ret;
}
template <typename Type>
@ -431,20 +509,13 @@ struct hb_serialize_context_t
return this->allocate_size<Type> (Type::min_size);
}
template <typename Type>
inline Type *start_embed (void)
{
Type *ret = reinterpret_cast<Type *> (this->head);
return ret;
}
template <typename Type>
inline Type *embed (const Type &obj)
{
unsigned int size = obj.get_size ();
Type *ret = this->allocate_size<Type> (size);
if (unlikely (!ret)) return nullptr;
memcpy (ret, obj, size);
memcpy (ret, &obj, size);
return ret;
}
@ -466,6 +537,38 @@ struct hb_serialize_context_t
return reinterpret_cast<Type *> (&obj);
}
/* Output routines. */
template <typename Type>
inline Type *copy (void) const
{
assert (!this->ran_out_of_room);
unsigned int len = this->head - this->start;
void *p = malloc (len);
if (p)
memcpy (p, this->start, len);
return reinterpret_cast<Type *> (p);
}
inline hb_bytes_t copy_bytes (void) const
{
assert (!this->ran_out_of_room);
unsigned int len = this->head - this->start;
void *p = malloc (len);
if (p)
memcpy (p, this->start, len);
else
return hb_bytes_t ();
return hb_bytes_t (p, len);
}
inline hb_blob_t *copy_blob (void) const
{
assert (!this->ran_out_of_room);
return hb_blob_create (this->start,
this->head - this->start,
HB_MEMORY_MODE_DUPLICATE,
nullptr, nullptr);
}
public:
unsigned int debug_depth;
char *start, *end, *head;
bool ran_out_of_room;
@ -479,12 +582,19 @@ struct hb_serialize_context_t
template <typename Type>
struct Supplier
{
inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type))
inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof (Type))
{
head = array;
len = len_;
stride = stride_;
}
inline Supplier (const hb_vector_t<Type> *v)
{
head = v->arrayZ;
len = v->len;
stride = sizeof (Type);
}
inline const Type operator [] (unsigned int i) const
{
if (unlikely (i >= len)) return Type ();
@ -682,6 +792,10 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
}
return p;
}
inline Stored * get_stored_relaxed (void) const
{
return this->instance.get_relaxed ();
}
inline void set_stored (Stored *instance_)
{
@ -695,6 +809,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
}
inline const Returned * get (void) const { return Funcs::convert (get_stored ()); }
inline const Returned * get_relaxed (void) const { return Funcs::convert (get_stored_relaxed ()); }
inline Returned * get_unconst (void) const { return const_cast<Returned *> (Funcs::convert (get_stored ())); }
/* To be possibly overloaded by subclasses. */
@ -729,9 +844,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
/* Specializations. */
template <unsigned int WheresFace, typename T>
template <typename T, unsigned int WheresFace>
struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
hb_face_lazy_loader_t<WheresFace, T>,
hb_face_lazy_loader_t<T, WheresFace>,
hb_face_t, WheresFace> {};
template <typename T, unsigned int WheresFace>
@ -789,4 +904,4 @@ struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Sub
};
#endif /* HB_MACHINERY_PRIVATE_HH */
#endif /* HB_MACHINERY_HH */

View File

@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-map-private.hh"
#include "hb-map.hh"
/* Public API */

View File

@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_MAP_PRIVATE_HH
#define HB_MAP_PRIVATE_HH
#ifndef HB_MAP_HH
#define HB_MAP_HH
#include "hb-private.hh"
#include "hb.hh"
template <typename T>
@ -251,4 +251,4 @@ struct hb_map_t
};
#endif /* HB_MAP_PRIVATE_HH */
#endif /* HB_MAP_HH */

View File

@ -29,10 +29,10 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_MUTEX_PRIVATE_HH
#define HB_MUTEX_PRIVATE_HH
#ifndef HB_MUTEX_HH
#define HB_MUTEX_HH
#include "hb-private.hh"
#include "hb.hh"
/* mutex */
@ -138,4 +138,4 @@ struct hb_mutex_t
};
#endif /* HB_MUTEX_PRIVATE_HH */
#endif /* HB_MUTEX_HH */

View File

@ -27,7 +27,7 @@
#ifndef HB_NULL_HH
#define HB_NULL_HH
#include "hb-private.hh"
#include "hb.hh"
/*
@ -51,27 +51,40 @@ static inline Type const & Null (void) {
/* Specializaitons for arbitrary-content Null objects expressed in bytes. */
#define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \
} /* Close namespace. */ \
extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \
template <> \
/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
} \
namespace Namespace { \
static_assert (true, "Just so we take semicolon after.")
} /* Close namespace. */ \
extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \
template <> \
/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
} \
namespace Namespace { \
static_assert (true, "Just so we take semicolon after.")
#define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]
const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]
/* Specializaitons for arbitrary-content Null objects expressed as struct initializer. */
#define DECLARE_NULL_INSTANCE(Type) \
extern HB_INTERNAL const Type _hb_Null_##Type; \
template <> \
/*static*/ inline const Type& Null<Type> (void) { \
return _hb_Null_##Type; \
} \
extern HB_INTERNAL const Type _hb_Null_##Type; \
template <> \
/*static*/ inline const Type& Null<Type> (void) { \
return _hb_Null_##Type; \
} \
static_assert (true, "Just so we take semicolon after.")
#define DEFINE_NULL_INSTANCE(Type) \
const Type _hb_Null_##Type
const Type _hb_Null_##Type
/* Specializaiton to disallow Null objects. */
#define DECLARE_NULL_DISALLOW(Type) \
template <> inline const Type& Null<Type> (void)
#define DECLARE_NULL_NAMSPACE_DISALLOW(Namespace, Type) \
} /* Close namespace. */ \
template <> \
/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
extern void *_hb_undefined; \
return *reinterpret_cast<const Namespace::Type *> (_hb_undefined); \
} \
namespace Namespace { \
static_assert (true, "Just so we take semicolon after.")
/* Global writable pool. Enlarge as necessary. */

View File

@ -29,13 +29,13 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OBJECT_PRIVATE_HH
#define HB_OBJECT_PRIVATE_HH
#ifndef HB_OBJECT_HH
#define HB_OBJECT_HH
#include "hb-private.hh"
#include "hb-atomic-private.hh"
#include "hb-mutex-private.hh"
#include "hb-vector-private.hh"
#include "hb.hh"
#include "hb-atomic.hh"
#include "hb-mutex.hh"
#include "hb-vector.hh"
/*
@ -322,4 +322,4 @@ static inline void *hb_object_get_user_data (Type *obj,
}
#endif /* HB_OBJECT_PRIVATE_HH */
#endif /* HB_OBJECT_HH */

View File

@ -26,10 +26,10 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OPEN_FILE_PRIVATE_HH
#define HB_OPEN_FILE_PRIVATE_HH
#ifndef HB_OPEN_FILE_HH
#define HB_OPEN_FILE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
#include "hb-ot-head-table.hh"
@ -115,7 +115,7 @@ typedef struct OffsetTable
* table list. */
int i = tables.len < 64 ? tables.lsearch (t) : tables.bsearch (t);
if (table_index)
*table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i;
*table_index = i == -1 ? (unsigned) Index::NOT_FOUND_INDEX : (unsigned) i;
return i != -1;
}
inline const TableRecord& get_table_by_tag (hb_tag_t tag) const
@ -161,8 +161,7 @@ typedef struct OffsetTable
memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
/* 4-byte allignment. */
if (rec.length % 4)
c->allocate_size<void> (4 - rec.length % 4);
c->align (4);
const char *end = (const char *) c->head;
if (tags[i] == HB_OT_TAG_head && end - start >= head::static_size)
@ -565,4 +564,4 @@ struct OpenTypeFontFile
} /* namespace OT */
#endif /* HB_OPEN_FILE_PRIVATE_HH */
#endif /* HB_OPEN_FILE_HH */

View File

@ -26,13 +26,14 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OPEN_TYPE_PRIVATE_HH
#define HB_OPEN_TYPE_PRIVATE_HH
#ifndef HB_OPEN_TYPE_HH
#define HB_OPEN_TYPE_HH
#include "hb-private.hh"
#include "hb-blob-private.hh"
#include "hb-face-private.hh"
#include "hb-machinery-private.hh"
#include "hb.hh"
#include "hb-blob.hh"
#include "hb-face.hh"
#include "hb-machinery.hh"
#include "hb-subset.hh"
namespace OT {
@ -149,7 +150,7 @@ typedef HBUINT16 NameID;
/* Script/language-system/feature index */
struct Index : HBUINT16 {
static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
enum { NOT_FOUND_INDEX = 0xFFFFu };
};
DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
@ -246,6 +247,19 @@ struct OffsetTo : Offset<OffsetType>
return * (Type *) Offset<OffsetType>::serialize (c, base);
}
template <typename T>
inline void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
{
if (&src == &Null(T))
{
this->set (0);
return;
}
serialize (c->serializer, base);
if (!src.subset (c))
this->set (0);
}
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
@ -404,7 +418,6 @@ struct ArrayOf
if (unlikely (!c->extend (*this))) return_trace (false);
return_trace (true);
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<Type> &items,
unsigned int items_len)
@ -505,6 +518,17 @@ struct OffsetListOf : OffsetArrayOf<Type>
return this+this->arrayZ[i];
}
inline bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
struct OffsetListOf<Type> *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
unsigned int count = this->len;
for (unsigned int i = 0; i < count; i++)
out->arrayZ[i].serialize_subset (c, (*this)[i], out);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -646,4 +670,4 @@ struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {};
} /* namespace OT */
#endif /* HB_OPEN_TYPE_PRIVATE_HH */
#endif /* HB_OPEN_TYPE_HH */

View File

@ -27,9 +27,8 @@
#ifndef HB_OT_CMAP_TABLE_HH
#define HB_OT_CMAP_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-set-private.hh"
#include "hb-subset-plan.hh"
#include "hb-open-type.hh"
#include "hb-set.hh"
/*
* cmap -- Character to Glyph Index Mapping
@ -37,10 +36,6 @@
*/
#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
#ifndef HB_MAX_UNICODE_CODEPOINT_VALUE
#define HB_MAX_UNICODE_CODEPOINT_VALUE 0x10FFFF
#endif
namespace OT {
@ -54,6 +49,12 @@ struct CmapSubtableFormat0
*glyph = gid;
return true;
}
inline void collect_unicodes (hb_set_t *out) const
{
for (unsigned int i = 0; i < 256; i++)
if (glyphIdArray[i])
out->add (i);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
@ -237,15 +238,14 @@ struct CmapSubtableFormat4
glyphIdArray = idRangeOffset + segCount;
glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
}
inline void fini (void) {}
static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
const accelerator_t *thiz = (const accelerator_t *) obj;
/* Custom two-array bsearch. */
int min = 0, max = (int) thiz->segCount - 1;
const HBUINT16 *startCount = thiz->startCount;
const HBUINT16 *endCount = thiz->endCount;
int min = 0, max = (int) this->segCount - 1;
const HBUINT16 *startCount = this->startCount;
const HBUINT16 *endCount = this->endCount;
unsigned int i;
while (min <= max)
{
@ -264,33 +264,55 @@ struct CmapSubtableFormat4
found:
hb_codepoint_t gid;
unsigned int rangeOffset = thiz->idRangeOffset[i];
unsigned int rangeOffset = this->idRangeOffset[i];
if (rangeOffset == 0)
gid = codepoint + thiz->idDelta[i];
gid = codepoint + this->idDelta[i];
else
{
/* Somebody has been smoking... */
unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
if (unlikely (index >= thiz->glyphIdArrayLength))
unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
if (unlikely (index >= this->glyphIdArrayLength))
return false;
gid = thiz->glyphIdArray[index];
gid = this->glyphIdArray[index];
if (unlikely (!gid))
return false;
gid += thiz->idDelta[i];
gid += this->idDelta[i];
}
*glyph = gid & 0xFFFFu;
gid &= 0xFFFFu;
if (!gid)
return false;
*glyph = gid;
return true;
}
static inline void get_all_codepoints_func (const void *obj, hb_set_t *out)
static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
{
const accelerator_t *thiz = (const accelerator_t *) obj;
for (unsigned int i = 0; i < thiz->segCount; i++)
return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph);
}
inline void collect_unicodes (hb_set_t *out) const
{
unsigned int count = this->segCount;
if (count && this->startCount[count - 1] == 0xFFFFu)
count--; /* Skip sentinel segment. */
for (unsigned int i = 0; i < count; i++)
{
if (thiz->startCount[i] != 0xFFFFu
|| thiz->endCount[i] != 0xFFFFu) // Skip the last segment (0xFFFF)
hb_set_add_range (out, thiz->startCount[i], thiz->endCount[i]);
unsigned int rangeOffset = this->idRangeOffset[i];
if (rangeOffset == 0)
out->add_range (this->startCount[i], this->endCount[i]);
else
{
for (hb_codepoint_t codepoint = this->startCount[i];
codepoint <= this->endCount[i];
codepoint++)
{
unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
if (unlikely (index >= this->glyphIdArrayLength))
break;
hb_codepoint_t gid = this->glyphIdArray[index];
if (unlikely (!gid))
continue;
out->add (codepoint);
}
}
}
}
@ -305,10 +327,14 @@ struct CmapSubtableFormat4
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
accelerator_t accel;
accel.init (this);
hb_auto_t<accelerator_t> accel (this);
return accel.get_glyph_func (&accel, codepoint, glyph);
}
inline void collect_unicodes (hb_set_t *out) const
{
hb_auto_t<accelerator_t> accel (this);
accel.collect_unicodes (out);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
@ -383,7 +409,7 @@ struct CmapSubtableLongGroup
HBUINT32 startCharCode; /* First character code in this group. */
HBUINT32 endCharCode; /* Last character code in this group. */
HBUINT32 glyphID; /* Glyph index; interpretation depends on
* subtable format. */
* subtable format. */
public:
DEFINE_SIZE_STATIC (12);
};
@ -400,6 +426,14 @@ struct CmapSubtableTrimmed
*glyph = gid;
return true;
}
inline void collect_unicodes (hb_set_t *out) const
{
hb_codepoint_t start = startCharCode;
unsigned int count = glyphIdArray.len;
for (unsigned int i = 0; i < count; i++)
if (glyphIdArray[i])
out->add (start + i);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
@ -432,18 +466,19 @@ struct CmapSubtableLongSegmented
int i = groups.bsearch (codepoint);
if (i == -1)
return false;
*glyph = T::group_get_glyph (groups[i], codepoint);
hb_codepoint_t gid = T::group_get_glyph (groups[i], codepoint);
if (!gid)
return false;
*glyph = gid;
return true;
}
inline void get_all_codepoints (hb_set_t *out) const
inline void collect_unicodes (hb_set_t *out) const
{
for (unsigned int i = 0; i < this->groups.len; i++) {
hb_set_add_range (out,
MIN ((unsigned int) this->groups[i].startCharCode,
(unsigned int) HB_MAX_UNICODE_CODEPOINT_VALUE),
MIN ((unsigned int) this->groups[i].endCharCode,
(unsigned int) HB_MAX_UNICODE_CODEPOINT_VALUE));
out->add_range (this->groups[i].startCharCode,
MIN ((hb_codepoint_t) this->groups[i].endCharCode,
(hb_codepoint_t) HB_UNICODE_MAX));
}
}
@ -574,13 +609,29 @@ struct UnicodeValueRange
}
HBUINT24 startUnicodeValue; /* First value in this range. */
HBUINT8 additionalCount; /* Number of additional values in this
HBUINT8 additionalCount; /* Number of additional values in this
* range. */
public:
DEFINE_SIZE_STATIC (4);
};
typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS;
struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
{
inline void collect_unicodes (hb_set_t *out) const
{
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
{
hb_codepoint_t first = arrayZ[i].startUnicodeValue;
hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
(hb_codepoint_t) HB_UNICODE_MAX);
out->add_range (first, last);
}
}
public:
DEFINE_SIZE_ARRAY (4, arrayZ);
};
struct UVSMapping
{
@ -601,7 +652,18 @@ struct UVSMapping
DEFINE_SIZE_STATIC (5);
};
typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS;
struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
{
inline void collect_unicodes (hb_set_t *out) const
{
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
out->add (arrayZ[i].glyphID);
}
public:
DEFINE_SIZE_ARRAY (4, arrayZ);
};
struct VariationSelectorRecord
{
@ -616,7 +678,7 @@ struct VariationSelectorRecord
return GLYPH_VARIANT_USE_DEFAULT;
const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
i = nonDefaults.bsearch (codepoint);
if (i != -1)
if (i != -1 && nonDefaults[i].glyphID)
{
*glyph = nonDefaults[i].glyphID;
return GLYPH_VARIANT_FOUND;
@ -624,6 +686,12 @@ struct VariationSelectorRecord
return GLYPH_VARIANT_NOT_FOUND;
}
inline void collect_unicodes (hb_set_t *out, const void *base) const
{
(base+defaultUVS).collect_unicodes (out);
(base+nonDefaultUVS).collect_unicodes (out);
}
inline int cmp (const hb_codepoint_t &variation_selector) const
{
return varSelector.cmp (variation_selector);
@ -652,7 +720,19 @@ struct CmapSubtableFormat14
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
return record[record.bsearch (variation_selector)].get_glyph (codepoint, glyph, this);
}
inline void collect_variation_selectors (hb_set_t *out) const
{
unsigned int count = record.len;
for (unsigned int i = 0; i < count; i++)
out->add (record.arrayZ[i].varSelector);
}
inline void collect_variation_unicodes (hb_codepoint_t variation_selector,
hb_set_t *out) const
{
record[record.bsearch (variation_selector)].collect_unicodes (out, this);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@ -690,6 +770,19 @@ struct CmapSubtable
default: return false;
}
}
inline void collect_unicodes (hb_set_t *out) const
{
switch (u.format) {
case 0: u.format0 .collect_unicodes (out); return;
case 4: u.format4 .collect_unicodes (out); return;
case 6: u.format6 .collect_unicodes (out); return;
case 10: u.format10.collect_unicodes (out); return;
case 12: u.format12.collect_unicodes (out); return;
case 13: u.format13.collect_unicodes (out); return;
case 14:
default: return;
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
@ -754,7 +847,8 @@ struct cmap
{
static const hb_tag_t tableTag = HB_OT_TAG_cmap;
struct subset_plan {
struct subset_plan
{
subset_plan(void)
{
format4_segments.init();
@ -895,33 +989,44 @@ struct cmap
return result;
}
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
{
if (symbol) *symbol = false;
const CmapSubtable *subtable;
/* 32-bit subtables. */
if ((subtable = this->find_subtable (3, 10))) return subtable;
if ((subtable = this->find_subtable (0, 6))) return subtable;
if ((subtable = this->find_subtable (0, 4))) return subtable;
/* 16-bit subtables. */
if ((subtable = this->find_subtable (3, 1))) return subtable;
if ((subtable = this->find_subtable (0, 3))) return subtable;
if ((subtable = this->find_subtable (0, 2))) return subtable;
if ((subtable = this->find_subtable (0, 1))) return subtable;
if ((subtable = this->find_subtable (0, 0))) return subtable;
/* Symbol subtable. */
if ((subtable = this->find_subtable (3, 0)))
{
if (symbol) *symbol = true;
return subtable;
}
/* Meh. */
return &Null(CmapSubtable);
}
struct accelerator_t
{
inline void init (hb_face_t *face)
{
this->blob = hb_sanitize_context_t().reference_table<cmap> (face);
const cmap *table = this->blob->as<cmap> ();
const CmapSubtable *subtable = nullptr;
const CmapSubtableFormat14 *subtable_uvs = nullptr;
bool symbol = false;
/* 32-bit subtables. */
if (!subtable) subtable = table->find_subtable (3, 10);
if (!subtable) subtable = table->find_subtable (0, 6);
if (!subtable) subtable = table->find_subtable (0, 4);
/* 16-bit subtables. */
if (!subtable) subtable = table->find_subtable (3, 1);
if (!subtable) subtable = table->find_subtable (0, 3);
if (!subtable) subtable = table->find_subtable (0, 2);
if (!subtable) subtable = table->find_subtable (0, 1);
if (!subtable) subtable = table->find_subtable (0, 0);
if (!subtable)
{
subtable = table->find_subtable (3, 0);
if (subtable) symbol = true;
}
/* Meh. */
if (!subtable) subtable = &Null(CmapSubtable);
bool symbol;
subtable = table->find_best_subtable (&symbol);
/* UVS subtable. */
if (!subtable_uvs)
@ -933,30 +1038,26 @@ struct cmap
/* Meh. */
if (!subtable_uvs) subtable_uvs = &Null(CmapSubtableFormat14);
this->uvs_table = subtable_uvs;
this->subtable_uvs = subtable_uvs;
this->get_glyph_data = subtable;
if (unlikely (symbol))
{
this->get_glyph_func = get_glyph_from_symbol<CmapSubtable>;
this->get_all_codepoints_func = null_get_all_codepoints_func;
} else {
switch (subtable->u.format) {
/* Accelerate format 4 and format 12. */
default:
this->get_glyph_func = get_glyph_from<CmapSubtable>;
this->get_all_codepoints_func = null_get_all_codepoints_func;
break;
case 12:
this->get_glyph_func = get_glyph_from<CmapSubtableFormat12>;
this->get_all_codepoints_func = get_all_codepoints_from<CmapSubtableFormat12>;
break;
case 4:
{
this->format4_accel.init (&subtable->u.format4);
this->get_glyph_data = &this->format4_accel;
this->get_glyph_func = this->format4_accel.get_glyph_func;
this->get_all_codepoints_func = this->format4_accel.get_all_codepoints_func;
}
break;
}
@ -978,9 +1079,9 @@ struct cmap
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
switch (this->uvs_table->get_glyph_variant (unicode,
variation_selector,
glyph))
switch (this->subtable_uvs->get_glyph_variant (unicode,
variation_selector,
glyph))
{
case GLYPH_VARIANT_NOT_FOUND: return false;
case GLYPH_VARIANT_FOUND: return true;
@ -990,22 +1091,24 @@ struct cmap
return get_nominal_glyph (unicode, glyph);
}
inline void get_all_codepoints (hb_set_t *out) const
inline void collect_unicodes (hb_set_t *out) const
{
this->get_all_codepoints_func (get_glyph_data, out);
subtable->collect_unicodes (out);
}
inline void collect_variation_selectors (hb_set_t *out) const
{
subtable_uvs->collect_variation_selectors (out);
}
inline void collect_variation_unicodes (hb_codepoint_t variation_selector,
hb_set_t *out) const
{
subtable_uvs->collect_variation_unicodes (variation_selector, out);
}
protected:
typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph);
typedef void (*hb_cmap_get_all_codepoints_func_t) (const void *obj,
hb_set_t *out);
static inline void null_get_all_codepoints_func (const void *obj, hb_set_t *out)
{
// NOOP
}
template <typename Type>
static inline bool get_glyph_from (const void *obj,
@ -1016,14 +1119,6 @@ struct cmap
return typed_obj->get_glyph (codepoint, glyph);
}
template <typename Type>
static inline void get_all_codepoints_from (const void *obj,
hb_set_t *out)
{
const Type *typed_obj = (const Type *) obj;
typed_obj->get_all_codepoints (out);
}
template <typename Type>
static inline bool get_glyph_from_symbol (const void *obj,
hb_codepoint_t codepoint,
@ -1047,13 +1142,14 @@ struct cmap
}
private:
const CmapSubtable *subtable;
const CmapSubtableFormat14 *subtable_uvs;
hb_cmap_get_glyph_func_t get_glyph_func;
const void *get_glyph_data;
hb_cmap_get_all_codepoints_func_t get_all_codepoints_func;
CmapSubtableFormat4::accelerator_t format4_accel;
const CmapSubtableFormat14 *uvs_table;
hb_blob_t *blob;
};
@ -1066,10 +1162,7 @@ struct cmap
key.platformID.set (platform_id);
key.encodingID.set (encoding_id);
/* Note: We can use bsearch, but since it has no performance
* implications, we use lsearch and as such accept fonts with
* unsorted subtable list. */
int result = encodingRecord./*bsearch*/lsearch (key);
int result = encodingRecord.bsearch (key);
if (result == -1 || !encodingRecord[result].subtable)
return nullptr;
@ -1084,6 +1177,7 @@ struct cmap
DEFINE_SIZE_ARRAY (4, encodingRecord);
};
struct cmap_accelerator_t : cmap::accelerator_t {};
} /* namespace OT */

View File

@ -27,7 +27,7 @@
#ifndef HB_OT_COLOR_CBDT_TABLE_HH
#define HB_OT_COLOR_CBDT_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
/*
* CBLC -- Color Bitmap Location
@ -533,6 +533,8 @@ struct CBDT
DEFINE_SIZE_ARRAY(4, dataZ);
};
struct CBDT_accelerator_t : CBDT::accelerator_t {};
} /* namespace OT */
#endif /* HB_OT_COLOR_CBDT_TABLE_HH */

View File

@ -25,7 +25,7 @@
#ifndef HB_OT_COLOR_COLR_TABLE_HH
#define HB_OT_COLOR_COLR_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
/*
* COLR -- Color

View File

@ -28,7 +28,7 @@
#ifndef HB_OT_COLOR_CPAL_TABLE_HH
#define HB_OT_COLOR_CPAL_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
/*

View File

@ -25,7 +25,7 @@
#ifndef HB_OT_COLOR_SBIX_TABLE_HH
#define HB_OT_COLOR_SBIX_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
/*
* sbix -- Standard Bitmap Graphics

View File

@ -25,7 +25,7 @@
#ifndef HB_OT_COLOR_SVG_TABLE_HH
#define HB_OT_COLOR_SVG_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
/*
* SVG -- SVG (Scalable Vector Graphics)

View File

@ -25,7 +25,7 @@
* Google Author(s): Sascha Brawer
*/
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
#include "hb-ot-color-colr-table.hh"
#include "hb-ot-color-cpal-table.hh"
#include "hb-ot.h"
@ -33,8 +33,8 @@
#include <stdlib.h>
#include <string.h>
#include "hb-ot-layout-private.hh"
#include "hb-shaper-private.hh"
#include "hb-ot-layout.hh"
#include "hb-shaper.hh"
#if 0
HB_MARK_AS_FLAG_T (hb_ot_color_palette_flags_t)
@ -45,16 +45,14 @@ static inline const OT::COLR&
_get_colr (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::COLR);
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
return *(layout->colr.get ());
return *(hb_ot_face_data (face)->colr.get ());
}
static inline const OT::CPAL&
_get_cpal (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CPAL);
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
return *(layout->cpal.get ());
return *(hb_ot_face_data (face)->cpal.get ());
}

View File

@ -0,0 +1,76 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-kern-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
void hb_ot_face_data_t::init0 (hb_face_t *face)
{
this->face = face;
#define HB_OT_LAYOUT_TABLE(Namespace, Type) Type.init0 ();
#define HB_OT_LAYOUT_ACCELERATOR(Namespace, Type) HB_OT_LAYOUT_TABLE (Namespace, Type)
HB_OT_LAYOUT_TABLES
#undef HB_OT_LAYOUT_ACCELERATOR
#undef HB_OT_LAYOUT_TABLE
}
void hb_ot_face_data_t::fini (void)
{
#define HB_OT_LAYOUT_TABLE(Namespace, Type) Type.fini ();
#define HB_OT_LAYOUT_ACCELERATOR(Namespace, Type) HB_OT_LAYOUT_TABLE (Namespace, Type)
HB_OT_LAYOUT_TABLES
#undef HB_OT_LAYOUT_ACCELERATOR
#undef HB_OT_LAYOUT_TABLE
}
hb_ot_face_data_t *
_hb_ot_face_data_create (hb_face_t *face)
{
hb_ot_face_data_t *data = (hb_ot_face_data_t *) calloc (1, sizeof (hb_ot_face_data_t));
if (unlikely (!data))
return nullptr;
data->init0 (face);
return data;
}
void
_hb_ot_face_data_destroy (hb_ot_face_data_t *data)
{
data->fini ();
free (data);
}

View File

@ -0,0 +1,116 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_FACE_HH
#define HB_OT_FACE_HH
#include "hb.hh"
#include "hb-machinery.hh"
#define hb_ot_face_data(face) ((hb_ot_face_data_t *) face->shaper_data.ot.get_relaxed ())
/*
* hb_ot_face_data_t
*/
/* Most of these tables are NOT needed for shaping. But we need to hook them *somewhere*.
* This is as good as any place. */
#define HB_OT_LAYOUT_TABLES \
/* OpenType shaping. */ \
HB_OT_LAYOUT_TABLE(OT, JSTF) \
HB_OT_LAYOUT_TABLE(OT, BASE) \
/* AAT shaping. */ \
HB_OT_LAYOUT_TABLE(AAT, morx) \
HB_OT_LAYOUT_TABLE(AAT, kerx) \
HB_OT_LAYOUT_TABLE(AAT, ankr) \
HB_OT_LAYOUT_TABLE(AAT, trak) \
/* OpenType variations. */ \
HB_OT_LAYOUT_TABLE(OT, fvar) \
HB_OT_LAYOUT_TABLE(OT, avar) \
HB_OT_LAYOUT_TABLE(OT, MVAR) \
/* OpenType math. */ \
HB_OT_LAYOUT_TABLE(OT, MATH) \
/* OpenType fundamentals. */ \
HB_OT_LAYOUT_ACCELERATOR(OT, GDEF) \
HB_OT_LAYOUT_ACCELERATOR(OT, GSUB) \
HB_OT_LAYOUT_ACCELERATOR(OT, GPOS) \
HB_OT_LAYOUT_ACCELERATOR(OT, cmap) \
HB_OT_LAYOUT_ACCELERATOR(OT, hmtx) \
HB_OT_LAYOUT_ACCELERATOR(OT, vmtx) \
HB_OT_LAYOUT_ACCELERATOR(OT, post) \
HB_OT_LAYOUT_ACCELERATOR(OT, kern) \
HB_OT_LAYOUT_ACCELERATOR(OT, glyf) \
HB_OT_LAYOUT_ACCELERATOR(OT, CBDT) \
/* */
/* Declare tables. */
#define HB_OT_LAYOUT_TABLE(Namespace, Type) namespace Namespace { struct Type; }
#define HB_OT_LAYOUT_ACCELERATOR(Namespace, Type) HB_OT_LAYOUT_TABLE (Namespace, Type##_accelerator_t)
HB_OT_LAYOUT_TABLES
#undef HB_OT_LAYOUT_ACCELERATOR
#undef HB_OT_LAYOUT_TABLE
struct hb_ot_face_data_t
{
HB_INTERNAL void init0 (hb_face_t *face);
HB_INTERNAL void fini (void);
#define HB_OT_LAYOUT_TABLE_ORDER(Namespace, Type) \
HB_PASTE (ORDER_, HB_PASTE (Namespace, HB_PASTE (_, Type)))
enum order_t
{
ORDER_ZERO,
#define HB_OT_LAYOUT_TABLE(Namespace, Type) HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type),
#define HB_OT_LAYOUT_ACCELERATOR(Namespace, Type) HB_OT_LAYOUT_TABLE (Namespace, Type)
HB_OT_LAYOUT_TABLES
#undef HB_OT_LAYOUT_ACCELERATOR
#undef HB_OT_LAYOUT_TABLE
};
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
#define HB_OT_LAYOUT_TABLE(Namespace, Type) \
hb_table_lazy_loader_t<Namespace::Type, HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type)> Type;
#define HB_OT_LAYOUT_ACCELERATOR(Namespace, Type) \
hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type)> Type;
HB_OT_LAYOUT_TABLES
#undef HB_OT_LAYOUT_ACCELERATOR
#undef HB_OT_LAYOUT_TABLE
};
HB_INTERNAL hb_ot_face_data_t *
_hb_ot_face_data_create (hb_face_t *face);
HB_INTERNAL void
_hb_ot_face_data_destroy (hb_ot_face_data_t *data);
#endif /* HB_OT_FACE_HH */

View File

@ -24,84 +24,22 @@
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
#include "hb-private.hh"
#include "hb.hh"
#include "hb-ot.h"
#include "hb-font-private.hh"
#include "hb-machinery-private.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-kern-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-color-cbdt-table.hh"
struct hb_ot_font_t
{
inline void init (hb_face_t *face)
{
cmap.init (face);
h_metrics.init (face);
v_metrics.init (face, h_metrics.ascender - h_metrics.descender); /* TODO Can we do this lazily? */
this->face = face;
glyf.init ();
cbdt.init ();
post.init ();
kern.init ();
}
inline void fini (void)
{
cmap.fini ();
h_metrics.fini ();
v_metrics.fini ();
glyf.fini ();
cbdt.fini ();
post.fini ();
kern.fini ();
}
OT::cmap::accelerator_t cmap;
OT::hmtx::accelerator_t h_metrics;
OT::vmtx::accelerator_t v_metrics;
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
hb_face_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
hb_face_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
hb_face_lazy_loader_t<3, OT::post::accelerator_t> post;
hb_face_lazy_loader_t<4, OT::kern::accelerator_t> kern;
};
static hb_ot_font_t *
_hb_ot_font_create (hb_face_t *face)
{
hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
if (unlikely (!ot_font))
return nullptr;
ot_font->init (face);
return ot_font;
}
static void
_hb_ot_font_destroy (void *data)
{
hb_ot_font_t *ot_font = (hb_ot_font_t *) data;
ot_font->fini ();
free (ot_font);
}
static hb_bool_t
hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
@ -110,8 +48,8 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
return ot_font->cmap.get_nominal_glyph (unicode, glyph);
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
return ot_font->cmap.get_relaxed()->get_nominal_glyph (unicode, glyph);
}
static hb_bool_t
@ -122,8 +60,8 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
return ot_font->cmap.get_relaxed ()->get_variation_glyph (unicode, variation_selector, glyph);
}
static hb_position_t
@ -132,8 +70,8 @@ hb_ot_get_glyph_h_advance (hb_font_t *font,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font));
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
return font->em_scale_x (ot_font->hmtx.get_relaxed ()->get_advance (glyph, font));
}
static hb_position_t
@ -142,8 +80,8 @@ hb_ot_get_glyph_v_advance (hb_font_t *font,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
return font->em_scale_y (-(int) ot_font->vmtx.get_relaxed ()->get_advance (glyph, font));
}
static hb_position_t
@ -153,7 +91,7 @@ hb_ot_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
return font->em_scale_x (ot_font->kern->get_h_kerning (left_glyph, right_glyph));
}
@ -164,10 +102,10 @@ hb_ot_get_glyph_extents (hb_font_t *font,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
bool ret = ot_font->glyf->get_extents (glyph, extents);
if (!ret)
ret = ot_font->cbdt->get_extents (glyph, extents);
ret = ot_font->CBDT->get_extents (glyph, extents);
// TODO Hook up side-bearings variations.
extents->x_bearing = font->em_scale_x (extents->x_bearing);
extents->y_bearing = font->em_scale_y (extents->y_bearing);
@ -183,7 +121,7 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
return ot_font->post->get_glyph_name (glyph, name, size);
}
@ -194,7 +132,7 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
return ot_font->post->get_glyph_from_name (name, len, glyph);
}
@ -204,12 +142,12 @@ hb_ot_get_font_h_extents (hb_font_t *font,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
metrics->ascender = font->em_scale_y (ot_font->hmtx.get_relaxed ()->ascender);
metrics->descender = font->em_scale_y (ot_font->hmtx.get_relaxed ()->descender);
metrics->line_gap = font->em_scale_y (ot_font->hmtx.get_relaxed ()->line_gap);
// TODO Hook up variations.
return ot_font->h_metrics.has_font_extents;
return ot_font->hmtx.get_relaxed ()->has_font_extents;
}
static hb_bool_t
@ -218,16 +156,17 @@ hb_ot_get_font_v_extents (hb_font_t *font,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
const hb_ot_face_data_t *ot_font = (const hb_ot_face_data_t *) font_data;
metrics->ascender = font->em_scale_x (ot_font->vmtx.get_relaxed ()->ascender);
metrics->descender = font->em_scale_x (ot_font->vmtx.get_relaxed ()->descender);
metrics->line_gap = font->em_scale_x (ot_font->vmtx.get_relaxed ()->line_gap);
// TODO Hook up variations.
return ot_font->v_metrics.has_font_extents;
return ot_font->vmtx.get_relaxed ()->has_font_extents;
}
#ifdef HB_USE_ATEXIT
static void free_static_ot_funcs (void);
#endif
static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
{
@ -283,12 +222,16 @@ _hb_ot_get_font_funcs (void)
void
hb_ot_font_set_funcs (hb_font_t *font)
{
hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
if (unlikely (!ot_font))
return;
if (unlikely (!hb_ot_shaper_face_data_ensure (font->face))) return;
hb_ot_face_data_t *ot_font = hb_ot_face_data (font->face);
/* Load them lazies. We access them with get_relaxed() for performance. */
ot_font->cmap.get ();
ot_font->hmtx.get ();
ot_font->vmtx.get ();
hb_font_set_funcs (font,
_hb_ot_get_font_funcs (),
ot_font,
_hb_ot_font_destroy);
nullptr);
}

View File

@ -27,11 +27,9 @@
#ifndef HB_OT_GLYF_TABLE_HH
#define HB_OT_GLYF_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
#include "hb-ot-head-table.hh"
#include "hb-subset-glyf.hh"
#include "hb-subset-plan.hh"
#include "hb-subset-private.hh"
namespace OT {
@ -490,6 +488,8 @@ struct glyf
DEFINE_SIZE_ARRAY (0, dataZ);
};
struct glyf_accelerator_t : glyf::accelerator_t {};
} /* namespace OT */

View File

@ -27,8 +27,7 @@
#ifndef HB_OT_HDMX_TABLE_HH
#define HB_OT_HDMX_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-subset-plan.hh"
#include "hb-open-type.hh"
/*
* hdmx -- Horizontal Device Metrics
@ -89,8 +88,13 @@ struct DeviceRecord
{
TRACE_SERIALIZE (this);
if (unlikely (!c->allocate_size<DeviceRecord> (get_size (subset_view.len()))))
unsigned int size = get_size (subset_view.len());
if (unlikely (!c->allocate_size<DeviceRecord> (size)))
{
DEBUG_MSG (SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
size);
return_trace (false);
}
this->pixel_size.set (subset_view.source_device_record->pixel_size);
this->max_width.set (subset_view.source_device_record->max_width);
@ -161,14 +165,14 @@ struct hdmx
return_trace (true);
}
static inline size_t get_subsetted_size (hb_subset_plan_t *plan)
static inline size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
{
return min_size + DeviceRecord::get_size (plan->glyphs.len);
return min_size + source_hdmx->num_records * DeviceRecord::get_size (plan->glyphs.len);
}
inline bool subset (hb_subset_plan_t *plan) const
{
size_t dest_size = get_subsetted_size (plan);
size_t dest_size = get_subsetted_size (this, plan);
hdmx *dest = (hdmx *) malloc (dest_size);
if (unlikely (!dest))
{
@ -178,8 +182,10 @@ struct hdmx
hb_serialize_context_t c (dest, dest_size);
hdmx *hdmx_prime = c.start_serialize<hdmx> ();
if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) {
if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
{
free (dest);
DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
return false;
}
c.end_serialize ();

View File

@ -29,7 +29,7 @@
#ifndef HB_OT_HEAD_TABLE_HH
#define HB_OT_HEAD_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
/*
* head -- Font Header

View File

@ -27,7 +27,7 @@
#ifndef HB_OT_HHEA_TABLE_HH
#define HB_OT_HHEA_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
/*
* hhea -- Horizontal Header

View File

@ -27,11 +27,10 @@
#ifndef HB_OT_HMTX_TABLE_HH
#define HB_OT_HMTX_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-var-hvar-table.hh"
#include "hb-subset-plan.hh"
/*
* hmtx -- Horizontal Metrics
@ -332,6 +331,9 @@ struct vmtx : hmtxvmtx<vmtx, vhea> {
static const hb_tag_t os2Tag = HB_TAG_NONE;
};
struct hmtx_accelerator_t : hmtx::accelerator_t {};
struct vmtx_accelerator_t : vmtx::accelerator_t {};
} /* namespace OT */

View File

@ -27,7 +27,7 @@
#ifndef HB_OT_KERN_TABLE_HH
#define HB_OT_KERN_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-open-type.hh"
/*
* kern -- Kerning
@ -390,6 +390,8 @@ struct kern
DEFINE_SIZE_UNION (2, major);
};
struct kern_accelerator_t : kern::accelerator_t {};
} /* namespace OT */

View File

@ -28,8 +28,8 @@
#ifndef HB_OT_LAYOUT_BASE_TABLE_HH
#define HB_OT_LAYOUT_BASE_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-ot-layout-common-private.hh"
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
namespace OT {

View File

@ -26,13 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
#define HB_OT_LAYOUT_COMMON_PRIVATE_HH
#ifndef HB_OT_LAYOUT_COMMON_HH
#define HB_OT_LAYOUT_COMMON_HH
#include "hb-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-open-type-private.hh"
#include "hb-set-private.hh"
#include "hb.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
#include "hb-set.hh"
#ifndef HB_MAX_NESTING_LEVEL
@ -97,15 +97,14 @@ struct Record
};
template <typename Type>
struct RecordArrayOf : SortedArrayOf<Record<Type> > {
struct RecordArrayOf : SortedArrayOf<Record<Type> >
{
inline const OffsetTo<Type>& get_offset (unsigned int i) const
{ return (*this)[i].offset; }
inline OffsetTo<Type>& get_offset (unsigned int i)
{ return (*this)[i].offset; }
inline const Tag& get_tag (unsigned int i) const
{
/* We cheat slightly and don't define separate Null objects
* for Record types. Instead, we return the correct Null(Tag)
* here. */
if (unlikely (i >= this->len)) return Null(Tag);
return (*this)[i].tag;
}
{ return (*this)[i].tag; }
inline unsigned int get_tags (unsigned int start_offset,
unsigned int *record_count /* IN/OUT */,
hb_tag_t *record_tags /* OUT */) const
@ -136,7 +135,18 @@ template <typename Type>
struct RecordListOf : RecordArrayOf<Type>
{
inline const Type& operator [] (unsigned int i) const
{ return this+RecordArrayOf<Type>::operator [](i).offset; }
{ return this+this->get_offset (i); }
inline bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
struct RecordListOf<Type> *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
unsigned int count = this->len;
for (unsigned int i = 0; i < count; i++)
out->get_offset (i).serialize_subset (c, (*this)[i], out);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
@ -158,9 +168,8 @@ struct RangeRecord
return_trace (c->check_struct (this));
}
inline bool intersects (const hb_set_t *glyphs) const {
return glyphs->intersects (start, end);
}
inline bool intersects (const hb_set_t *glyphs) const
{ return glyphs->intersects (start, end); }
template <typename set_t>
inline bool add_coverage (set_t *glyphs) const {
@ -224,6 +233,12 @@ struct LangSys
return reqFeatureIndex;;
}
inline bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
return_trace (c->serializer->embed (*this));
}
inline bool sanitize (hb_sanitize_context_t *c,
const Record<LangSys>::sanitize_closure_t * = nullptr) const
{
@ -238,7 +253,7 @@ struct LangSys
* = 0xFFFFu */
IndexArray featureIndex; /* Array of indices into the FeatureList */
public:
DEFINE_SIZE_ARRAY (6, featureIndex);
DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
};
DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
@ -263,6 +278,18 @@ struct Script
inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
inline bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
struct Script *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
unsigned int count = langSys.len;
for (unsigned int i = 0; i < count; i++)
out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c,
const Record<Script>::sanitize_closure_t * = nullptr) const
{
@ -278,7 +305,7 @@ struct Script
langSys; /* Array of LangSysRecords--listed
* alphabetically by LangSysTag */
public:
DEFINE_SIZE_ARRAY (4, langSys);
DEFINE_SIZE_ARRAY_SIZED (4, langSys);
};
typedef RecordListOf<Script> ScriptList;
@ -516,6 +543,15 @@ struct Feature
inline const FeatureParams &get_feature_params (void) const
{ return this+featureParams; }
inline bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
struct Feature *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
out->featureParams.set (0); /* TODO(subset) FeatureParams. */
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c,
const Record<Feature>::sanitize_closure_t *closure = nullptr) const
{
@ -567,7 +603,7 @@ struct Feature
* if not required */
IndexArray lookupIndex; /* Array of LookupList indices */
public:
DEFINE_SIZE_ARRAY (4, lookupIndex);
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
};
typedef RecordListOf<Feature> FeatureList;
@ -598,16 +634,16 @@ struct Lookup
{
inline unsigned int get_subtable_count (void) const { return subTable.len; }
template <typename SubTableType>
inline const SubTableType& get_subtable (unsigned int i) const
{ return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
template <typename TSubTable>
inline const TSubTable& get_subtable (unsigned int i) const
{ return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
template <typename SubTableType>
inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
{ return CastR<OffsetArrayOf<SubTableType> > (subTable); }
template <typename SubTableType>
inline OffsetArrayOf<SubTableType>& get_subtables (void)
{ return CastR<OffsetArrayOf<SubTableType> > (subTable); }
template <typename TSubTable>
inline const OffsetArrayOf<TSubTable>& get_subtables (void) const
{ return CastR<OffsetArrayOf<TSubTable> > (subTable); }
template <typename TSubTable>
inline OffsetArrayOf<TSubTable>& get_subtables (void)
{ return CastR<OffsetArrayOf<TSubTable> > (subTable); }
inline unsigned int get_size (void) const
{
@ -633,14 +669,14 @@ struct Lookup
return flag;
}
template <typename SubTableType, typename context_t>
template <typename TSubTable, typename context_t>
inline typename context_t::return_t dispatch (context_t *c) const
{
unsigned int lookup_type = get_type ();
TRACE_DISPATCH (this, lookup_type);
unsigned int count = get_subtable_count ();
for (unsigned int i = 0; i < count; i++) {
typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
if (c->stop_sublookup_iteration (r))
return_trace (r);
}
@ -666,16 +702,72 @@ struct Lookup
return_trace (true);
}
/* Older compileres need this to NOT be locally defined in a function. */
template <typename TSubTable>
struct SubTableSubsetWrapper
{
inline SubTableSubsetWrapper (const TSubTable &subtable_,
unsigned int lookup_type_) :
subtable (subtable_),
lookup_type (lookup_type_) {}
inline bool subset (hb_subset_context_t *c) const
{ return subtable.dispatch (c, lookup_type); }
private:
const TSubTable &subtable;
unsigned int lookup_type;
};
template <typename TSubTable>
inline bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
struct Lookup *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
/* Subset the actual subtables. */
/* TODO Drop empty ones, either by calling intersects() beforehand,
* or just dropping null offsets after. */
const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
unsigned int count = subTable.len;
for (unsigned int i = 0; i < count; i++)
{
SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
out_subtables[i].serialize_subset (c, wrapper, out);
}
return_trace (true);
}
template <typename TSubTable>
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
/* Real sanitize of the subtables is done by GSUB/GPOS/... */
if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
if (!markFilteringSet.sanitize (c)) return_trace (false);
}
if (unlikely (!dispatch<TSubTable> (c))) return_trace (false);
if (unlikely (get_type () == TSubTable::Extension))
{
/* The spec says all subtables of an Extension lookup should
* have the same type, which shall not be the Extension type
* itself (but we already checked for that).
* This is specially important if one has a reverse type! */
unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
unsigned int count = get_subtable_count ();
for (unsigned int i = 1; i < count; i++)
if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
return_trace (false);
}
return_trace (true);
return_trace (true);
}
@ -730,9 +822,17 @@ struct CoverageFormat1
return_trace (glyphArray.sanitize (c));
}
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
return glyphs->has (glyphArray[index]);
inline bool intersects (const hb_set_t *glyphs) const
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
unsigned int count = glyphArray.len;
for (unsigned int i = 0; i < count; i++)
if (glyphs->has (glyphArray[i]))
return true;
return false;
}
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{ return glyphs->has (glyphArray[index]); }
template <typename set_t>
inline bool add_coverage (set_t *glyphs) const {
@ -743,6 +843,7 @@ struct CoverageFormat1
/* Older compilers need this to be public. */
struct Iter {
inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
inline void fini (void) {};
inline bool more (void) { return i < c->glyphArray.len; }
inline void next (void) { i++; }
inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
@ -819,7 +920,17 @@ struct CoverageFormat2
return_trace (rangeRecord.sanitize (c));
}
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
inline bool intersects (const hb_set_t *glyphs) const
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
if (rangeRecord[i].intersects (glyphs))
return true;
return false;
}
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
unsigned int i;
unsigned int count = rangeRecord.len;
for (i = 0; i < count; i++) {
@ -859,6 +970,7 @@ struct CoverageFormat2
i = c->rangeRecord.len;
}
}
inline void fini (void) {};
inline bool more (void) { return i < c->rangeRecord.len; }
inline void next (void)
{
@ -924,7 +1036,8 @@ struct Coverage
if (glyphs[i - 1] + 1 != glyphs[i])
num_ranges++;
u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
switch (u.format) {
switch (u.format)
{
case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
default:return_trace (false);
@ -935,25 +1048,27 @@ struct Coverage
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
switch (u.format)
{
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
default:return_trace (true);
}
}
inline bool intersects (const hb_set_t *glyphs) const {
/* TODO speed this up */
Coverage::Iter iter;
for (iter.init (*this); iter.more (); iter.next ()) {
if (glyphs->has (iter.get_glyph ()))
return true;
inline bool intersects (const hb_set_t *glyphs) const
{
switch (u.format)
{
case 1: return u.format1.intersects (glyphs);
case 2: return u.format2.intersects (glyphs);
default:return false;
}
return false;
}
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
switch (u.format) {
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
switch (u.format)
{
case 1: return u.format1.intersects_coverage (glyphs, index);
case 2: return u.format2.intersects_coverage (glyphs, index);
default:return false;
@ -963,47 +1078,61 @@ struct Coverage
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename set_t>
inline bool add_coverage (set_t *glyphs) const {
switch (u.format) {
inline bool add_coverage (set_t *glyphs) const
{
switch (u.format)
{
case 1: return u.format1.add_coverage (glyphs);
case 2: return u.format2.add_coverage (glyphs);
default:return false;
}
}
struct Iter {
struct Iter
{
Iter (void) : format (0), u () {};
inline void init (const Coverage &c_) {
inline void init (const Coverage &c_)
{
format = c_.u.format;
switch (format) {
switch (format)
{
case 1: u.format1.init (c_.u.format1); return;
case 2: u.format2.init (c_.u.format2); return;
default: return;
default: return;
}
}
inline bool more (void) {
switch (format) {
inline void fini (void) {}
inline bool more (void)
{
switch (format)
{
case 1: return u.format1.more ();
case 2: return u.format2.more ();
default:return false;
}
}
inline void next (void) {
switch (format) {
inline void next (void)
{
switch (format)
{
case 1: u.format1.next (); break;
case 2: u.format2.next (); break;
default: break;
default: break;
}
}
inline hb_codepoint_t get_glyph (void) {
switch (format) {
inline hb_codepoint_t get_glyph (void)
{
switch (format)
{
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
default:return 0;
}
}
inline unsigned int get_coverage (void) {
switch (format) {
inline unsigned int get_coverage (void)
{
switch (format)
{
case 1: return u.format1.get_coverage ();
case 2: return u.format2.get_coverage ();
default:return -1;
@ -1085,6 +1214,17 @@ struct ClassDefFormat1
return true;
}
inline bool intersects (const hb_set_t *glyphs) const
{
/* TODO Speed up, using hb_set_next()? */
hb_codepoint_t start = startGlyph;
hb_codepoint_t end = startGlyph + classValue.len;
for (hb_codepoint_t iter = startGlyph - 1;
hb_set_next (glyphs, &iter) && iter < end;)
if (classValue[iter - start])
return true;
return false;
}
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
unsigned int count = classValue.len;
if (klass == 0)
@ -1135,7 +1275,8 @@ struct ClassDefFormat2
}
template <typename set_t>
inline bool add_coverage (set_t *glyphs) const {
inline bool add_coverage (set_t *glyphs) const
{
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
if (rangeRecord[i].value)
@ -1145,7 +1286,8 @@ struct ClassDefFormat2
}
template <typename set_t>
inline bool add_class (set_t *glyphs, unsigned int klass) const {
inline bool add_class (set_t *glyphs, unsigned int klass) const
{
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
{
@ -1156,7 +1298,17 @@ struct ClassDefFormat2
return true;
}
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
inline bool intersects (const hb_set_t *glyphs) const
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
if (rangeRecord[i].intersects (glyphs))
return true;
return false;
}
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
{
unsigned int count = rangeRecord.len;
if (klass == 0)
{
@ -1233,6 +1385,13 @@ struct ClassDef
}
}
inline bool intersects (const hb_set_t *glyphs) const {
switch (u.format) {
case 1: return u.format1.intersects (glyphs);
case 2: return u.format2.intersects (glyphs);
default:return false;
}
}
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
switch (u.format) {
case 1: return u.format1.intersects_class (glyphs, klass);
@ -1584,7 +1743,7 @@ struct FeatureVariationRecord
struct FeatureVariations
{
static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
enum { NOT_FOUND_INDEX = 0xFFFFFFFFu };
inline bool find_index (const int *coords, unsigned int coord_len,
unsigned int *index) const
@ -1610,6 +1769,12 @@ struct FeatureVariations
return (this+record.substitutions).find_substitute (feature_index);
}
inline bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
return_trace (c->serializer->embed (*this));
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -1623,7 +1788,7 @@ struct FeatureVariations
LArrayOf<FeatureVariationRecord>
varRecords;
public:
DEFINE_SIZE_ARRAY (8, varRecords);
DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
};
@ -1803,4 +1968,4 @@ struct Device
} /* namespace OT */
#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
#endif /* HB_OT_LAYOUT_COMMON_HH */

View File

@ -29,9 +29,9 @@
#ifndef HB_OT_LAYOUT_GDEF_TABLE_HH
#define HB_OT_LAYOUT_GDEF_TABLE_HH
#include "hb-ot-layout-common-private.hh"
#include "hb-ot-layout-common.hh"
#include "hb-font-private.hh"
#include "hb-font.hh"
namespace OT {
@ -337,6 +337,7 @@ struct MarkGlyphSets
* https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
*/
struct GDEF
{
static const hb_tag_t tableTag = HB_OT_TAG_GDEF;
@ -386,19 +387,6 @@ struct GDEF
inline const VariationStore &get_var_store (void) const
{ return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
glyphClassDef.sanitize (c, this) &&
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
@ -420,6 +408,38 @@ struct GDEF
}
}
struct accelerator_t
{
HB_INTERNAL inline void init (hb_face_t *face);
inline void fini (void)
{
hb_blob_destroy (this->blob);
}
hb_blob_t *blob;
const GDEF *table;
};
inline unsigned int get_size (void) const
{
return min_size +
(version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
(version.to_int () >= 0x00010003u ? varStore.static_size : 0);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
glyphClassDef.sanitize (c, this) &&
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
protected:
FixedVersion<>version; /* Version of the GDEF table--currently
@ -454,6 +474,7 @@ struct GDEF
DEFINE_SIZE_MIN (12);
};
struct GDEF_accelerator_t : GDEF::accelerator_t {};
} /* namespace OT */

Some files were not shown because too many files have changed in this diff Show More