Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added branding/icons/BearBrowser.icns
Binary file not shown.
Binary file added branding/icons/bear-1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added branding/icons/bear-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added branding/icons/bear-16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added branding/icons/bear-256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added branding/icons/bear-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added branding/icons/bear-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added branding/icons/bear-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added branding/icons/bear-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added branding/icons/bear.ico
Binary file not shown.
13 changes: 13 additions & 0 deletions scripts/apply-bearbrowser-branding.sh
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@ while IFS= read -r -d '' icon_dir; do
[ "$icon_dirs_seen" -ge 50 ] && break
done < <(find "$workspace" -type d \( -iname '*icon*' -o -iname '*branding*' -o -iname '*browser*' \) -print0)

# Stage the pre-generated raster icon set (branding/icons/, built by
# scripts/generate-brand-icons.sh) into the workspace so `make dir`
# (scripts/bearbrowser-patches.py) can overwrite the librewolf-derived
# browser/branding/bearbrowser rasters (.icns/.ico/sized .png) with the bear.
# SVG-swapping alone (above) never changed the packaged app icons — the OSes
# consume the rasters compiled into the branding dir, not the SVGs.
if [ -d "$repo_root/branding/icons" ] && [ "$dry_run" != "true" ]; then
mkdir -p "$workspace/branding-icons"
cp "$repo_root/branding/icons/"* "$workspace/branding-icons/"
echo "branding-icons: staged $(ls "$repo_root/branding/icons" | wc -l | tr -d ' ') raster assets -> workspace/branding-icons/"
changed=$((changed + 1))
fi

# Ensure a BearBrowser app id marker exists for downstream package steps.
if [ "$dry_run" != "true" ]; then
mkdir -p "$workspace/.bearbrowser"
Expand Down
11 changes: 11 additions & 0 deletions scripts/bearbrowser-package-source-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,18 @@ PY

# ── Step 3: Install BearBrowser icon ─────────────────────────────────────────
echo "[3/6] Installing BearBrowser icon..."
# Info.plist sets CFBundleIconFile=BearBrowser, which macOS resolves to
# Contents/Resources/BearBrowser.icns — an SVG is NOT a valid bundle icon, so
# the .icns (generated by scripts/generate-brand-icons.sh) is the load-bearing
# file here. The SVG is kept alongside for in-app/about uses.
icon_icns="$repo_root/branding/icons/BearBrowser.icns"
icon_svg="$repo_root/branding/bearbrowser.svg"
if [ -f "$icon_icns" ]; then
cp "$icon_icns" "$out_app/Contents/Resources/BearBrowser.icns"
echo " BearBrowser.icns installed (CFBundleIconFile target)"
else
echo " WARNING: $icon_icns not found — app will show a generic icon"
fi
if [ -f "$icon_svg" ]; then
cp "$icon_svg" "$out_app/Contents/Resources/BearBrowser.svg"
echo " BearBrowser.svg installed"
Expand Down
41 changes: 41 additions & 0 deletions scripts/bearbrowser-patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,47 @@ def _strip_l10n_base(_path):
_shutil.copytree(str(_lw_brand), str(_bb_brand))
print(f"Created {_bb_brand} from {_lw_brand}")

# ── Bear icons: overwrite the librewolf-derived rasters ──────────────────
# The branding dir copied above still carries LibreWolf's raster icons —
# the files the OSes actually display (.icns compiled into the .app, .ico
# compiled into firefox.exe by rc, sized .png shipped for Linux). Overwrite
# them with the bear set staged by apply-bearbrowser-branding.sh
# (workspace/branding-icons/, generated from branding/bearbrowser.svg by
# scripts/generate-brand-icons.sh). Square .png slots are matched by their
# real IHDR pixel size (exact match only — never ship a wrong-size png);
# non-square art (wordmarks) is left alone.
_icons_src = Path("../branding-icons")
if _icons_src.is_dir() and _bb_brand.exists():
def _png_size(p):
try:
with open(p, "rb") as f:
h = f.read(24)
if h[:8] != b"\x89PNG\r\n\x1a\n":
return None
return (int.from_bytes(h[16:20], "big"), int.from_bytes(h[20:24], "big"))
except OSError:
return None
_icns = _icons_src / "BearBrowser.icns"
_ico = _icons_src / "bear.ico"
_replaced = 0
for _f in sorted(_bb_brand.rglob("*")):
if not _f.is_file():
continue
_suf = _f.suffix.lower()
if _suf == ".icns" and _icns.exists():
_shutil.copy(str(_icns), str(_f)); _replaced += 1
elif _suf == ".ico" and _ico.exists():
_shutil.copy(str(_ico), str(_f)); _replaced += 1
elif _suf == ".png":
_sz = _png_size(_f)
if _sz and _sz[0] == _sz[1]:
_bear_png = _icons_src / f"bear-{_sz[0]}.png"
if _bear_png.exists():
_shutil.copy(str(_bear_png), str(_f)); _replaced += 1
print(f"-> Bear icons: replaced {_replaced} raster(s) in {_bb_brand}")
else:
print("note: ../branding-icons not staged — keeping librewolf rasters")

# copy the right search-config.json file
exec('cp -v ../assets/search-config.json services/settings/dumps/main/search-config.json')

Expand Down
83 changes: 83 additions & 0 deletions scripts/generate-brand-icons.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env bash
# generate-brand-icons.sh — rasterize branding/bearbrowser.svg into the platform
# icon formats the OSes actually use, committed under branding/icons/:
#
# bear-{16,32,48,64,128,256,512,1024}.png (Linux window/desktop icons + sources)
# BearBrowser.icns (macOS app bundle icon)
# bear.ico (Windows exe/installer icon, multi-size)
#
# Run manually on macOS after changing the SVG (uses qlmanage + iconutil + sips +
# Pillow — all present on a stock dev Mac). CI never runs this; the build lanes
# consume the committed assets (scripts/bearbrowser-patches.py overwrites the
# librewolf-derived browser/branding/bearbrowser rasters with these).
#
# Gotcha encoded: qlmanage renders SVG at high quality but bakes an OPAQUE WHITE
# background — the rounded-rect corners must be re-masked to transparent or the
# icon ships with white corners. The mask radius mirrors the SVG (rx=112 at 512).
set -euo pipefail

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
svg="$repo_root/branding/bearbrowser.svg"
out="$repo_root/branding/icons"
[ -f "$svg" ] || { echo "ERROR: $svg missing" >&2; exit 1; }
command -v qlmanage >/dev/null || { echo "ERROR: qlmanage (macOS) required" >&2; exit 1; }
command -v iconutil >/dev/null || { echo "ERROR: iconutil (macOS) required" >&2; exit 1; }
python3 -c 'import PIL' 2>/dev/null || { echo "ERROR: Pillow required (pip install Pillow)" >&2; exit 1; }

mkdir -p "$out"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

echo "[1/4] Rendering SVG at 1024px (QuickLook)..."
qlmanage -t -s 1024 -o "$tmp" "$svg" >/dev/null
base="$tmp/$(basename "$svg").png"
[ -f "$base" ] || { echo "ERROR: qlmanage produced no PNG" >&2; exit 1; }

echo "[2/4] Masking rounded corners to transparent + generating PNG sizes..."
python3 - "$base" "$out" <<'PY'
import sys
from PIL import Image, ImageDraw

base_path, out = sys.argv[1], sys.argv[2]
im = Image.open(base_path).convert("RGBA")
w = im.width # 1024
radius = round(112 / 512 * w) # SVG: rx=112 on a 512 viewBox

mask = Image.new("L", (w, w), 0)
ImageDraw.Draw(mask).rounded_rectangle([0, 0, w - 1, w - 1], radius=radius, fill=255)
im.putalpha(mask)

for size in (16, 32, 48, 64, 128, 256, 512, 1024):
scaled = im if size == w else im.resize((size, size), Image.LANCZOS)
scaled.save(f"{out}/bear-{size}.png")
print(f" bear-{size}.png")
PY

echo "[3/4] Building BearBrowser.icns (iconutil)..."
iconset="$tmp/BearBrowser.iconset"
mkdir -p "$iconset"
cp "$out/bear-16.png" "$iconset/icon_16x16.png"
cp "$out/bear-32.png" "$iconset/icon_16x16@2x.png"
cp "$out/bear-32.png" "$iconset/icon_32x32.png"
cp "$out/bear-64.png" "$iconset/icon_32x32@2x.png"
cp "$out/bear-128.png" "$iconset/icon_128x128.png"
cp "$out/bear-256.png" "$iconset/icon_128x128@2x.png"
cp "$out/bear-256.png" "$iconset/icon_256x256.png"
cp "$out/bear-512.png" "$iconset/icon_256x256@2x.png"
cp "$out/bear-512.png" "$iconset/icon_512x512.png"
cp "$out/bear-1024.png" "$iconset/icon_512x512@2x.png"
iconutil -c icns "$iconset" -o "$out/BearBrowser.icns"
echo " BearBrowser.icns"

echo "[4/4] Building bear.ico (Pillow, multi-size)..."
python3 - "$out" <<'PY'
import sys
from PIL import Image
out = sys.argv[1]
im = Image.open(f"{out}/bear-256.png")
im.save(f"{out}/bear.ico", sizes=[(16,16),(24,24),(32,32),(48,48),(64,64),(128,128),(256,256)])
print(" bear.ico")
PY

echo "Done → $out"
ls -la "$out"
Loading