Bug 1929024 - Use language code as a hint to resolve script for textruns with only COMMON or INHERITED codepoints. r=jwatt

Differential Revision: https://phabricator.services.mozilla.com/D227842
This commit is contained in:
Jonathan Kew 2024-11-08 20:26:35 +00:00
parent 6e4a71a742
commit 832db1eb0d

View File

@ -5,30 +5,32 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxTextRun.h"
#include "gfxGlyphExtents.h"
#include "gfxHarfBuzzShaper.h"
#include "gfxPlatformFontList.h"
#include "gfxUserFontSet.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPresData.h"
#include "gfx2DGlue.h"
#include "gfxContext.h"
#include "gfxFontConstants.h"
#include "gfxFontMissingGlyphs.h"
#include "gfxGlyphExtents.h"
#include "gfxHarfBuzzShaper.h"
#include "gfxPlatformFontList.h"
#include "gfxScriptItemizer.h"
#include "nsUnicodeProperties.h"
#include "nsStyleConsts.h"
#include "nsStyleUtil.h"
#include "mozilla/Likely.h"
#include "gfx2DGlue.h"
#include "gfxUserFontSet.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h" // for gfxCriticalError
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/intl/Locale.h"
#include "mozilla/intl/String.h"
#include "mozilla/intl/UnicodeProperties.h"
#include "mozilla/Likely.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPresData.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "nsStyleConsts.h"
#include "nsStyleUtil.h"
#include "nsUnicodeProperties.h"
#include "SharedFontList-impl.h"
#include "TextDrawTarget.h"
@ -2555,6 +2557,45 @@ template already_AddRefed<gfxTextRun> gfxFontGroup::MakeTextRun(
gfx::ShapedTextFlags aFlags, nsTextFrameUtils::Flags aFlags2,
gfxMissingFontRecorder* aMFR);
// Helper to get a hashtable that maps tags to Script codes, created on first
// use.
static const nsTHashMap<nsUint32HashKey, Script>* ScriptTagToCodeTable() {
using TableT = nsTHashMap<nsUint32HashKey, Script>;
// Initialize our static var by creating the hashtable and populating it with
// all the valid codes.
// According to
// https://en.cppreference.com/w/cpp/language/storage_duration#Static_block_variables:
// "If multiple threads attempt to initialize the same static local variable
// concurrently, the initialization occurs exactly once."
static UniquePtr<TableT> sScriptTagToCode = []() {
auto tagToCode = MakeUnique<TableT>(size_t(Script::NUM_SCRIPT_CODES));
Script scriptCount =
Script(std::min<int>(UnicodeProperties::GetMaxNumberOfScripts() + 1,
int(Script::NUM_SCRIPT_CODES)));
for (Script s = Script::ARABIC; s < scriptCount;
s = Script(static_cast<int>(s) + 1)) {
uint32_t tag = GetScriptTagForCode(s);
if (tag != HB_SCRIPT_UNKNOWN) {
tagToCode->InsertOrUpdate(tag, s);
}
}
// Clearing the UniquePtr at shutdown will free the table. The call to
// ClearOnShutdown has to be done on the main thread, even if this
// initialization happens from a worker.
if (NS_IsMainThread()) {
ClearOnShutdown(&sScriptTagToCode);
} else {
NS_DispatchToMainThread(
NS_NewRunnableFunction("ClearOnShutdown(sScriptTagToCode)",
[]() { ClearOnShutdown(&sScriptTagToCode); }));
}
return tagToCode;
}();
return sScriptTagToCode.get();
}
template <typename T>
void gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
const T* aString, uint32_t aLength,
@ -2652,6 +2693,33 @@ void gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
.get()));
}
// If COMMON or INHERITED was not resolved, try to use the language code
// to guess a likely script.
if (run.mScript <= Script::INHERITED) {
// This assumes Script codes begin with COMMON and INHERITED, preceding
// codes for any "real" scripts.
MOZ_ASSERT(
run.mScript == Script::COMMON || run.mScript == Script::INHERITED,
"unexpected Script code!");
nsAutoCString lang;
mLanguage->ToUTF8String(lang);
Locale locale;
if (LocaleParser::TryParse(lang, locale).isOk()) {
if (locale.Script().Missing()) {
Unused << locale.AddLikelySubtags();
}
if (locale.Script().Present()) {
Span span = locale.Script().Span();
MOZ_ASSERT(span.Length() == 4);
uint32_t tag = TRUETYPE_TAG(span[0], span[1], span[2], span[3]);
Script script;
if (ScriptTagToCodeTable()->Get(tag, &script)) {
run.mScript = script;
}
}
}
}
if (textPtr) {
InitScriptRun(aDrawTarget, aTextRun, textPtr + run.mOffset, run.mOffset,
run.mLength, run.mScript, aMFR);