diff --git a/build/bromite_patches_list.txt b/build/bromite_patches_list.txt index 82131324..e6f215ee 100644 --- a/build/bromite_patches_list.txt +++ b/build/bromite_patches_list.txt @@ -282,6 +282,7 @@ Timezone-customization.patch 00Disable-Service-and-Shared-workers-on-3P-iframe.patch 00Disable-Real-Box.patch 00Always-allow-inspect-fallback.patch +00Add-cromite-flags-support.patch 00Temp-PerformanceNavigationTiming-privacy-fix.patch diff --git a/build/patches/00Add-cromite-flags-support.patch b/build/patches/00Add-cromite-flags-support.patch new file mode 100644 index 00000000..db181476 --- /dev/null +++ b/build/patches/00Add-cromite-flags-support.patch @@ -0,0 +1,840 @@ +From: uazo +Date: Sat, 18 Nov 2023 09:41:28 +0000 +Subject: Add cromite flags support + +Add SET_CROMITE_FEATURE_ENABLED*, SET_CROMITE_FEATURE_DISABLED* +and CROMITE_FEATURE macros, logic has been adapted from that found +in brave. +Allows flags to be defined in separate files. +Activates a new cromite tab in chrome://flags with only the flags +added and changed. In android added chrome://flags/cromite +in the setting ui. +Currently in wip + +Need: bromite-build-utils.patch +License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html +--- + base/BUILD.gn | 4 +- + base/feature_list.cc | 56 +++++++++++++ + base/feature_list.h | 84 ++++++++++++++++++- + build/android/gyp/java_cpp_features.py | 17 ++++ + chrome/android/java/res/values/values.xml | 3 + + .../java/res/xml/privacy_preferences.xml | 4 + + chrome/browser/about_flags.cc | 7 ++ + .../flags/android/chrome_feature_list.cc | 1 + + chrome/browser/ui/ui_features.cc | 1 + + chrome/common/chrome_features.cc | 1 + + components/flags_ui/flags_state.cc | 21 +++++ + components/flags_ui/resources/experiment.html | 7 +- + components/flags_ui/resources/experiment.ts | 16 ++++ + components/flags_ui/resources/flags.css | 19 +++++ + components/flags_ui/resources/flags.html | 13 +++ + components/flags_ui/resources/flags.ts | 36 ++++++-- + .../flags_ui/resources/flags_browser_proxy.ts | 5 ++ + content/common/features.cc | 1 + + content/public/common/content_features.cc | 1 + + content/public/common/content_features.h | 1 + + cromite_flags/BUILD.gn | 72 ++++++++++++++++ + .../browser/about_flags_cc/placeholder.txt | 1 + + .../chrome_feature_list_cc/placeholder.txt | 1 + + .../browser/ui/ui_features_cc/placeholder.txt | 1 + + .../common/chrome_features_cc/placeholder.txt | 1 + + .../common/chrome_features_h/placeholder.txt | 1 + + .../common/features_cc/placeholder.txt | 1 + + .../content_features_cc/placeholder.txt | 1 + + .../common/content_features_h/placeholder.txt | 1 + + .../blink/common/features_cc/placeholder.txt | 1 + + third_party/blink/common/features.cc | 1 + + 31 files changed, 370 insertions(+), 10 deletions(-) + create mode 100755 cromite_flags/BUILD.gn + create mode 100755 cromite_flags/chrome/browser/about_flags_cc/placeholder.txt + create mode 100755 cromite_flags/chrome/browser/flags/android/chrome_feature_list_cc/placeholder.txt + create mode 100755 cromite_flags/chrome/browser/ui/ui_features_cc/placeholder.txt + create mode 100755 cromite_flags/chrome/common/chrome_features_cc/placeholder.txt + create mode 100755 cromite_flags/chrome/common/chrome_features_h/placeholder.txt + create mode 100755 cromite_flags/content/common/features_cc/placeholder.txt + create mode 100755 cromite_flags/content/public/common/content_features_cc/placeholder.txt + create mode 100755 cromite_flags/content/public/common/content_features_h/placeholder.txt + create mode 100755 cromite_flags/third_party/blink/common/features_cc/placeholder.txt + +diff --git a/base/BUILD.gn b/base/BUILD.gn +--- a/base/BUILD.gn ++++ b/base/BUILD.gn +@@ -206,6 +206,8 @@ buildflag_header("message_pump_buildflags") { + # This does not include test code (test support and anything in the test + # directory) which should use source_set as is recommended for GN targets). + component("base") { ++ deps = [ "//cromite_flags", ] ++ + sources = [ + "allocator/allocator_check.cc", + "allocator/allocator_check.h", +@@ -1034,7 +1036,7 @@ component("base") { + "//build/config/compiler:wglobal_constructors", + ] + +- deps = [ ++ deps += [ + ":message_pump_buildflags", + "//base/allocator:buildflags", + "//base/allocator/partition_allocator:raw_ptr", +diff --git a/base/feature_list.cc b/base/feature_list.cc +--- a/base/feature_list.cc ++++ b/base/feature_list.cc +@@ -29,6 +29,33 @@ + #include "base/strings/stringprintf.h" + #include "build/build_config.h" + ++namespace base { ++namespace internal { ++ ++using DefaultStateOverrides = ++ flat_map; ++ ++constexpr size_t kDefaultStateOverridesReserve = 64 * 4; ++ ++DefaultStateOverrides& GetListOfNewFeatureState() { ++ static NoDestructor ++ startup_default_state_overrides([] { ++ DefaultStateOverrides v; ++ v.reserve(kDefaultStateOverridesReserve); ++ return v; ++ }()); ++ return *startup_default_state_overrides; ++} ++ ++FeatureDefaultStateOverrider::FeatureDefaultStateOverrider( ++ const Feature& feature, FeatureState state) { ++ auto& default_state_overrides = GetListOfNewFeatureState(); ++ default_state_overrides.insert({&feature, state}); ++} ++ ++} // namespace internal ++} // namespace base ++ + namespace base { + + namespace { +@@ -436,6 +463,24 @@ bool FeatureList::IsEnabled(const Feature& feature) { + return g_feature_list_instance->IsFeatureEnabled(feature); + } + ++bool FeatureList::IsCromiteChanged(const Feature& feature) { ++ for(auto const& [key, value]: internal::GetListOfNewFeatureState()) { ++ if (key->name == feature.name) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool FeatureList::GetCromiteChange(const Feature& feature) { ++ for(auto const& [key, value]: internal::GetListOfNewFeatureState()) { ++ if (key->name == feature.name) { ++ return value == base::FEATURE_ENABLED_BY_DEFAULT; ++ } ++ } ++ NOTREACHED(); ++ return false; ++} + // static + bool FeatureList::IsValidFeatureOrFieldTrialName(StringPiece name) { + return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos; +@@ -616,6 +661,17 @@ void FeatureList::SetCachingContextForTesting(uint16_t caching_context) { + + void FeatureList::FinalizeInitialization() { + DCHECK(!initialized_); ++ LOG(INFO) << "---FinalizeInitialization"; ++ for(auto const& [key, value]: internal::GetListOfNewFeatureState()) { ++ LOG(INFO) << "---key " << key->name ++ << " " ++ << (value == base::FEATURE_ENABLED_BY_DEFAULT ? "1" : "0"); ++ RegisterOverride(key->name, ++ value == base::FEATURE_ENABLED_BY_DEFAULT ++ ? OverrideState::OVERRIDE_ENABLE_FEATURE ++ : OverrideState::OVERRIDE_DISABLE_FEATURE, ++ /* field_trial = */ nullptr); ++ } + // Store the field trial list pointer for DCHECKing. + field_trial_list_ = FieldTrialList::GetInstance(); + initialized_ = true; +diff --git a/base/feature_list.h b/base/feature_list.h +--- a/base/feature_list.h ++++ b/base/feature_list.h +@@ -93,8 +93,10 @@ enum FeatureState { + // [1]: + // https://crsrc.org/c/docs/speed/binary_size/android_binary_size_trybot.md#Mutable-Constants + struct BASE_EXPORT LOGICALLY_CONST Feature { +- constexpr Feature(const char* name, FeatureState default_state) +- : name(name), default_state(default_state) { ++ constexpr Feature(const char* name, FeatureState default_state, ++ bool cromite = false, bool is_new_flag = false) ++ : name(name), default_state(default_state), ++ is_cromite(cromite), is_new(is_new_flag) { + #if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) + if (StringPiece(name).find(BUILDFLAG(BANNED_BASE_FEATURE_PREFIX)) == 0) { + LOG(FATAL) << "Invalid feature name " << name << " starts with " +@@ -120,6 +122,9 @@ struct BASE_EXPORT LOGICALLY_CONST Feature { + // command line switch. + const FeatureState default_state; + ++ const bool is_cromite = false; ++ const bool is_new = false; ++ + private: + friend class FeatureList; + +@@ -395,6 +400,9 @@ class BASE_EXPORT FeatureList { + // instance, which is checked in builds with DCHECKs enabled. + static bool IsEnabled(const Feature& feature); + ++ static bool IsCromiteChanged(const Feature& feature); ++ static bool GetCromiteChange(const Feature& feature); ++ + // Some characters are not allowed to appear in feature names or the + // associated field trial names, as they are used as special characters for + // command-line serialization. This function checks that the strings are ASCII +@@ -616,4 +624,76 @@ class BASE_EXPORT FeatureList { + + } // namespace base + ++namespace base { ++namespace internal { ++ ++// Perform base::Feature duplicates check and fills overriden states into a ++// map that is used at runtime to get an override if available. ++class BASE_EXPORT FeatureDefaultStateOverrider { ++ public: ++ using FeatureOverrideInfo = ++ std::pair, FeatureState>; ++ ++ FeatureDefaultStateOverrider( ++ const Feature& feature, FeatureState state); ++}; ++ ++} // namespace internal ++} // namespace base ++ ++#define CROMITE_FEATURE(feature, name, default_state) \ ++ CONSTINIT const base::Feature feature(name, default_state, true, true) ++ ++#define CROMITE_FEATURE_KEEP_DISABLED(feature, name, default_state) \ ++ CONSTINIT const base::Feature feature(name, base::FEATURE_DISABLED_BY_DEFAULT, true); \ ++ static_assert(default_state == base::FEATURE_DISABLED_BY_DEFAULT, \ ++ "Feature is not disabled by default.") ++ ++#define CROMITE_FEATURE_DISABLED(feature, name, default_state) \ ++ CONSTINIT const base::Feature feature(name, base::FEATURE_DISABLED_BY_DEFAULT, true); \ ++ static_assert(default_state == base::FEATURE_ENABLED_BY_DEFAULT, \ ++ "Feature is not enabled by default.") ++ ++#define CROMITE_FEATURE_KEEP_ENABLED(feature, name, default_state) \ ++ CONSTINIT const base::Feature feature(name, base::FEATURE_ENABLED_BY_DEFAULT, true); \ ++ static_assert(default_state == base::FEATURE_ENABLED_BY_DEFAULT, \ ++ "Feature is not enabled by default.") ++ ++#define CROMITE_FEATURE_ENABLED(feature, name, default_state) \ ++ CONSTINIT const base::Feature feature(name, base::FEATURE_ENABLED_BY_DEFAULT, true); \ ++ static_assert(default_state == base::FEATURE_DISABLED_BY_DEFAULT, \ ++ "Feature is not disabled by default.") ++ ++#define SET_CROMITE_FEATURE_ENABLED(feature) \ ++ _Pragma("clang diagnostic push") \ ++ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \ ++ static const ::base::internal::FeatureDefaultStateOverrider \ ++ g_feature_default_state_overrider_ ##feature {feature, base::FEATURE_ENABLED_BY_DEFAULT}; \ ++ _Pragma("clang diagnostic pop") \ ++ static_assert(true, "") /* for a semicolon requirement */ ++ ++#define SET_CROMITE_FEATURE_DISABLED(feature) \ ++ _Pragma("clang diagnostic push") \ ++ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \ ++ static const ::base::internal::FeatureDefaultStateOverrider \ ++ g_feature_default_state_overrider_ ##feature {feature, base::FEATURE_DISABLED_BY_DEFAULT}; \ ++ _Pragma("clang diagnostic pop") \ ++ static_assert(true, "") /* for a semicolon requirement */ ++ ++#define SET_CROMITE_FEATURE_ENABLED_W_NAMESPACE(namespace_value, feature) \ ++ _Pragma("clang diagnostic push") \ ++ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \ ++ static const ::base::internal::FeatureDefaultStateOverrider \ ++ g_feature_default_state_overrider_ ##feature {namespace_value::feature, base::FEATURE_ENABLED_BY_DEFAULT}; \ ++ _Pragma("clang diagnostic pop") \ ++ static_assert(true, "") /* for a semicolon requirement */ ++ ++#define SET_CROMITE_FEATURE_DISABLED_W_NAMESPACE(namespace_value, feature) \ ++ _Pragma("clang diagnostic push") \ ++ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \ ++ static const ::base::internal::FeatureDefaultStateOverrider \ ++ g_feature_default_state_overrider_ ##feature {namespace_value::feature, base::FEATURE_DISABLED_BY_DEFAULT}; \ ++ _Pragma("clang diagnostic pop") \ ++ static_assert(true, "") /* for a semicolon requirement */ ++ + #endif // BASE_FEATURE_LIST_H_ +diff --git a/build/android/gyp/java_cpp_features.py b/build/android/gyp/java_cpp_features.py +--- a/build/android/gyp/java_cpp_features.py ++++ b/build/android/gyp/java_cpp_features.py +@@ -22,10 +22,27 @@ class FeatureParserDelegate(java_cpp_utils.CppConstantParser.Delegate): + # ExtractConstantName() -> 'ConstantName' + # ExtractValue() -> '"StringNameOfTheFeature"' + FEATURE_RE = re.compile(r'BASE_FEATURE\(k([^,]+),') ++ ++ FEATURE_RE1 = re.compile(r'CROMITE_FEATURE\(k([^,]+),') ++ FEATURE_RE2 = re.compile(r'CROMITE_FEATURE_KEEP_DISABLED\(k([^,]+),') ++ FEATURE_RE3 = re.compile(r'CROMITE_FEATURE_DISABLED\(k([^,]+),') ++ FEATURE_RE4 = re.compile(r'CROMITE_FEATURE_KEEP_ENABLED\(k([^,]+),') ++ FEATURE_RE5 = re.compile(r'CROMITE_FEATURE_ENABLED\(k([^,]+),') ++ + VALUE_RE = re.compile(r'\s*("(?:\"|[^"])*")\s*,') + + def ExtractConstantName(self, line): + match = FeatureParserDelegate.FEATURE_RE.match(line) ++ if match is None: ++ match = FeatureParserDelegate.FEATURE_RE1.match(line) ++ if match is None: ++ match = FeatureParserDelegate.FEATURE_RE2.match(line) ++ if match is None: ++ match = FeatureParserDelegate.FEATURE_RE3.match(line) ++ if match is None: ++ match = FeatureParserDelegate.FEATURE_RE4.match(line) ++ if match is None: ++ match = FeatureParserDelegate.FEATURE_RE5.match(line) + return match.group(1) if match else None + + def ExtractValue(self, line): +diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml +--- a/chrome/android/java/res/values/values.xml ++++ b/chrome/android/java/res/values/values.xml +@@ -42,6 +42,9 @@ found in the LICENSE file. + + 0.95 + ++ Cromite Flags (wip) ++ chrome://flags/cromite ++ + + 0.5 + 0 +diff --git a/chrome/android/java/res/xml/privacy_preferences.xml b/chrome/android/java/res/xml/privacy_preferences.xml +--- a/chrome/android/java/res/xml/privacy_preferences.xml ++++ b/chrome/android/java/res/xml/privacy_preferences.xml +@@ -99,6 +99,10 @@ found in the LICENSE file. + android:title="@string/tabgrid_use_icons_title" + android:summary="@string/tabgrid_use_icons_summary" + android:defaultValue="false" /> ++ + default_state == base::FEATURE_ENABLED_BY_DEFAULT; ++ data.Set("default_value", is_enabled ++ ? "enabled" : "disabled"); ++ if (is_enabled) ++ data.Set("is_default_value_on", true); ++ } ++ if (entry.feature.feature->is_cromite) ++ data.Set("is_cromite", true); ++ if (entry.feature.feature->is_new) ++ data.Set("is_new", true); ++ } ++ + switch (entry.type) { + case FeatureEntry::SINGLE_VALUE: + case FeatureEntry::SINGLE_DISABLE_VALUE: +diff --git a/components/flags_ui/resources/experiment.html b/components/flags_ui/resources/experiment.html +--- a/components/flags_ui/resources/experiment.html ++++ b/components/flags_ui/resources/experiment.html +@@ -119,6 +119,11 @@ + color: white; + } + ++ .experiment-on select { ++ background: #dddddd; ++ color: var(--link-color); ++ } ++ + .experiment-switched option { + background: white; + color: var(--link-color); +@@ -164,7 +169,6 @@ + .experiment .experiment-actions { + max-width: 100%; + padding-top: 12px; +- text-align: left; /* csschecker-disable-line left-right */ + width: 100%; + } + +@@ -172,7 +176,6 @@ + .body { + overflow: hidden; + text-overflow: ellipsis; +- white-space: nowrap; + width: 100%; + } + +diff --git a/components/flags_ui/resources/experiment.ts b/components/flags_ui/resources/experiment.ts +--- a/components/flags_ui/resources/experiment.ts ++++ b/components/flags_ui/resources/experiment.ts +@@ -60,11 +60,16 @@ function resetHighlights(element: HTMLElement) { + + export class FlagsExperimentElement extends CustomElement { + private feature_: Feature|null = null; ++ private permalink_: boolean = true; + + static override get template() { + return getTemplate(); + } + ++ set permalink(visible: boolean) { ++ this.permalink_ = visible; ++ } ++ + set data(feature: Feature) { + this.feature_ = feature; + +@@ -76,12 +81,18 @@ export class FlagsExperimentElement extends CustomElement { + 'experiment-default', feature.is_default); + experimentDefault.classList.toggle( + 'experiment-switched', !feature.is_default); ++ experimentDefault.classList.toggle( ++ 'cromite', feature.is_cromite && feature.is_new); ++ experimentDefault.classList.toggle( ++ 'experiment-on', !!feature.is_default_value_on); + + const experimentName = this.getRequiredElement('.experiment-name'); + experimentName.id = `${feature.internal_name}_name`; + experimentName.title = + feature.is_default ? '' : loadTimeData.getString('experiment-enabled'); + experimentName.textContent = feature.name; ++ if (feature.is_cromite && feature.is_new) ++ experimentName.textContent += " (Cromite flag)" + + const description = this.getRequiredElement('.description'); + description.textContent = feature.description; +@@ -124,6 +135,7 @@ export class FlagsExperimentElement extends CustomElement { + const permalink = this.getRequiredElement('.permalink'); + permalink.href = `#${feature.internal_name}`; + permalink.textContent = `#${feature.internal_name}`; ++ if (!this.permalink_) permalink.hidden = true; + + const smallScreenCheck = window.matchMedia('(max-width: 480px)'); + // Toggling of experiment description overflow content on smaller screens. +@@ -152,6 +164,10 @@ export class FlagsExperimentElement extends CustomElement { + const optionEl = document.createElement('option'); + optionEl.selected = option.selected; + optionEl.textContent = option.description; ++ if (option.description == "Default" && ++ feature.default_value !== undefined) { ++ optionEl.textContent += " (" + feature.default_value + ")"; ++ } + experimentSelect.appendChild(optionEl); + } + +diff --git a/components/flags_ui/resources/flags.css b/components/flags_ui/resources/flags.css +--- a/components/flags_ui/resources/flags.css ++++ b/components/flags_ui/resources/flags.css +@@ -468,3 +468,22 @@ button.primary:-webkit-any(:active, :hover) { + padding-top: 1.5rem; + } + } ++ ++.cromite #header { ++ display: none; ++} ++.cromite .blurb-container { ++ display: none; ++} ++.cromite #tabs { ++ display: none; ++} ++.cromite #tab-content-available { ++ display: none; ++} ++.cromite #tab-content-unavailable { ++ display: none; ++} ++.cromite #tab-content-cromite { ++ display: block !important; ++} +diff --git a/components/flags_ui/resources/flags.html b/components/flags_ui/resources/flags.html +--- a/components/flags_ui/resources/flags.html ++++ b/components/flags_ui/resources/flags.html +@@ -92,6 +92,11 @@ + aria-selected="false" aria-controls="panel2" + tabindex="-1">$i18n{unavailable} + ++ Cromite + +
+
+
+ ++
++ ++
++ ++
++ ++
+
+
+
+diff --git a/components/flags_ui/resources/flags.ts b/components/flags_ui/resources/flags.ts +--- a/components/flags_ui/resources/flags.ts ++++ b/components/flags_ui/resources/flags.ts +@@ -39,6 +39,10 @@ interface Tab { + } + + const tabs: Tab[] = [ ++ { ++ tabEl: document.body.querySelector('#tab-cromite')!, ++ panelEl: document.body.querySelector('#tab-content-cromite')!, ++ }, + { + tabEl: document.body.querySelector('#tab-available')!, + panelEl: document.body.querySelector('#tab-content-available')!, +@@ -84,18 +88,27 @@ function render(experimentalFeaturesData: ExperimentalFeaturesData) { + const defaultFeatures: Feature[] = []; + const nonDefaultFeatures: Feature[] = []; + ++ if (document.body.classList.contains("cromite")) { ++ experimentalFeaturesData.supportedFeatures = ++ experimentalFeaturesData.supportedFeatures.filter(item => item.is_new); ++ } ++ experimentalFeaturesData.supportedFeatures.sort( ++ (a,b) => (a.internal_name.localeCompare(b.internal_name))); + experimentalFeaturesData.supportedFeatures.forEach( + f => (f.is_default ? defaultFeatures : nonDefaultFeatures).push(f)); + + renderExperiments( +- nonDefaultFeatures, getRequiredElement('non-default-experiments')); ++ nonDefaultFeatures, getRequiredElement('non-default-experiments'), ++ getRequiredElement('non-default-cromite-experiments'), false); + +- renderExperiments(defaultFeatures, getRequiredElement('default-experiments')); ++ renderExperiments(defaultFeatures, getRequiredElement('default-experiments'), ++ getRequiredElement('cromite-experiments'), false); + + // + renderExperiments( + experimentalFeaturesData.unsupportedFeatures, +- getRequiredElement('unavailable-experiments'), true); ++ getRequiredElement('unavailable-experiments'), ++ undefined, true); + // + + showRestartToast(experimentalFeaturesData.needsRestart); +@@ -248,16 +261,22 @@ function resetAllFlags() { + } + + function renderExperiments( +- features: Feature[], container: HTMLElement, unsupported = false) { ++ features: Feature[], container: HTMLElement, cromiteContainer: HTMLElement | undefined, unsupported: boolean) { + const fragment = document.createDocumentFragment(); ++ const fragmentCromite = document.createDocumentFragment(); ++ const show_permalink = !document.body.classList.contains('cromite'); + for (const feature of features) { + const experiment = document.createElement('flags-experiment'); + + experiment.toggleAttribute('unsupported', unsupported); ++ experiment.permalink = show_permalink; + experiment.data = feature; + experiment.id = feature.internal_name; + + const select = experiment.getSelect(); ++ // if (select && feature.is_cromite && !feature.is_new) { ++ // select.disabled = true; ++ // } + if (select) { + experiment.addEventListener('select-change', () => { + showRestartToast(true); +@@ -281,9 +300,14 @@ function renderExperiments( + return false; + }); + } +- fragment.appendChild(experiment); ++ if (feature.is_cromite) ++ fragmentCromite.appendChild(experiment); ++ else ++ fragment.appendChild(experiment); + } + container.replaceChildren(fragment); ++ if (!!cromiteContainer) ++ cromiteContainer.replaceChildren(fragmentCromite); + } + + /** +@@ -507,6 +531,8 @@ function setupRestartButton() { + // + + document.addEventListener('DOMContentLoaded', function() { ++ if (location.pathname == '/cromite') ++ document.body.classList.add('cromite'); + // Get and display the data upon loading. + requestExperimentalFeaturesData(); + // There is no restart button on iOS. +diff --git a/components/flags_ui/resources/flags_browser_proxy.ts b/components/flags_ui/resources/flags_browser_proxy.ts +--- a/components/flags_ui/resources/flags_browser_proxy.ts ++++ b/components/flags_ui/resources/flags_browser_proxy.ts +@@ -16,6 +16,11 @@ export interface Feature { + description: string; + enabled: boolean; + is_default: boolean; ++ is_default_value_on: boolean; ++ default_value: string; ++ is_cromite: boolean; ++ is_new: boolean; ++ permalink: boolean; + supported_platforms: string[]; + origin_list_value?: string; + string_value?: string; +diff --git a/content/common/features.cc b/content/common/features.cc +--- a/content/common/features.cc ++++ b/content/common/features.cc +@@ -529,4 +529,5 @@ BASE_FEATURE(kWindowOpenFileSelectFix, + + // Please keep features in alphabetical order. + ++#include "cromite_flags/content_common_features_cc.inc" + } // namespace features +diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc +--- a/content/public/common/content_features.cc ++++ b/content/public/common/content_features.cc +@@ -1331,4 +1331,5 @@ bool IsVideoCaptureServiceEnabledForBrowserProcess() { + VideoCaptureServiceConfiguration::kEnabledForBrowserProcess; + } + ++#include "cromite_flags/content_public_common_content_features_cc.inc" + } // namespace features +diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h +--- a/content/public/common/content_features.h ++++ b/content/public/common/content_features.h +@@ -330,6 +330,7 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebRtcPipeWireCapturer); + CONTENT_EXPORT bool IsVideoCaptureServiceEnabledForOutOfProcess(); + CONTENT_EXPORT bool IsVideoCaptureServiceEnabledForBrowserProcess(); + ++#include "cromite_flags/content_public_common_content_features_h.inc" + } // namespace features + + #endif // CONTENT_PUBLIC_COMMON_CONTENT_FEATURES_H_ +diff --git a/cromite_flags/BUILD.gn b/cromite_flags/BUILD.gn +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/BUILD.gn +@@ -0,0 +1,72 @@ ++# This file is part of Bromite. ++ ++# Bromite is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# Bromite is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with Bromite. If not, see . ++ ++# for placeholder.txt: ++# ++# this file is intentionally empty ++# ++ ++cpp_bromite_include("chrome_browser_about_flags_cc") { ++ inputs = [ "//cromite_flags/chrome/browser/about_flags_cc/placeholder.txt" ] ++ output_file = "chrome_browser_about_flags_cc.inc" ++} ++ ++cpp_bromite_include("chrome_common_chrome_features_cc") { ++ inputs = [ "//cromite_flags/chrome/common/chrome_features_cc/placeholder.txt" ] ++ output_file = "chrome_common_chrome_features_cc.inc" ++} ++ ++cpp_bromite_include("content_common_features_cc") { ++ inputs = [ "//cromite_flags/content/common/features_cc/placeholder.txt" ] ++ output_file = "content_common_features_cc.inc" ++} ++ ++cpp_bromite_include("content_public_common_content_features_h") { ++ inputs = [ "//cromite_flags/content/public/common/content_features_h/placeholder.txt" ] ++ output_file = "content_public_common_content_features_h.inc" ++} ++ ++cpp_bromite_include("content_public_common_content_features_cc") { ++ inputs = [ "//cromite_flags/content/public/common/content_features_cc/placeholder.txt" ] ++ output_file = "content_public_common_content_features_cc.inc" ++} ++ ++cpp_bromite_include("third_party_blink_common_features_cc") { ++ inputs = [ "//cromite_flags/third_party/blink/common/features_cc/placeholder.txt" ] ++ output_file = "third_party_blink_common_features_cc.inc" ++} ++ ++cpp_bromite_include("chrome_browser_flags_android_chrome_feature_list_cc") { ++ inputs = [ "//cromite_flags/chrome/browser/flags/android/chrome_feature_list_cc/placeholder.txt" ] ++ output_file = "chrome_browser_flags_android_chrome_feature_list_cc.inc" ++} ++ ++cpp_bromite_include("chrome_browser_ui_ui_features_cc") { ++ inputs = [ "//cromite_flags/chrome/browser/ui/ui_features_cc/placeholder.txt" ] ++ output_file = "chrome_browser_ui_ui_features_cc.inc" ++} ++ ++component("cromite_flags") { ++ deps = [ ++ ":content_common_features_cc", ++ ":content_public_common_content_features_cc", ++ ":content_public_common_content_features_h", ++ ":chrome_common_chrome_features_cc", ++ ":chrome_browser_about_flags_cc", ++ ":chrome_browser_flags_android_chrome_feature_list_cc", ++ ":chrome_browser_ui_ui_features_cc", ++ ":third_party_blink_common_features_cc", ++ ] ++} +diff --git a/cromite_flags/chrome/browser/about_flags_cc/placeholder.txt b/cromite_flags/chrome/browser/about_flags_cc/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/chrome/browser/about_flags_cc/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/cromite_flags/chrome/browser/flags/android/chrome_feature_list_cc/placeholder.txt b/cromite_flags/chrome/browser/flags/android/chrome_feature_list_cc/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/chrome/browser/flags/android/chrome_feature_list_cc/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/cromite_flags/chrome/browser/ui/ui_features_cc/placeholder.txt b/cromite_flags/chrome/browser/ui/ui_features_cc/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/chrome/browser/ui/ui_features_cc/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/cromite_flags/chrome/common/chrome_features_cc/placeholder.txt b/cromite_flags/chrome/common/chrome_features_cc/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/chrome/common/chrome_features_cc/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/cromite_flags/chrome/common/chrome_features_h/placeholder.txt b/cromite_flags/chrome/common/chrome_features_h/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/chrome/common/chrome_features_h/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/cromite_flags/content/common/features_cc/placeholder.txt b/cromite_flags/content/common/features_cc/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/content/common/features_cc/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/cromite_flags/content/public/common/content_features_cc/placeholder.txt b/cromite_flags/content/public/common/content_features_cc/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/content/public/common/content_features_cc/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/cromite_flags/content/public/common/content_features_h/placeholder.txt b/cromite_flags/content/public/common/content_features_h/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/content/public/common/content_features_h/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/cromite_flags/third_party/blink/common/features_cc/placeholder.txt b/cromite_flags/third_party/blink/common/features_cc/placeholder.txt +new file mode 100755 +--- /dev/null ++++ b/cromite_flags/third_party/blink/common/features_cc/placeholder.txt +@@ -0,0 +1 @@ ++this file is intentionally empty +diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc +--- a/third_party/blink/common/features.cc ++++ b/third_party/blink/common/features.cc +@@ -2192,5 +2192,6 @@ bool IsKeepAliveURLLoaderServiceEnabled() { + base::FeatureList::IsEnabled(kFetchLaterAPI); + } + ++#include "cromite_flags/third_party_blink_common_features_cc.inc" + } // namespace features + } // namespace blink +-- +2.25.1