dom/encoding/FallbackEncoding.cpp
author Bobby Holley <bobbyholley@gmail.com>
Fri, 31 Jan 2014 14:51:41 -0800
changeset 166310 8c206e77eb64ed7671ced59ddf599c4af79351ed
parent 159791 98be0e9cbc152f4313ef9adbbc0b6925ef7d0123
child 167159 a4e9e8bead92c9d51d4e478a73e8e589263e92ae
permissions -rw-r--r--
Bug 962449 - Don't call initIteratorClasses directly, and use ensureConstructor. r=luke This isn't strictly necessary at this point. The basic issue is that there are a few new classes (iterator stuff, intl stuff, and typed objects) that use this kind of constructor bootstrap scheme, and each of them will need something like this to move to ClassSpecs. But that doesn't actually need to happen until we convert them. I wrote this patch before I realized this, and I believe it's correct, so I figured I'd get it landed along with everything. But I'm also ok to skip it for now.

/* 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 "mozilla/dom/FallbackEncoding.h"

#include "mozilla/dom/EncodingUtils.h"
#include "nsUConvPropertySearch.h"
#include "nsIChromeRegistry.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"

namespace mozilla {
namespace dom {

static const char* localesFallbacks[][3] = {
#include "localesfallbacks.properties.h"
};

FallbackEncoding* FallbackEncoding::sInstance = nullptr;

FallbackEncoding::FallbackEncoding()
{
  MOZ_COUNT_CTOR(FallbackEncoding);
  MOZ_ASSERT(!FallbackEncoding::sInstance,
             "Singleton already exists.");
}

FallbackEncoding::~FallbackEncoding()
{
  MOZ_COUNT_DTOR(FallbackEncoding);
}

void
FallbackEncoding::Get(nsACString& aFallback)
{
  if (!mFallback.IsEmpty()) {
    aFallback = mFallback;
    return;
  }

  const nsAdoptingCString& override =
    Preferences::GetCString("intl.charset.fallback.override");
  // Don't let the user break things by setting the override to unreasonable
  // values via about:config
  if (!EncodingUtils::FindEncodingForLabel(override, mFallback) ||
      !EncodingUtils::IsAsciiCompatible(mFallback) ||
      mFallback.EqualsLiteral("UTF-8")) {
    mFallback.Truncate();
  }

  if (!mFallback.IsEmpty()) {
    aFallback = mFallback;
    return;
  }

  nsAutoCString locale;
  nsCOMPtr<nsIXULChromeRegistry> registry =
    mozilla::services::GetXULChromeRegistryService();
  if (registry) {
    registry->GetSelectedLocale(NS_LITERAL_CSTRING("global"), locale);
  }

  // Let's lower case the string just in case unofficial language packs
  // don't stick to conventions.
  ToLowerCase(locale); // ASCII lowercasing with CString input!

  // Special case Traditional Chinese before throwing away stuff after the
  // language itself. Today we only ship zh-TW, but be defensive about
  // possible future values.
  if (locale.EqualsLiteral("zh-tw") ||
      locale.EqualsLiteral("zh-hk") ||
      locale.EqualsLiteral("zh-mo") ||
      locale.EqualsLiteral("zh-hant")) {
    mFallback.AssignLiteral("Big5");
    aFallback = mFallback;
    return;
  }

  // Throw away regions and other variants to accommodate weird stuff seen
  // in telemetry--apparently unofficial language packs.
  int32_t index = locale.FindChar('-');
  if (index >= 0) {
    locale.Truncate(index);
  }

  if (NS_FAILED(nsUConvPropertySearch::SearchPropertyValue(
      localesFallbacks, ArrayLength(localesFallbacks), locale, mFallback))) {
    mFallback.AssignLiteral("windows-1252");
  }

  aFallback = mFallback;
}

void
FallbackEncoding::FromLocale(nsACString& aFallback)
{
  MOZ_ASSERT(FallbackEncoding::sInstance,
             "Using uninitialized fallback cache.");
  FallbackEncoding::sInstance->Get(aFallback);
}

// PrefChangedFunc
void
FallbackEncoding::PrefChanged(const char*, void*)
{
  MOZ_ASSERT(FallbackEncoding::sInstance,
             "Pref callback called with null fallback cache.");
  FallbackEncoding::sInstance->Invalidate();
}

void
FallbackEncoding::Initialize()
{
  MOZ_ASSERT(!FallbackEncoding::sInstance,
             "Initializing pre-existing fallback cache.");
  FallbackEncoding::sInstance = new FallbackEncoding;
  Preferences::RegisterCallback(FallbackEncoding::PrefChanged,
                                "intl.charset.fallback.override",
                                nullptr);
  Preferences::RegisterCallback(FallbackEncoding::PrefChanged,
                                "general.useragent.locale",
                                nullptr);
}

void
FallbackEncoding::Shutdown()
{
  MOZ_ASSERT(FallbackEncoding::sInstance,
             "Releasing non-existent fallback cache.");
  delete FallbackEncoding::sInstance;
  FallbackEncoding::sInstance = nullptr;
}

} // namespace dom
} // namespace mozilla