Repository: xbmc/xbmc
File: xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitlesLibass.cpp (C++)

Code before:
  ass_renderer_done(m_renderer);
  ass_library_done(m_library);
}

void CDVDSubtitlesLibass::Configure()
{
  CLog::Log(LOGINFO, "CDVDSubtitlesLibass: Initializing ASS library font settings");

  if (!m_renderer)
  {
    CLog::Log(LOGERROR, "CDVDSubtitlesLibass: Failed to initialize ASS font settings. ASS renderer "
                        "not initialized.");
    return;
  }

  ass_set_margins(m_renderer, 0, 0, 0, 0);
  ass_set_use_margins(m_renderer, 0);

  std::string fontsDir = CSpecialProtocol::TranslatePath(FONT::FONTPATH::USER);
  int fontProvider = ASS_FONTPROVIDER_AUTODETECT;
  std::string fontconfigPath; // Keep string alive for lifetime of fontconfigConfig pointer
  const char* fontconfigConfig = nullptr;

#if defined(TARGET_ANDROID)
  // Use fontconfig with custom config pointing to Android system fonts.
  // Fontconfig provides automatic font fallback for all scripts (Malayalam, Tamil, Chinese, etc.).
  fontProvider = ASS_FONTPROVIDER_FONTCONFIG;

  // Create fontconfig cache directory
  std::string fontconfigCacheDir = CSpecialProtocol::TranslatePath("special://temp/fontconfig");
  XFILE::CDirectory::Create(fontconfigCacheDir);

  // Create fontconfig configuration programmatically
  // Escape XML special characters in paths to prevent XML injection
  std::string escapedFontsDir = fontsDir;
  StringUtils::Replace(escapedFontsDir, "&", "&amp;");
  StringUtils::Replace(escapedFontsDir, "<", "&lt;");
  StringUtils::Replace(escapedFontsDir, ">", "&gt;");
  StringUtils::Replace(escapedFontsDir, "\"", "&quot;");
  StringUtils::Replace(escapedFontsDir, "'", "&apos;");

  std::string systemFontsDir = CSpecialProtocol::TranslatePath(FONT::FONTPATH::SYSTEM);
  std::string escapedSystemFontsDir = systemFontsDir;
  StringUtils::Replace(escapedSystemFontsDir, "&", "&amp;");
  StringUtils::Replace(escapedSystemFontsDir, "<", "&lt;");
  StringUtils::Replace(escapedSystemFontsDir, ">", "&gt;");
  StringUtils::Replace(escapedSystemFontsDir, "\"", "&quot;");
  StringUtils::Replace(escapedSystemFontsDir, "'", "&apos;");

  std::string escapedCacheDir = fontconfigCacheDir;
  StringUtils::Replace(escapedCacheDir, "&", "&amp;");

Review comment (suggestion):
> // Use fontconfig with custom config pointing to Android system fonts.

All following code is clearly a _workaround / hack_ since Libass does not currently support native Android "fontconfig", this must be clearly specified, so instead to remove in full the original comment, it must be readapted

> // Fontconfig provides automatic font fallback for all scripts (Malayalam, Tamil, Chinese, etc.).

this comment is not required, is an intrinsic feature



Code after:
    ass_free_track(m_track);
  ass_renderer_done(m_renderer);
  ass_library_done(m_library);
}

void CDVDSubtitlesLibass::Configure()
{
  CLog::Log(LOGINFO, "CDVDSubtitlesLibass: Initializing ASS library font settings");

  if (!m_renderer)
  {
    CLog::Log(LOGERROR, "CDVDSubtitlesLibass: Failed to initialize ASS font settings. ASS renderer "
                        "not initialized.");
    return;
  }

  ass_set_margins(m_renderer, 0, 0, 0, 0);
  ass_set_use_margins(m_renderer, 0);

  int fontProvider = ASS_FONTPROVIDER_AUTODETECT;
  std::string fontconfigPath; // Keep string alive for lifetime of fontconfigConfig pointer
  const char* fontconfigConfig = nullptr;

#if defined(TARGET_ANDROID)
  // Libass uses system font provider (like fontconfig) by default on some platforms (e.g. Linux/Windows),
  // but on Android the font provider is currently not supported by libass.
  // Workaround: Use fontconfig with a custom configuration pointing to Android system fonts,
  // enabling automatic font fallback for subtitles with non-Latin scripts.
  // This is a temporary workaround until libass implements native Android font provider support.
  fontProvider = ASS_FONTPROVIDER_FONTCONFIG;

  // Write fontconfig configuration to temp directory
  fontconfigPath = CSpecialProtocol::TranslatePath("special://temp/fonts.conf");

  if (!XFILE::CFile::Exists(fontconfigPath))
  {
    // Create fontconfig cache directory
    const std::string fontconfigCacheDir =
        CSpecialProtocol::TranslatePath("special://temp/fontconfig");
    if (!XFILE::CDirectory::Exists(fontconfigCacheDir))
      XFILE::CDirectory::Create(fontconfigCacheDir);

    // Create fontconfig configuration using XML library
    CXBMCTinyXML2 xmlDoc;
    xmlDoc.InsertEndChild(xmlDoc.NewDeclaration("xml version=\"1.0\""));
    xmlDoc.InsertEndChild(xmlDoc.NewUnknown("DOCTYPE fontconfig SYSTEM \"fonts.dtd\""));

    tinyxml2::XMLElement* eRoot = xmlDoc.NewElement("fontconfig");
    xmlDoc.InsertEndChild(eRoot);

    auto addRootChildText = [&](const char* name, const std::string& value)