# Maintainer (arch): Jan Alexander Steffens (heftig) <heftig@archlinux.org>
# Contributor: Ionut Biru <ibiru@archlinux.org>
# Contributor: Jakub Schmidtke <sjakub@gmail.com>
# Contributor: Henry Jensen <hjensen@connochaetos.org>
# Maintainer (archarm): Kevin Mihelich <kevin@archlinuxarm.org>
# Maintainer (arch32): Andreas Baumann <mail@andreasbaumann.cc>
# Contributor: Erich Eckner <git@eckner.net>
# Contributor: Andreas Grapentin <andreas@grapentin.org>
# Contributor: Luke Shumaker <lukeshu@parabola.nu>
# Contributor: André Silva <emulatorman@hyperbola.info>
# Contributor: Márcio Silva <coadde@hyperbola.info>
# Contributor: fauno <fauno@kiwwwi.com.ar>
# Contributor: vando <facundo@esdebian.org>
# Contributor: Figue <ffigue at gmail>
# Contributor: evr <evanroman at gmail>
# Contributor: Muhammad 'MJ' Jassim <UnbreakableMJ@gmail.com>
# Contributor: taro-k <taro-k@movasense_com>
# Contributor: Michał Masłowski <mtjm@mtjm.eu>
# Contributor: Luke R. <g4jc@openmailbox.org>
# Contributor: Isaac David <isacdaavid@isacdaavid.info>
# Contributor: bill-auger <bill-auger@programmer.net>
# Contributor: grizzlyuser <grizzlyuser@protonmail.com>


# parabola changes and rationale
# FSDG:
#  - Modify the addons pages to use GNU IceCat plugins sources, rather
#    than addons.mozilla.org, which hosts non-free addons
#  - Disable EME, which is implemented via the non-free libWideVine CDM
#  - Disable Normandy that let Mozilla push messages with recommendations
#    of nonfree software
#  - Make Remote Settings work completely offline using local data
#  - Rebrand to Iceweasel, per the mozilla trademark policy,
#    due to these FSDG changes
#
# technical:
#  - build i686 with GCC instead of clang
#  - disable rust-SIMD, LTO, PGO, and skip profiling build for armv7h and i686
#  - allow skipping profiling build for x86_64 (_x86_64_skip_pgo)
#  - prefer as many system libs as possible, over their vendored couterparts
# 
# privacy:
#  - Remove Google API keys and usage
#  - Disable Mozilla telemetry and crash reporting (good manners
#    because of all of the other patching we're doing)


pkgname=iceweasel
epoch=1
pkgver=88.0.1
pkgrel=1
pkgrel+=.parabola1
_brandingver=87.0-1
pkgdesc="Standalone web browser derived from Mozilla Firefox"
arch=(x86_64)
arch+=(i686 armv7h)
license=(MPL GPL LGPL)
url="https://wiki.parabola.nu/Iceweasel"
depends=(gtk3 libxt mime-types dbus-glib ffmpeg nss ttf-font libpulse)
makedepends=(unzip zip diffutils yasm mesa imake inetutils xorg-server-xvfb
             autoconf2.13 rust clang llvm jack gtk2 nodejs cbindgen nasm
             python-setuptools python-psutil python-zstandard lld dump_syms)
makedepends+=(quilt libxslt imagemagick git jq python-jsonschema)
optdepends=('networkmanager: Location detection via available WiFi networks'
            'libnotify: Notification integration'
            'pulseaudio: Audio support'
            'speech-dispatcher: Text-to-Speech'
            'hunspell-en_US: Spell checking, American English')
replaces=('firefox')
options=(!emptydirs !makeflags !strip)
source=(https://archive.mozilla.org/pub/firefox/releases/$pkgver/source/firefox-$pkgver.source.tar.xz{,.asc}
        0001-Use-remoting-name-for-GDK-application-names.patch
        $pkgname.desktop)
source+=(https://repo.parabola.nu/other/iceweasel/${pkgname}_${_brandingver}.branding.tar.xz{,.sig}
         9001-always-sync-remote-settings-with-local-dump.patch
         9002-preference-defaults.patch
         9003-misc-libre.patch
         process-json-files.py
         vendor.js.in)
source_armv7h=(arm.patch
               build-arm-libopus.patch)
source_i686=('avoid-libxul-OOM-python-check.patch'
             'rust-static-disable-network-test-on-static-libraries.patch')
sha256sums=('83df1eae0e28fe99661fd5d39d705cdab2e108b4a24ce12c2db6183c632804cc'
            'SKIP'
            '1b6814e85f13dcf069482ad1acfc1a099661922c85e3344aa4ee059288506ccc'
            '9cdc2602661717712092d28bb494e5b48e518cb930898aca85eaf21f91f7ef58')
sha256sums+=('e0a0c7434a057dffdce49bb3e5f53fa190aef24f2666cdc50262170df8fec94f'
             'SKIP'
             'be579cc7aa0674a35485b7a5a37f69a2c8b144b72362621db4b699e5a2741f19'
             '219648efd053ffff3411dfd85935e1e9aabfcaf5bbbf65caad3d4f7300452859'
             '39e3a5e1ad137e21f842a44d7e3bd24050292d2b41fe59b4e7c7dfed52a195dd'
             '90e710662f06c619de8752b088ce56bf3779f24168387b1c18e733391bedd143'
             '4e4ef3f5643da6a23b05de9266c1b2c5310483638b23670944374e12aa446a35')
sha256sums_i686=('2f0c81a38c4578f68f5456b618fe84a78974072821488173eb55e0e72287e353'
                 '10c5276eab2e87f400a6ec15d7ffbef3b0407ee888dea36f1128927ca55b9041')
sha256sums_armv7h=('bc00516032330760444939c516a60c78f868631e1b37f075f0fe71a53737b966'
                   '2d4d91f7e35d0860225084e37ec320ca6cae669f6c9c8fe7735cdbd542e3a7c9')
validpgpkeys=('14F26682D0916CDD81E37B6D61B7B526D98F0353') # Mozilla Software Releases <release@mozilla.com>
validpgpkeys+=('BFA8008A8265677063B11BF47171986E4B745536') # Andreas Grapentin
validpgpkeys+=('3954A7AB837D0EA9CFA9798925DB7D9B5A8D4B40') # bill-auger


# PGO requires networking
_should_skip_pgo_armv7h=1 # disable for armv7h - always
_should_skip_pgo_i686=1   # disable for i686   - always
_should_skip_pgo_x86_64=0 # disable for x86_64 - libremakepkg
eval "_should_skip_pgo=\$_should_skip_pgo_${CARCH}"


_check_build_config() {
  pushd "$srcdir/firefox-${pkgver%_*}" > /dev/null

  echo "Checking build configuration..."

  # Configure produces mozinfo.json that reflects current configuration.
  # See build/docs/mozinfo.rst
  ./mach configure

  # In this test, jq collects values of the following keys of mozinfo.json into array,
  # and checks if any of them are not equal to false, in which case it returns "true".
  # E.g. if the value of any key is true or null (in case the key is missing from mozinfo.json),
  # that means the build configuration has to be reworked.
  local obj_directory=$(./mach environment | sed -En '/object directory:/{n;s/^\s+//;p;}')
  local antifeature_keys=(.crashreporter .datareporting .healthreport .normandy .telemetry .updater)
  local antifeatures=()
  echo "obj_directory is: ${obj_directory}"
  for key in ${antifeature_keys[@]}
  do  jq -e "${key} != false" "${obj_directory}"/mozinfo.json && antifeatures+=(${key})
  done
  if   (( ${#antifeatures[@]} ))
  then echo "Some anti-features are not disabled in build configuration files, aborting:"
       for key in ${antifeatures[@]} ; do echo "  - ${key} is enabled" ; done ;
       return 1
  fi

  popd > /dev/null
}

prepare() {
  mkdir mozbuild
  cd firefox-$pkgver

  # https://bugzilla.mozilla.org/show_bug.cgi?id=1530052
  patch -Np1 -i ../0001-Use-remoting-name-for-GDK-application-names.patch

  cat >../mozconfig <<END
ac_add_options --enable-application=browser
mk_add_options MOZ_OBJDIR=${PWD@Q}/obj

ac_add_options --prefix=/usr
ac_add_options --enable-release
ac_add_options --enable-hardening
ac_add_options --enable-optimize
ac_add_options --enable-rust-simd
ac_add_options --enable-linker=lld
ac_add_options --disable-elf-hack

# Branding
ac_add_options --disable-official-branding
ac_add_options --with-branding=browser/branding/iceweasel
ac_add_options --enable-update-channel=release
ac_add_options --with-distribution-id=nu.parabola
ac_add_options --with-unsigned-addon-scopes=app,system
ac_add_options --allow-addon-sideload
export MOZ_APP_NAME=$pkgname
export MOZ_APP_REMOTINGNAME=${pkgname}
export MOZ_TELEMETRY_REPORTING=
export MOZ_REQUIRE_SIGNING=

# System libraries
ac_add_options --with-system-nspr
ac_add_options --with-system-nss

# Features
ac_add_options --enable-alsa
ac_add_options --enable-jack
ac_add_options --disable-crashreporter
ac_add_options --disable-updater
ac_add_options --disable-tests
ac_add_options --disable-eme
END


  ## [ARCH-SPECIFIC CONFIG] ##

  case ${CARCH} in
    armv7h)
      sed -i '
        /--enable-hardening/d
        /--enable-optimize/d
        /--enable-rust-simd/d
      ' ../mozconfig

      cat >>../mozconfig <<END
export CC=clang
export CXX=clang++
ac_add_options --disable-webrtc
ac_add_options --disable-elf-hack

# https://bugzilla.redhat.com/show_bug.cgi?id=1641623
ac_add_options --disable-av1
ac_add_options --enable-optimize="-g0 -O2"
mk_add_options MOZ_MAKE_FLAGS='-j2'
END

      # mozbuild.configure.options.InvalidOptionError: --disable-eme is not available in this configuration
      # EME is disabled anyway in the built package, but better check if it exists for ARM each new release.
      sed -i 's|ac_add_options --disable-eme||' ../mozconfig

      echo "applying arm.patch"
      patch -p1 -i ../arm.patch
      echo "applying build-arm-libopus.patch"
      patch -p1 -i ../build-arm-libopus.patch
    ;;
    i686)
      # disable LTO and use gcc toolchain (clang has issues on IA32)
      # disable SIMD (SSE2 for i686)
      export MOZ_SOURCE_CHANGESET="DEVEDITION_${pkgver//./_}_RELEASE"
      cat >>../mozconfig <<END
ac_add_options --disable-linker=lld
ac_add_options --enable-linker=bfd
ac_add_options --disable-lto
ac_add_options --disable-rust-simd
export CC=gcc
export CXX=g++
export AR=gcc-ar
export NM=gcc-nm
export RANLIB=gcc-ranlib
END

      # readelf: Error: Unable to seek to 0x801db328 for section headers
      echo "applying avoid-libxul-OOM-python-check.patch"
      patch -p1 -i ../avoid-libxul-OOM-python-check.patch

      # test failure in rust code (complaining about network functions) when PGO is used,
      # see https://bugzilla.mozilla.org/show_bug.cgi?id=1565757
      echo "applying rust-static-disable-network-test-on-static-libraries.patch"
      patch -p1 -i ../rust-static-disable-network-test-on-static-libraries.patch
    ;;
    x86_64)
    ;;
    *) echo "no [ARCH-SPECIFIC CONFIG] for arch: ${CARCH}" ; return 1 ;
    ;;
  esac


  ## branding ##

  echo "applying parabola branding"
  local brandingsrcdir="${srcdir}"/${pkgname}-${_brandingver/-*}
  local brandingdestdir=browser/branding/${pkgname}
  rm -rf -- ${brandingdestdir}
  cp -aT -- ${brandingsrcdir}/branding ${brandingdestdir}
  cp "${brandingdestdir}"/iceweasel_logo.svg "${brandingdestdir}"/content/aboutlogins.svg
  cp "${brandingdestdir}"/iceweasel_logo.svg "${brandingdestdir}"/content/about-logo.svg

  # produce icons
  for i in 16 22 24 32 48 64 128 192 256 384; do
    rsvg-convert -w ${i} -h ${i} "${brandingsrcdir}"/branding/${pkgname}_icon.svg \
                 -o "${brandingdestdir}"/default${i}.png
  done

  # custom new tab page
  # FIXME: the newtab page (aka "Start Page") has changed significantly
  #        the new upstream start page ('activity-streams') is an add-on now
  #        it must be forked and customized externally, then copied into the browser tree
  #        see: the branding-dev-build/ dir on the '68.0' branch of the branding git repo
  #        some of the branding components above and commented out below may no longer be used
  #        the following section aims to restore something similar
  #          to the previous parabola-branded "start page"
  #        once it is working well, all of these comments should be removed
  #          and any unused branding components may be deleted from the branding package
  # Put "Start Page" branding images in the source code
  #install -m644 -t browser/base/content/abouthome -- \
  #  "${brandingsrcdir}/branding"/{drm-free,gnu_headshadow,parabola-banner}.png
  #install -m644 -t browser/extensions/onboarding/content/img -- \
  #   "${brandingsrcdir}/branding/watermark.svg"

  # process default Top Sites and their icons
  local tippytopdir=browser/components/newtab/data/content/tippytop
  find ${tippytopdir} -type f      \
       -not -name 'wikipedia-org*' \
       -not -name 'top_sites.json' \
       -exec rm -v {} \;
  for image in "${brandingsrcdir}"/tippytop/*.svg; do
    local outname=$(basename -s .svg "${image}")
    local size=$(identify -format '%wx%h' ${tippytopdir}/images/wikipedia-org@2x.png)
    local background=$( [[ "${outname}" == 'gnu' ]] && echo 'white' || echo 'none' )
    magick -density 300 ${image}                           \
           -gravity center -resize ${size} -extent ${size} \
           "${tippytopdir}/images/${outname}@2x.png"

    size=256x256
    magick -density 300 -background ${background} ${image} \
           -gravity center -resize ${size} -extent ${size} \
           -define icon:auto-resize=64,48,32,16            \
           "${tippytopdir}/favicons/${outname}.ico"
  done

  # apply branding patches
  export QUILT_PATCHES="${brandingsrcdir}"/patches
  export QUILT_REFRESH_ARGS='-p ab --no-timestamps --no-index'
  export QUILT_DIFF_ARGS='--no-timestamps'
  export QUILT_PC="${srcdir}"/.pc
  quilt push -av


  ## searchengines ##

  pushd browser/components/search/extensions

  # Patch search-engines configs
  sed -i 's|https://duckduckgo.com/|https://html.duckduckgo.com/html/|' ddg/manifest.json

  # Removing URL parameters that let DuckDuckGo know the place in UI
  # the search was ran from (like address bar, context menu, etc.)
  local jq_cmd='del(.chrome_settings_overrides.search_provider.params)'
  jq "${jq_cmd}" ddg/manifest.json > manifest.json.tmp
  ! diff manifest.json.tmp ddg/manifest.json > /dev/null
  mv manifest.json.tmp ddg/manifest.json

  # Delete unused search engine configs
  find -mindepth 1 -maxdepth 1 \
       -not -name ddg \
       -not -name wikipedia \
       -exec rm -frv {} \;

  popd


  ## libre patching ##

  # Upstream tarball can contain some ignored cruft,
  # including binaries (for example, python3).
  echo 'Removing files specified in .gitignore...'
  git init && git clean -dfX \
    -e '!ipc/chromium/src/third_party/libevent/evconfig-private.h' \
    -e '!toolkit/crashreporter/google-breakpad/src/third_party/lss/' \
    -e '!third_party/python/**/*.egg-info/'
  rm -rf .git

  # Remove test-related networking dumps, because they contain code from
  # some Amazon webpage with no clear licensing, thus nonfree.
  # Also they interfere with checking of Remote Settings patching done later,
  # because communication with RS server has been captured in them too.
  rm python/mozperftest/mozperftest/system/example.zip
  rm testing/mozbase/mozproxy/tests/files/mitm5-linux-firefox-amazon.zip

  # Disable/neutralize Remote Settings (as best we can)
  echo "applying 9001-always-sync-remote-settings-with-local-dump.patch"
  patch -Np1 --no-backup-if-mismatch -i ../9001-always-sync-remote-settings-with-local-dump.patch

  # Verify Remote Settings patching
  local settings_server='firefox.settings.services.mozilla.com'
  ! grep -qr $settings_server || { echo 'Remote Settings patching needs rework'; return 1; }

  # Disable various components at the source level
  sed -i 's/;1/;0/' toolkit/components/telemetry/components.conf
  sed -Ei 's/((MOZ_SERVICES_HEALTHREPORT|MOZ_NORMANDY).+)True/\1False/' browser/moz.configure
  #sed -i 's/;1/;0/' browser/experiments/Experiments.manifest
  #sed -i '/pocket/d'          browser/extensions/moz.build
  #sed -i '/activity-stream/d' browser/extensions/moz.build

  python ../process-json-files.py "${srcdir}"/firefox-${pkgver} "${brandingsrcdir}"

  echo "applying 9002-preference-defaults.patch"
  patch -Np1 --no-backup-if-mismatch -i "${srcdir}"/9002-preference-defaults.patch

  # Remove remaining non-free bits
  echo "applying 9003-misc-libre.patch"
  patch -Np1 --no-backup-if-mismatch -i "${srcdir}"/9003-misc-libre.patch
}

build() {
  cd firefox-$pkgver

  ## build env ##

  export MOZ_NOSPAM=1
  export MOZBUILD_STATE_PATH="$srcdir/mozbuild"
  export MACH_USE_SYSTEM_PYTHON=1

  # LTO needs more open files
  ulimit -n 4096

  # clang-{9,10,11} -> error: unknown argument: '-fvar-tracking-assignments'
  CFLAGS="${CFLAGS/-fvar-tracking-assignments/}"
  CXXFLAGS="${CXXFLAGS/-fvar-tracking-assignments/}"


  ## [ARCH-SPECIFIC BUILD ENV] ##

  case ${CARCH} in
    armv7h)
      export MOZ_DEBUG_FLAGS=" "
      export CFLAGS+=" -g0"
      export CXXFLAGS+=" -g0"
      export LDFLAGS+=" -Wl,--no-keep-memory"
      export RUSTFLAGS="-Cdebuginfo=0"
    ;;
    i686)
      # -fno-plt with cross-LTO -> LLVM ERROR: Function Import: link error
      CFLAGS="${CFLAGS/-fno-plt/}"
      CXXFLAGS="${CXXFLAGS/-fno-plt/}"

      # disable LTO (clang has issues on IA32)
      export RUSTFLAGS+=" -Cdebuginfo=0 -Clto=off"
      export LDFLAGS+=" -Wl,--no-keep-memory -Wl,--reduce-memory-overheads"

      # libvpx has some hard-coded compiler flags for MMX, SSE, SSE2, use the correct one
      # per CARCH (75.0 uses an intrisic _mm_empty now, which required the corresponding
      # architecture flag to be preset - before it was merely embedding some assembly
      # code with EMMS
      export CFLAGS+=" -mmmx"
      export CXXFLAGS+=" -mmmx"
    ;;
    x86_64)
    ;;
    *) echo "no [ARCH-SPECIFIC BUILD ENV] for arch: ${CARCH}" ; return 1 ;
    ;;
  esac
  export CFLAGS
  export CXXFLAGS


  ## [ARCH-SPECIFIC BUILD CONFIG] ##

  case ${CARCH} in
    armv7h)
    ;;
    i686)
      # avoid excessive debug symbols in rust leading to out-of-memory situations
      sed -i "s/debug_info = '\''2'\''/debug_info = '\''0'\''/" build/moz.configure/toolchain.configure
    ;;
    x86_64)
    ;;
    *) echo "no [ARCH-SPECIFIC BUILD CONFIG] for arch: ${CARCH}" ; return 1 ;
    ;;
  esac


  ## PGO build ##

  if (( $_should_skip_pgo ))
  then
    # skipping "3-tier PGO" "instrumented browser", to avoid OOM problems;
    # so we have the final .mozconfig now
    cp ../mozconfig .mozconfig
  else
    # Do 3-tier PGO
    echo "Building instrumented browser..."
    cat >.mozconfig ../mozconfig - <<END
ac_add_options --enable-profile-generate=cross
END
    _check_build_config
    ./mach build

    echo "Profiling instrumented browser..."
    ./mach package
    LLVM_PROFDATA=llvm-profdata \
      JARLOG_FILE="$PWD/jarlog" \
      xvfb-run -s "-screen 0 1920x1080x24 -nolisten local" \
      ./mach python build/pgo/profileserver.py

    if [[ ! -s merged.profdata ]]; then
      echo "No profile data produced."
      return 1
    fi

    if [[ ! -s jarlog ]]; then
      echo "No jar log produced."
      return 1
    fi

    echo "Removing instrumented browser..."
    ./mach clobber

    cat >.mozconfig ../mozconfig - <<END
ac_add_options --enable-lto=cross
ac_add_options --enable-profile-use=cross
ac_add_options --with-pgo-profile-path=${PWD@Q}/merged.profdata
ac_add_options --with-pgo-jarlog=${PWD@Q}/jarlog
END
  fi # $_should_skip_pgo


  ## sanity checks ##

  # each of the [ARCH-SPECIFIC BUILD CONFIG] branches above should have created .mozconfig
  [[ ! -f .mozconfig ]] && echo ".mozconfig file not found in source root" && return 1
  _check_build_config


  ## main build ##

  echo "Building optimized browser..."
  ./mach build
}

package() {
  cd firefox-$pkgver
  DESTDIR="$pkgdir" ./mach install

  local vendorjs="$pkgdir/usr/lib/$pkgname/browser/defaults/preferences/vendor.js"
  install -Dvm644 /dev/stdin "$vendorjs" <<END
// Use LANG environment variable to choose locale
pref("intl.locale.requested", "");

// Use system-provided dictionaries
pref("spellchecker.dictionary_path", "/usr/share/hunspell");

// Disable default browser checking.
pref("browser.shell.checkDefaultBrowser", false);

// Don't disable extensions in the application directory
pref("extensions.autoDisableScopes", 11);
END

  # Parabola additions to vendor.js
  cat "${srcdir}"/vendor.js.in >> "${vendorjs}"

  local distini="$pkgdir/usr/lib/$pkgname/distribution/distribution.ini"
  install -Dvm644 /dev/stdin "$distini" <<END
[Global]
id=parabola
version=1.0
about=Iceweasel for Parabola GNU/Linux-libre

[Preferences]
app.distributor=parabola
app.distributor.channel=$pkgname
app.partner.parabola=parabola
END

  local i
  for i in 16 22 24 32 48 64 128 192 256 384; do
    install -Dvm644 browser/branding/$pkgname/default$i.png \
      "$pkgdir/usr/share/icons/hicolor/${i}x${i}/apps/$pkgname.png"
  done
  install -Dvm644 "browser/branding/$pkgname/${pkgname}_icon.svg" \
    "$pkgdir/usr/share/icons/hicolor/scalable/apps/$pkgname.svg"

  install -Dvm644 ../$pkgname.desktop \
    "$pkgdir/usr/share/applications/$pkgname.desktop"

  # Install a wrapper to avoid confusion about binary path
  install -Dvm755 /dev/stdin "$pkgdir/usr/bin/$pkgname" <<END
#!/bin/sh
exec /usr/lib/$pkgname/$pkgname "\$@"
END


  ## [ARCH-SPECIFIC INSTALL] ##

  case ${CARCH} in
    armv7h)
    ;;
    i686)
      # libxul.so cannot find it's libraries
      install -dm 755 "${pkgdir}"/etc/ld.so.conf.d
      echo "/usr/lib/${pkgname}" > "${pkgdir}"/etc/ld.so.conf.d/${pkgname}.conf
    ;;
    x86_64)
    ;;
    *) echo "no [ARCH-SPECIFIC INSTALL] for arch: ${CARCH}" ; return 1 ;
    ;;
  esac

  # Replace duplicate binary with wrapper
  # https://bugzilla.mozilla.org/show_bug.cgi?id=658850
  ln -srfv "$pkgdir/usr/bin/$pkgname" "$pkgdir/usr/lib/$pkgname/$pkgname-bin"

  # Use system certificates
  local nssckbi="$pkgdir/usr/lib/$pkgname/libnssckbi.so"
  if [[ -e $nssckbi ]]; then
    ln -srfv "$pkgdir/usr/lib/libnssckbi.so" "$nssckbi"
  fi
}
