123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- # Copyright 2024 Google LLC
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- import copy
- from waflib import Node
- from resources.find_resource_filename import find_most_specific_filename
- from resources.types.resource_definition import ResourceDefinition
- from resources.types.resource_object import ResourceObject
- from resources.resource_map import resource_generator
- import resources.resource_map.resource_generator_bitmap
- import resources.resource_map.resource_generator_font
- import resources.resource_map.resource_generator_js
- import resources.resource_map.resource_generator_pbi
- import resources.resource_map.resource_generator_png
- import resources.resource_map.resource_generator_raw
- from sdk_helpers import is_sdk_2x, validate_resource_not_larger_than
- def _preprocess_resource_ids(bld, resources_list, has_published_media=False):
- """
- This method reads all of the defined resources for the project and assigns resource IDs to
- them prior to the start of resource processing. This preprocessing step is necessary in order
- for the timeline lookup table to contain accurate resource IDs, while still allowing us the
- prepend the TLUT as a resource in the resource ball.
- :param bld: the BuildContext object
- :param resources_list: the list of resources defined for this project
- :param has_published_media: boolean for whether publishedMedia exists for the project
- :return: None
- """
- resource_id_mapping = {}
- next_id = 1
- if has_published_media:
- # The timeline lookup table must be the first resource if one exists
- resource_id_mapping['TIMELINE_LUT'] = next_id
- next_id += 1
- for res_id, res in enumerate(resources_list, start=next_id):
- if isinstance(res, Node.Node):
- if res.name == 'timeline_resource_table.reso':
- continue
- res_name = ResourceObject.load(res.abspath()).definition.name
- resource_id_mapping[res_name] = res_id
- else:
- resource_id_mapping[res.name] = res_id
- bld.env.RESOURCE_ID_MAPPING = resource_id_mapping
- def generate_resources(bld, resource_source_path):
- """
- This method creates all of the task generators necessary to handle every possible resource
- allowed by the SDK.
- :param bld: the BuildContext object
- :param resource_source_path: the path from which to retrieve resource files
- :return: N/A
- """
- resources_json = getattr(bld.env, 'RESOURCES_JSON', [])
- published_media_json = getattr(bld.env, 'PUBLISHED_MEDIA_JSON', [])
- if resource_source_path:
- resources_node = bld.path.find_node(resource_source_path)
- else:
- resources_node = bld.path.find_node('resources')
- resource_file_mapping = {}
- for resource in resources_json:
- resource_file_mapping[resource['name']] = (
- find_most_specific_filename(bld, bld.env, resources_node, resource['file']))
- # Load the waftools that handle creating resource objects, a resource pack and the resource
- # ID header
- bld.load('generate_pbpack generate_resource_ball generate_resource_id_header')
- bld.load('process_timeline_resources')
- # Iterate over the resource definitions and do some processing to remove resources that
- # aren't relevant to the platform we're building for and to apply various backwards
- # compatibility adjustments
- resource_definitions = []
- max_menu_icon_dimensions = (25, 25)
- for r in resources_json:
- if 'menuIcon' in r and r['menuIcon']:
- res_file = (
- resources_node.find_node(find_most_specific_filename(bld, bld.env,
- resources_node,
- str(r['file'])))).abspath()
- if not validate_resource_not_larger_than(bld, res_file,
- dimensions=max_menu_icon_dimensions):
- bld.fatal("menuIcon resource '{}' exceeds the maximum allowed dimensions of {}".
- format(r['name'], max_menu_icon_dimensions))
- defs = resource_generator.definitions_from_dict(bld, r, resource_source_path)
- for d in defs:
- if not d.is_in_target_platform(bld):
- continue
- if d.type == 'png-trans':
- # SDK hack for SDK compatibility
- # One entry in the media list with the type png-trans actually represents two
- # resources, one for the black mask and one for the white mask. They each have
- # their own resource ids, so we need two entries in our definitions list.
- for suffix in ('WHITE', 'BLACK'):
- new_definition = copy.deepcopy(d)
- new_definition.name = '%s_%s' % (d.name, suffix)
- resource_definitions.append(new_definition)
- continue
- if d.type == 'png' and is_sdk_2x(bld.env.SDK_VERSION_MAJOR, bld.env.SDK_VERSION_MINOR):
- # We don't have png support in the 2.x sdk, instead process these into a pbi
- d.type = 'pbi'
- resource_definitions.append(d)
- bld_dir = bld.path.get_bld().make_node(bld.env.BUILD_DIR)
- lib_resources = []
- for lib in bld.env.LIB_JSON:
- # Skip resource handling if not a Pebble library or if no resources are specified
- if 'pebble' not in lib or 'resources' not in lib['pebble']:
- continue
- if 'media' not in lib['pebble']['resources'] or not lib['pebble']['resources']['media']:
- continue
- lib_path = bld.path.find_node(lib['path'])
- try:
- resources_path = lib_path.find_node('resources').find_node(bld.env.PLATFORM_NAME)
- except AttributeError:
- bld.fatal("Library {} is missing resources".format(lib['name']))
- else:
- if resources_path is None:
- bld.fatal("Library {} is missing resources for the {} platform".
- format(lib['name'], bld.env.PLATFORM_NAME))
- for lib_resource in bld.env.LIB_RESOURCES_JSON.get(lib['name'], []):
- # Skip resources that specify targetPlatforms other than this one
- if 'targetPlatforms' in lib_resource:
- if bld.env.PLATFORM_NAME not in lib_resource['targetPlatforms']:
- continue
- reso_file = '{}.{}.reso'.format(lib_resource['file'], lib_resource['name'])
- resource_node = resources_path.find_node(reso_file)
- if resource_node is None:
- bld.fatal("Library {} is missing the {} resource for the {} platform".
- format(lib['name'], lib_resource['name'], bld.env.PLATFORM_NAME))
- if lib_resource['name'] in resource_file_mapping:
- bld.fatal("Duplicate resource IDs are not permitted. Package resource {} uses the "
- "same resource ID as another resource already in this project.".
- format(lib_resource['name']))
- resource_file_mapping[lib_resource['name']] = resource_node
- lib_resources.append(resource_node)
- resources_list = []
- if resource_definitions:
- resources_list.extend(resource_definitions)
- if lib_resources:
- resources_list.extend(lib_resources)
- build_type = getattr(bld.env, 'BUILD_TYPE', 'app')
- resource_ball = bld_dir.make_node('system_resources.resball')
- # If this is a library, generate a resource ball containing only resources provided in this
- # project (not additional dependencies)
- project_resource_ball = None
- if build_type == 'lib':
- project_resource_ball = bld_dir.make_node('project_resources.resball')
- bld.env.PROJECT_RESBALL = project_resource_ball
- if published_media_json:
- # Only create TLUT for non-packages
- if build_type != 'lib':
- timeline_resource_table = bld_dir.make_node('timeline_resource_table.reso')
- resources_list.append(timeline_resource_table)
- _preprocess_resource_ids(bld, resources_list, True)
- bld(features='process_timeline_resources',
- published_media=published_media_json,
- timeline_reso=timeline_resource_table,
- layouts_json=bld_dir.make_node('layouts.json'),
- resource_mapping=resource_file_mapping,
- vars=['RESOURCE_ID_MAPPING', 'PUBLISHED_MEDIA_JSON'])
- # Create resource objects from a set of resource definitions and package them in a resource ball
- bld(features='generate_resource_ball',
- resources=resources_list,
- resource_ball=resource_ball,
- project_resource_ball=project_resource_ball,
- vars=['RESOURCES_JSON', 'LIB_RESOURCES_JSON', 'RESOURCE_ID_MAPPING'])
- # Create a resource ID header for use during the linking step of the build
- # FIXME PBL-36458: Since pebble.h requires this file through a #include, this file must be
- # present for every project, regardless of whether or not resources exist for the project. At
- # this time, this means the `generate_resource_id_header` task generator must run for every
- # project. Since the input of the `generate_resource_id_header` task generator is the
- # resource ball created by the `generate_resource_ball` task generator, the
- # `generate_resource_ball` task generator must also run for every project.
- resource_id_header = bld_dir.make_node('src/resource_ids.auto.h')
- bld.env.RESOURCE_ID_HEADER = resource_id_header.abspath()
- bld(features='generate_resource_id_header',
- resource_ball=resource_ball,
- resource_id_header_target=resource_id_header,
- use_extern=build_type == 'lib',
- use_define=build_type == 'app',
- published_media=published_media_json)
- resource_id_definitions = bld_dir.make_node('src/resource_ids.auto.c')
- bld.env.RESOURCE_ID_DEFINITIONS = resource_id_definitions.abspath()
- bld(features='generate_resource_id_definitions',
- resource_ball=resource_ball,
- resource_id_definitions_target=resource_id_definitions,
- published_media=published_media_json)
- if not bld.env.BUILD_TYPE or bld.env.BUILD_TYPE in ('app', 'rocky'):
- # Create a resource pack for distribution with an application binary
- pbpack = bld_dir.make_node('app_resources.pbpack')
- bld(features='generate_pbpack',
- resource_ball=resource_ball,
- pbpack_target=pbpack,
- is_system=False)
|