From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- third_party/aom/CHANGELOG | 19 + third_party/aom/CMakeLists.txt | 22 +- third_party/aom/README.md | 26 +- third_party/aom/aom/aom_encoder.h | 5 + third_party/aom/aom/aomdx.h | 7 +- third_party/aom/aom/src/aom_encoder.c | 5 + third_party/aom/aom/src/aom_image.c | 2 + third_party/aom/aom_dsp/aom_dsp.cmake | 15 +- third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl | 118 +- .../aom/aom_dsp/arm/aom_convolve8_neon_dotprod.c | 116 +- .../aom/aom_dsp/arm/aom_convolve8_neon_i8mm.c | 73 +- third_party/aom/aom_dsp/arm/aom_filter.h | 33 + third_party/aom/aom_dsp/arm/aom_neon_sve2_bridge.h | 36 + third_party/aom/aom_dsp/arm/aom_neon_sve_bridge.h | 56 + third_party/aom/aom_dsp/arm/avg_sve.c | 2 +- third_party/aom/aom_dsp/arm/blk_sse_sum_sve.c | 2 +- third_party/aom/aom_dsp/arm/dot_sve.h | 42 - third_party/aom/aom_dsp/arm/highbd_convolve8_sve.c | 681 + third_party/aom/aom_dsp/arm/highbd_sse_sve.c | 2 +- third_party/aom/aom_dsp/arm/highbd_variance_sve.c | 2 +- third_party/aom/aom_dsp/arm/mem_neon.h | 56 +- third_party/aom/aom_dsp/arm/sum_squares_sve.c | 2 +- .../aom/aom_dsp/flow_estimation/corner_detect.c | 44 +- .../aom/aom_dsp/flow_estimation/corner_detect.h | 5 +- .../aom/aom_dsp/flow_estimation/corner_match.c | 317 +- .../aom/aom_dsp/flow_estimation/corner_match.h | 12 +- third_party/aom/aom_dsp/flow_estimation/disflow.c | 36 +- third_party/aom/aom_dsp/flow_estimation/disflow.h | 11 +- .../aom/aom_dsp/flow_estimation/flow_estimation.c | 20 +- .../aom/aom_dsp/flow_estimation/flow_estimation.h | 7 +- third_party/aom/aom_dsp/flow_estimation/ransac.c | 349 +- .../flow_estimation/x86/corner_match_avx2.c | 148 +- .../flow_estimation/x86/corner_match_sse4.c | 171 +- .../aom/aom_dsp/flow_estimation/x86/disflow_avx2.c | 417 + .../aom/aom_dsp/flow_estimation/x86/disflow_sse4.c | 424 +- third_party/aom/aom_dsp/mathutils.h | 1 - third_party/aom/aom_dsp/noise_model.c | 6 +- third_party/aom/aom_dsp/noise_model.h | 6 +- third_party/aom/aom_dsp/pyramid.c | 181 +- third_party/aom/aom_dsp/pyramid.h | 61 +- third_party/aom/aom_dsp/rect.h | 35 - third_party/aom/aom_dsp/variance.c | 125 +- third_party/aom/aom_dsp/x86/aom_asm_stubs.c | 34 - .../aom/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c | 569 - .../aom/aom_dsp/x86/aom_subpixel_8t_sse2.asm | 615 - .../aom/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm | 295 - third_party/aom/aom_dsp/x86/avg_intrin_sse2.c | 2 +- third_party/aom/aom_dsp/x86/fwd_txfm_impl_sse2.h | 6 + third_party/aom/aom_dsp/x86/highbd_variance_avx2.c | 63 +- third_party/aom/aom_dsp/x86/highbd_variance_sse2.c | 12 +- third_party/aom/aom_dsp/x86/intrapred_ssse3.c | 8 +- third_party/aom/aom_dsp/x86/masked_sad4d_ssse3.c | 50 +- .../aom/aom_dsp/x86/subpel_variance_sse2.asm | 1470 - .../aom/aom_dsp/x86/subpel_variance_ssse3.asm | 1442 + third_party/aom/aom_dsp/x86/synonyms.h | 19 + third_party/aom/aom_dsp/x86/synonyms_avx2.h | 25 + third_party/aom/aom_dsp/x86/variance_avx2.c | 26 +- third_party/aom/aom_dsp/x86/variance_impl_avx2.c | 6 +- third_party/aom/aom_dsp/x86/variance_sse2.c | 16 +- third_party/aom/aom_ports/aarch64_cpudetect.c | 16 + third_party/aom/aom_ports/arm.h | 2 + third_party/aom/aom_ports/mem.h | 8 +- third_party/aom/aom_scale/aom_scale_rtcd.pl | 12 +- third_party/aom/aom_scale/generic/yv12config.c | 34 +- third_party/aom/aom_scale/generic/yv12extend.c | 42 +- third_party/aom/aom_scale/yv12config.h | 31 +- third_party/aom/aom_util/aom_pthread.h | 172 + third_party/aom/aom_util/aom_thread.c | 56 +- third_party/aom/aom_util/aom_thread.h | 146 +- third_party/aom/aom_util/aom_util.cmake | 3 +- third_party/aom/apps/aomenc.c | 4 +- third_party/aom/av1/av1.cmake | 22 +- third_party/aom/av1/av1_cx_iface.c | 49 +- third_party/aom/av1/av1_dx_iface.c | 17 +- third_party/aom/av1/common/alloccommon.c | 6 +- .../av1/common/arm/highbd_compound_convolve_neon.c | 532 +- .../av1/common/arm/highbd_compound_convolve_neon.h | 293 + .../av1/common/arm/highbd_compound_convolve_sve2.c | 1555 + .../aom/av1/common/arm/highbd_convolve_sve2.c | 1720 + .../aom/av1/common/arm/highbd_convolve_sve2.h | 97 + .../aom/av1/common/arm/highbd_warp_plane_neon.c | 30 +- .../aom/av1/common/arm/highbd_warp_plane_neon.h | 60 +- .../aom/av1/common/arm/highbd_warp_plane_sve.c | 32 +- third_party/aom/av1/common/arm/warp_plane_neon.c | 38 +- third_party/aom/av1/common/arm/warp_plane_neon.h | 60 +- .../aom/av1/common/arm/warp_plane_neon_i8mm.c | 38 +- third_party/aom/av1/common/arm/warp_plane_sve.c | 40 +- third_party/aom/av1/common/av1_common_int.h | 2 +- third_party/aom/av1/common/av1_rtcd_defs.pl | 54 +- third_party/aom/av1/common/cdef.c | 13 +- third_party/aom/av1/common/entropymode.h | 9 +- third_party/aom/av1/common/quant_common.c | 18 +- third_party/aom/av1/common/reconintra.c | 6 +- third_party/aom/av1/common/resize.c | 52 +- third_party/aom/av1/common/resize.h | 44 +- third_party/aom/av1/common/restoration.c | 35 +- third_party/aom/av1/common/thread_common.c | 7 + third_party/aom/av1/common/thread_common.h | 1 + third_party/aom/av1/common/tile_common.c | 61 +- third_party/aom/av1/common/tile_common.h | 15 +- third_party/aom/av1/common/x86/cdef_block_sse2.c | 40 - third_party/aom/av1/common/x86/cdef_block_ssse3.c | 11 + third_party/aom/av1/common/x86/convolve_2d_avx2.c | 18 +- third_party/aom/av1/common/x86/convolve_2d_sse2.c | 17 +- third_party/aom/av1/common/x86/convolve_sse2.c | 26 +- third_party/aom/av1/common/x86/jnt_convolve_sse2.c | 229 - third_party/aom/av1/decoder/decodeframe.c | 49 +- third_party/aom/av1/decoder/decodemv.h | 2 + third_party/aom/av1/decoder/decoder.c | 1 + third_party/aom/av1/decoder/dthread.h | 1 - third_party/aom/av1/decoder/obu.c | 41 +- third_party/aom/av1/encoder/allintra_vis.c | 4 +- third_party/aom/av1/encoder/aq_cyclicrefresh.c | 50 +- .../aom/av1/encoder/arm/neon/av1_error_sve.c | 2 +- .../arm/neon/temporal_filter_neon_dotprod.c | 58 +- .../aom/av1/encoder/arm/neon/wedge_utils_sve.c | 92 + .../aom/av1/encoder/av1_temporal_denoiser.c | 8 +- third_party/aom/av1/encoder/bitstream.c | 19 +- third_party/aom/av1/encoder/bitstream.h | 1 + third_party/aom/av1/encoder/block.h | 3 + third_party/aom/av1/encoder/cnn.c | 10 +- third_party/aom/av1/encoder/encode_strategy.c | 27 +- third_party/aom/av1/encoder/encodeframe.c | 20 +- third_party/aom/av1/encoder/encodeframe_utils.c | 6 + third_party/aom/av1/encoder/encoder.c | 94 +- third_party/aom/av1/encoder/encoder.h | 9 +- third_party/aom/av1/encoder/encoder_alloc.h | 3 +- third_party/aom/av1/encoder/encoder_utils.c | 20 +- third_party/aom/av1/encoder/encodetxb.c | 26 +- third_party/aom/av1/encoder/ethread.c | 8 +- third_party/aom/av1/encoder/firstpass.c | 1 + third_party/aom/av1/encoder/global_motion.c | 82 +- third_party/aom/av1/encoder/global_motion.h | 32 +- third_party/aom/av1/encoder/global_motion_facade.c | 47 +- third_party/aom/av1/encoder/k_means_template.h | 10 +- third_party/aom/av1/encoder/lookahead.c | 19 +- third_party/aom/av1/encoder/lookahead.h | 20 +- third_party/aom/av1/encoder/nonrd_pickmode.c | 7 +- third_party/aom/av1/encoder/palette.c | 2 +- third_party/aom/av1/encoder/palette.h | 2 +- third_party/aom/av1/encoder/partition_search.c | 48 +- third_party/aom/av1/encoder/partition_strategy.c | 2 +- third_party/aom/av1/encoder/pass2_strategy.c | 100 +- third_party/aom/av1/encoder/pickcdef.c | 2 +- third_party/aom/av1/encoder/picklpf.c | 21 +- third_party/aom/av1/encoder/pickrst.c | 111 +- third_party/aom/av1/encoder/ratectrl.c | 120 +- third_party/aom/av1/encoder/ratectrl.h | 3 + third_party/aom/av1/encoder/speed_features.c | 9 +- third_party/aom/av1/encoder/speed_features.h | 7 + third_party/aom/av1/encoder/superres_scale.c | 2 +- third_party/aom/av1/encoder/svc_layercontext.c | 12 +- third_party/aom/av1/encoder/svc_layercontext.h | 15 + third_party/aom/av1/encoder/temporal_filter.c | 21 +- third_party/aom/av1/encoder/temporal_filter.h | 2 + third_party/aom/av1/encoder/tpl_model.c | 3 +- third_party/aom/av1/encoder/tpl_model.h | 1 + third_party/aom/av1/encoder/tune_butteraugli.c | 10 +- third_party/aom/av1/encoder/tune_vmaf.c | 105 +- third_party/aom/av1/encoder/tune_vmaf.h | 6 +- third_party/aom/av1/encoder/tx_search.c | 23 +- .../aom/av1/encoder/x86/av1_fwd_txfm_sse2.c | 6 + third_party/aom/av1/encoder/x86/cnn_avx2.c | 2 +- .../aom/build/cmake/aom_config_defaults.cmake | 6 + third_party/aom/build/cmake/aom_configure.cmake | 11 + third_party/aom/build/cmake/compiler_flags.cmake | 4 +- third_party/aom/build/cmake/cpu.cmake | 21 +- third_party/aom/build/cmake/rtcd.pl | 2 +- third_party/aom/doc/dev_guide/av1_encoder.dox | 28 + third_party/aom/examples/av1_dec_fuzzer.cc | 15 + third_party/aom/examples/svc_encoder_rtc.cc | 34 + third_party/aom/libs.doxy_template | 57 - third_party/aom/test/active_map_test.cc | 18 +- third_party/aom/test/aom_image_test.cc | 12 +- third_party/aom/test/av1_convolve_test.cc | 38 +- third_party/aom/test/av1_fwd_txfm2d_test.cc | 15 +- third_party/aom/test/av1_wedge_utils_test.cc | 12 + third_party/aom/test/cdef_test.cc | 72 +- third_party/aom/test/convolve_test.cc | 35 +- third_party/aom/test/corner_match_test.cc | 221 +- third_party/aom/test/disflow_test.cc | 5 + third_party/aom/test/encode_api_test.cc | 79 + third_party/aom/test/hbd_metrics_test.cc | 8 +- third_party/aom/test/level_test.cc | 14 +- third_party/aom/test/quantize_func_test.cc | 9 +- third_party/aom/test/resize_test.cc | 40 +- third_party/aom/test/sad_test.cc | 2 + third_party/aom/test/segment_binarization_sync.cc | 11 +- third_party/aom/test/sharpness_test.cc | 2 +- third_party/aom/test/test.cmake | 48 +- third_party/aom/test/test_libaom.cc | 1 + third_party/aom/test/variance_test.cc | 78 +- third_party/aom/test/wiener_test.cc | 382 + third_party/aom/third_party/libwebm/README.libaom | 2 +- .../aom/third_party/libwebm/mkvmuxer/mkvmuxer.cc | 102 +- .../aom/third_party/libwebm/mkvmuxer/mkvmuxer.h | 2 +- .../third_party/libwebm/mkvmuxer/mkvmuxerutil.cc | 10 +- .../aom/third_party/libwebm/mkvparser/mkvparser.cc | 11 +- third_party/content_analysis_sdk/.gitignore | 6 - .../content_analysis_sdk/agent/src/event_win.cc | 1 - .../content_analysis_sdk/agent_improvements.patch | 480 + .../content_analysis_sdk/browser/src/client_mac.cc | 4 +- .../browser/src/client_posix.cc | 2 +- third_party/content_analysis_sdk/demo/agent.cc | 7 +- third_party/content_analysis_sdk/demo/client.cc | 2 +- third_party/content_analysis_sdk/demo/handler.h | 208 +- .../demo/handler_misbehaving.h | 257 +- third_party/content_analysis_sdk/moz.yaml | 33 + third_party/content_analysis_sdk/prepare_build | 96 +- .../proto/content_analysis/sdk/analysis.proto | 24 +- third_party/dav1d/NEWS | 18 +- third_party/dav1d/THANKS.md | 33 +- third_party/dav1d/gcovr.cfg | 2 +- third_party/dav1d/meson.build | 77 +- third_party/dav1d/src/arm/32/itx.S | 79 +- third_party/dav1d/src/arm/32/itx16.S | 19 +- third_party/dav1d/src/arm/32/msac.S | 167 +- third_party/dav1d/src/arm/64/itx.S | 99 +- third_party/dav1d/src/arm/64/itx16.S | 21 +- third_party/dav1d/src/arm/64/mc.S | 411 +- third_party/dav1d/src/arm/64/mc16.S | 373 +- third_party/dav1d/src/arm/64/msac.S | 167 +- third_party/dav1d/src/arm/64/util.S | 49 + third_party/dav1d/src/arm/asm.S | 44 + third_party/dav1d/src/arm/cpu.c | 137 +- third_party/dav1d/src/arm/cpu.h | 4 + third_party/dav1d/src/arm/itx.h | 4 +- third_party/dav1d/src/arm/msac.h | 2 +- third_party/dav1d/src/cpu.h | 14 + third_party/dav1d/src/ext/x86/x86inc.asm | 198 +- third_party/dav1d/src/itx_1d.c | 5 + third_party/dav1d/src/itx_tmpl.c | 10 + third_party/dav1d/src/loongarch/msac.S | 216 +- third_party/dav1d/src/msac.c | 58 +- third_party/dav1d/src/ppc/cdef_tmpl.c | 399 +- third_party/dav1d/src/riscv/64/itx.S | 1061 +- third_party/dav1d/src/riscv/asm.S | 2 + third_party/dav1d/src/riscv/itx.h | 12 + third_party/dav1d/src/x86/cdef_avx2.asm | 7 +- third_party/dav1d/src/x86/filmgrain16_avx2.asm | 23 +- third_party/dav1d/src/x86/filmgrain16_sse.asm | 8 +- third_party/dav1d/src/x86/filmgrain_avx2.asm | 19 +- third_party/dav1d/src/x86/filmgrain_sse.asm | 14 +- third_party/dav1d/src/x86/ipred16_avx2.asm | 18 - third_party/dav1d/src/x86/ipred_avx2.asm | 106 +- third_party/dav1d/src/x86/ipred_sse.asm | 10 +- third_party/dav1d/src/x86/looprestoration_sse.asm | 8 +- third_party/dav1d/src/x86/mc16_avx2.asm | 6 - third_party/dav1d/src/x86/mc16_avx512.asm | 3 - third_party/dav1d/src/x86/mc16_sse.asm | 33 +- third_party/dav1d/src/x86/mc_avx2.asm | 33 +- third_party/dav1d/src/x86/mc_avx512.asm | 3 - third_party/dav1d/src/x86/mc_sse.asm | 16 +- third_party/dav1d/src/x86/msac.asm | 172 +- third_party/jpeg-xl/CHANGELOG.md | 14 + third_party/jpeg-xl/WORKSPACE | 2 +- third_party/jpeg-xl/debian/changelog | 16 +- .../jpeg-xl/examples/decode_exif_metadata.cc | 2 +- third_party/jpeg-xl/examples/decode_oneshot.cc | 2 +- third_party/jpeg-xl/examples/decode_progressive.cc | 8 +- third_party/jpeg-xl/examples/encode_oneshot.cc | 4 +- third_party/jpeg-xl/lib/BUILD | 5 +- third_party/jpeg-xl/lib/CMakeLists.txt | 2 +- third_party/jpeg-xl/lib/extras/codec_test.cc | 7 +- third_party/jpeg-xl/lib/extras/dec/apng.cc | 34 +- third_party/jpeg-xl/lib/extras/dec/pnm.cc | 4 +- third_party/jpeg-xl/lib/extras/enc/apng.cc | 77 +- third_party/jpeg-xl/lib/extras/enc/jpegli.cc | 2 +- third_party/jpeg-xl/lib/extras/enc/jpg.cc | 2 +- third_party/jpeg-xl/lib/extras/enc/pnm.cc | 8 +- third_party/jpeg-xl/lib/extras/mmap.h | 8 +- third_party/jpeg-xl/lib/jpegli/color_transform.cc | 6 + third_party/jpeg-xl/lib/jpegli/decode.h | 2 +- third_party/jpeg-xl/lib/jpegli/decode_api_test.cc | 13 +- .../jpeg-xl/lib/jpegli/destination_manager.cc | 4 +- third_party/jpeg-xl/lib/jpegli/encode.h | 2 +- third_party/jpeg-xl/lib/jpegli/encode_api_test.cc | 12 +- .../jpeg-xl/lib/jpegli/error_handling_test.cc | 78 +- .../jpeg-xl/lib/jpegli/input_suspension_test.cc | 3 +- third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc | 4 +- third_party/jpeg-xl/lib/jpegli/source_manager.cc | 7 +- .../jpeg-xl/lib/jpegli/source_manager_test.cc | 2 +- third_party/jpeg-xl/lib/jpegli/streaming_test.cc | 3 +- third_party/jpeg-xl/lib/jpegli/test_utils.cc | 2 +- .../jpeg-xl/lib/jpegli/transcode_api_test.cc | 2 +- third_party/jpeg-xl/lib/jxl.cmake | 10 +- third_party/jpeg-xl/lib/jxl/alpha_test.cc | 34 +- third_party/jpeg-xl/lib/jxl/bit_reader_test.cc | 4 +- .../jpeg-xl/lib/jxl/butteraugli/butteraugli.h | 5 +- third_party/jpeg-xl/lib/jxl/cache_aligned.cc | 7 +- third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h | 13 +- third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h | 6 +- .../jpeg-xl/lib/jxl/cms/transfer_functions-inl.h | 2 +- .../jpeg-xl/lib/jxl/color_management_test.cc | 2 +- third_party/jpeg-xl/lib/jxl/convolve_test.cc | 8 +- third_party/jpeg-xl/lib/jxl/dct_for_test.h | 6 +- third_party/jpeg-xl/lib/jxl/dct_test.cc | 2 +- third_party/jpeg-xl/lib/jxl/dec_cache.cc | 12 +- third_party/jpeg-xl/lib/jxl/dec_modular.cc | 2 +- third_party/jpeg-xl/lib/jxl/decode_test.cc | 16 +- .../jpeg-xl/lib/jxl/enc_ar_control_field.cc | 4 +- third_party/jpeg-xl/lib/jxl/enc_fast_lossless.cc | 36 +- third_party/jpeg-xl/lib/jxl/enc_frame.cc | 14 +- third_party/jpeg-xl/lib/jxl/enc_group.cc | 6 +- third_party/jpeg-xl/lib/jxl/enc_icc_codec.cc | 20 +- third_party/jpeg-xl/lib/jxl/enc_modular.cc | 248 +- third_party/jpeg-xl/lib/jxl/enc_modular.h | 1 - third_party/jpeg-xl/lib/jxl/enc_params.h | 3 + .../jpeg-xl/lib/jxl/enc_patch_dictionary.cc | 18 +- third_party/jpeg-xl/lib/jxl/enc_quant_weights.cc | 6 +- third_party/jpeg-xl/lib/jxl/enc_splines.cc | 4 +- third_party/jpeg-xl/lib/jxl/enc_toc.cc | 6 +- third_party/jpeg-xl/lib/jxl/encode.cc | 29 +- third_party/jpeg-xl/lib/jxl/encode_test.cc | 20 +- third_party/jpeg-xl/lib/jxl/entropy_coder_test.cc | 2 +- third_party/jpeg-xl/lib/jxl/gradient_test.cc | 4 +- third_party/jpeg-xl/lib/jxl/icc_codec.h | 2 +- third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data.cc | 7 +- .../jpeg-xl/lib/jxl/jpeg/dec_jpeg_data_writer.cc | 4 +- third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data.cc | 19 +- .../jpeg-xl/lib/jxl/jpeg/enc_jpeg_data_reader.cc | 37 +- third_party/jpeg-xl/lib/jxl/jpeg/jpeg_data.cc | 18 +- third_party/jpeg-xl/lib/jxl/jxl_test.cc | 143 +- third_party/jpeg-xl/lib/jxl/lehmer_code_test.cc | 4 +- .../lib/jxl/modular/encoding/context_predict.h | 4 +- .../jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc | 8 +- .../jpeg-xl/lib/jxl/modular/encoding/encoding.cc | 12 +- .../lib/jxl/modular/transform/enc_palette.cc | 80 +- .../lib/jxl/modular/transform/enc_squeeze.cc | 12 +- .../jpeg-xl/lib/jxl/modular/transform/palette.h | 2 + .../jpeg-xl/lib/jxl/modular/transform/squeeze.cc | 22 +- .../jpeg-xl/lib/jxl/modular/transform/squeeze.h | 4 +- .../jpeg-xl/lib/jxl/modular/transform/transform.cc | 2 +- .../jpeg-xl/lib/jxl/modular/transform/transform.h | 2 +- third_party/jpeg-xl/lib/jxl/modular_test.cc | 15 +- third_party/jpeg-xl/lib/jxl/passes_test.cc | 47 +- third_party/jpeg-xl/lib/jxl/quant_weights_test.cc | 2 +- .../lib/jxl/render_pipeline/render_pipeline.cc | 2 +- .../jxl/render_pipeline/simple_render_pipeline.cc | 10 +- .../jpeg-xl/lib/jxl/render_pipeline/stage_cms.cc | 2 +- .../jpeg-xl/lib/jxl/render_pipeline/stage_epf.cc | 26 +- .../lib/jxl/render_pipeline/stage_upsampling.cc | 2 +- .../jpeg-xl/lib/jxl/render_pipeline/stage_write.cc | 11 +- .../jpeg-xl/lib/jxl/render_pipeline/stage_write.h | 3 +- third_party/jpeg-xl/lib/jxl/roundtrip_test.cc | 2 +- third_party/jpeg-xl/lib/jxl/speed_tier_test.cc | 1 - third_party/jpeg-xl/lib/jxl/splines.cc | 12 +- third_party/jpeg-xl/lib/jxl/test_image.cc | 3 +- third_party/jpeg-xl/lib/jxl/test_utils.h | 3 +- third_party/jpeg-xl/lib/jxl/testing.h | 24 +- third_party/jpeg-xl/lib/jxl/tf_gbench.cc | 4 +- third_party/jpeg-xl/lib/jxl/version.h.in | 2 +- .../jpeg-xl/lib/jxl/xorshift128plus_test.cc | 4 +- third_party/jpeg-xl/lib/jxl_cms.cmake | 2 +- third_party/jpeg-xl/lib/jxl_extras.cmake | 2 +- third_party/jpeg-xl/lib/jxl_lists.bzl | 2 +- .../lib/threads/thread_parallel_runner_test.cc | 6 +- third_party/jpeg-xl/plugins/gimp/file-jxl-load.cc | 8 +- third_party/jpeg-xl/plugins/gimp/file-jxl-save.cc | 12 +- third_party/libwebrtc/.vpython3 | 38 +- third_party/libwebrtc/BUILD.gn | 1 + third_party/libwebrtc/DEPS | 92 +- third_party/libwebrtc/README.moz-ff-commit | 846 + third_party/libwebrtc/README.mozilla | 564 + third_party/libwebrtc/api/BUILD.gn | 22 +- third_party/libwebrtc/api/DEPS | 7 - third_party/libwebrtc/api/audio_codecs/BUILD.gn | 1 + .../libwebrtc/api/audio_codecs/audio_format.cc | 4 +- .../libwebrtc/api/audio_codecs/audio_format.h | 10 +- .../libwebrtc/api/call/call_factory_interface.h | 43 - .../libwebrtc/api/callfactory_api_gn/moz.build | 213 - third_party/libwebrtc/api/candidate.cc | 18 + third_party/libwebrtc/api/candidate.h | 54 +- .../libwebrtc/api/create_peerconnection_factory.cc | 3 +- third_party/libwebrtc/api/enable_media.cc | 5 +- .../api/environment/environment_factory.cc | 10 + .../environment/environment_factory_gn/moz.build | 231 + third_party/libwebrtc/api/fec_controller.h | 5 +- third_party/libwebrtc/api/metronome/BUILD.gn | 2 +- third_party/libwebrtc/api/metronome/metronome.h | 2 +- third_party/libwebrtc/api/metronome/test/BUILD.gn | 9 +- .../libwebrtc/api/metronome/test/fake_metronome.cc | 10 +- .../libwebrtc/api/metronome/test/fake_metronome.h | 17 +- .../libwebrtc/api/peer_connection_interface.h | 8 +- .../api/rtc_event_log/rtc_event_log_factory.cc | 7 +- .../api/rtc_event_log/rtc_event_log_factory.h | 5 +- third_party/libwebrtc/api/rtp_parameters.cc | 9 + third_party/libwebrtc/api/rtp_parameters.h | 4 + third_party/libwebrtc/api/stats/attribute.h | 96 + third_party/libwebrtc/api/stats/rtc_stats.h | 329 +- third_party/libwebrtc/api/stats/rtc_stats_member.h | 185 + third_party/libwebrtc/api/stats/rtcstats_objects.h | 36 - third_party/libwebrtc/api/task_queue/BUILD.gn | 7 +- .../default_task_queue_factory_gn/moz.build | 198 + .../api/test/create_network_emulation_manager.cc | 6 +- .../api/test/create_network_emulation_manager.h | 4 +- .../libwebrtc/api/test/create_time_controller.cc | 13 +- third_party/libwebrtc/api/test/pclf/BUILD.gn | 1 - .../libwebrtc/api/test/pclf/media_configuration.h | 1 - .../api/test/pclf/media_quality_test_params.h | 1 + .../libwebrtc/api/test/pclf/peer_configurer.cc | 5 + .../libwebrtc/api/test/pclf/peer_configurer.h | 2 + .../api/test/peerconnection_quality_test_fixture.h | 1 - .../api/test/video_quality_test_fixture.h | 2 +- .../api/transport/rtp/dependency_descriptor.h | 21 + third_party/libwebrtc/api/transport/stun.cc | 20 +- third_party/libwebrtc/api/video_codecs/BUILD.gn | 1 + .../libwebrtc/api/video_codecs/av1_profile.cc | 6 +- .../libwebrtc/api/video_codecs/av1_profile.h | 6 +- .../api/video_codecs/h264_profile_level_id.cc | 6 +- .../api/video_codecs/h264_profile_level_id.h | 6 +- .../api/video_codecs/h265_profile_tier_level.cc | 496 +- .../api/video_codecs/h265_profile_tier_level.h | 218 +- .../libwebrtc/api/video_codecs/sdp_video_format.cc | 11 +- .../libwebrtc/api/video_codecs/sdp_video_format.h | 10 +- .../test/h264_profile_level_id_unittest.cc | 6 +- .../test/h265_profile_tier_level_unittest.cc | 496 +- .../video_codecs/test/sdp_video_format_unittest.cc | 2 +- ...o_encoder_factory_template_libaom_av1_adapter.h | 3 +- ...o_encoder_factory_template_libvpx_vp8_adapter.h | 3 +- .../libwebrtc/api/video_codecs/vp9_profile.cc | 6 +- .../libwebrtc/api/video_codecs/vp9_profile.h | 6 +- third_party/libwebrtc/audio/BUILD.gn | 14 +- .../libwebrtc/audio/audio_receive_stream.cc | 2 + third_party/libwebrtc/audio/audio_send_stream.cc | 3 +- third_party/libwebrtc/audio/audio_send_stream.h | 1 - .../channel_receive_frame_transformer_delegate.h | 2 +- third_party/libwebrtc/audio/channel_send.cc | 52 +- .../channel_send_frame_transformer_delegate.cc | 2 +- .../channel_send_frame_transformer_delegate.h | 6 +- ...nel_send_frame_transformer_delegate_unittest.cc | 10 +- .../libwebrtc/audio/channel_send_unittest.cc | 22 +- third_party/libwebrtc/audio/voip/BUILD.gn | 1 - third_party/libwebrtc/audio/voip/audio_egress.cc | 18 +- third_party/libwebrtc/audio/voip/audio_egress.h | 10 +- third_party/libwebrtc/call/BUILD.gn | 14 +- third_party/libwebrtc/call/call.cc | 150 +- third_party/libwebrtc/call/call.h | 6 - third_party/libwebrtc/call/call_config.cc | 26 +- third_party/libwebrtc/call/call_config.h | 30 +- third_party/libwebrtc/call/call_factory.cc | 119 - third_party/libwebrtc/call/call_factory.h | 37 - third_party/libwebrtc/call/create_call.cc | 98 + third_party/libwebrtc/call/create_call.h | 25 + third_party/libwebrtc/call/rtp_transport_config.h | 20 +- .../call/rtp_transport_controller_send.cc | 81 +- .../libwebrtc/call/rtp_transport_controller_send.h | 10 +- .../call/rtp_transport_controller_send_factory.h | 6 +- ...p_transport_controller_send_factory_interface.h | 7 +- .../libwebrtc/call/rtp_video_sender_unittest.cc | 26 +- third_party/libwebrtc/call/version.cc | 2 +- .../libwebrtc/common_video/h264/h264_common.h | 7 +- .../libwebrtc/common_video/h264/sps_parser.h | 5 +- .../common_video/h265/h265_bitstream_parser.cc | 3 + .../docs/native-code/development/README.md | 14 +- .../docs/native-code/development/fuzzers/README.md | 70 + .../androidnativeapi/jni/android_call_client.cc | 3 +- .../libwebrtc/examples/androidvoip/BUILD.gn | 2 +- .../androidvoip/jni/android_voip_client.cc | 34 +- .../examples/androidvoip/jni/android_voip_client.h | 16 +- .../objcnativeapi/objc/objc_call_client.mm | 3 +- third_party/libwebrtc/experiments/field_trials.py | 9 +- third_party/libwebrtc/infra/OWNERS | 1 - third_party/libwebrtc/infra/config/config.star | 2 + .../libwebrtc/infra/config/cr-buildbucket.cfg | 94 + third_party/libwebrtc/infra/config/luci-milo.cfg | 6 + third_party/libwebrtc/infra/config/luci-notify.cfg | 26 + .../libwebrtc/infra/specs/client.webrtc.json | 1537 +- .../infra/specs/internal.client.webrtc.json | 122 +- third_party/libwebrtc/infra/specs/mixins.pyl | 61 +- .../libwebrtc/infra/specs/mixins_webrtc.pyl | 42 - third_party/libwebrtc/infra/specs/test_suites.pyl | 32 +- .../libwebrtc/infra/specs/tryserver.webrtc.json | 2766 +- third_party/libwebrtc/infra/specs/variants.pyl | 26 +- third_party/libwebrtc/infra/specs/waterfalls.pyl | 72 +- third_party/libwebrtc/logging/BUILD.gn | 10 +- .../logging/rtc_event_log/rtc_event_log_impl.cc | 44 +- .../logging/rtc_event_log/rtc_event_log_impl.h | 13 +- third_party/libwebrtc/media/BUILD.gn | 1 - third_party/libwebrtc/media/base/codec.cc | 45 +- third_party/libwebrtc/media/base/codec.h | 11 +- third_party/libwebrtc/media/base/codec_unittest.cc | 61 + .../libwebrtc/media/base/media_channel_impl.cc | 20 - .../libwebrtc/media/base/media_channel_impl.h | 14 - .../libwebrtc/media/base/sdp_video_format_utils.cc | 73 +- .../libwebrtc/media/base/sdp_video_format_utils.h | 24 +- .../media/base/sdp_video_format_utils_unittest.cc | 57 +- .../engine/internal_decoder_factory_unittest.cc | 10 + .../engine/internal_encoder_factory_unittest.cc | 13 + .../engine/simulcast_encoder_adapter_unittest.cc | 2 +- .../libwebrtc/media/engine/webrtc_media_engine.cc | 37 - .../libwebrtc/media/engine/webrtc_media_engine.h | 42 - .../libwebrtc/media/engine/webrtc_video_engine.cc | 14 +- .../media/engine/webrtc_video_engine_unittest.cc | 8 +- .../libwebrtc/media/engine/webrtc_voice_engine.cc | 14 +- .../libwebrtc/media/engine/webrtc_voice_engine.h | 4 +- .../media/engine/webrtc_voice_engine_unittest.cc | 36 +- .../builtin_audio_decoder_factory_unittest.cc | 2 +- .../codecs/opus/audio_encoder_opus_unittest.cc | 2 +- .../neteq/test/neteq_opus_quality_test.cc | 4 +- .../modules/audio_coding/test/TestStereo.cc | 2 +- .../libwebrtc/modules/audio_device/BUILD.gn | 3 +- .../modules/audio_device/fine_audio_buffer.cc | 7 +- .../modules/audio_device/fine_audio_buffer.h | 11 +- .../audio_device/fine_audio_buffer_unittest.cc | 2 +- .../audio_device/include/test_audio_device.cc | 2 +- .../audio_device/mock_audio_device_buffer.h | 5 +- .../modules/audio_device/test_audio_device_impl.cc | 8 +- .../modules/audio_device/test_audio_device_impl.h | 4 +- .../libwebrtc/modules/audio_processing/BUILD.gn | 10 +- .../modules/audio_processing/aec_dump/BUILD.gn | 18 +- .../audio_processing/aec_dump/aec_dump_factory.h | 36 +- .../audio_processing/aec_dump/aec_dump_impl.cc | 26 +- .../audio_processing/aec_dump/aec_dump_impl.h | 6 +- .../audio_processing/aec_dump/aec_dump_unittest.cc | 4 +- .../aec_dump/null_aec_dump_factory.cc | 23 +- .../audio_processing/audio_processing_impl.cc | 16 +- .../audio_processing/audio_processing_impl.h | 16 +- .../audio_processing/audio_processing_unittest.cc | 10 +- .../audio_processing/include/audio_processing.h | 20 +- .../include/mock_audio_processing.h | 6 +- .../test/audio_processing_simulator.cc | 2 +- .../audio_processing/test/debug_dump_test.cc | 2 +- .../goog_cc/delay_based_bwe_unittest_helper.cc | 14 +- .../goog_cc/delay_based_bwe_unittest_helper.h | 9 +- .../goog_cc/send_side_bandwidth_estimation.cc | 3 +- .../modules/congestion_controller/rtp/BUILD.gn | 1 - .../congestion_controller/rtp/control_handler.cc | 18 +- .../congestion_controller/rtp/control_handler.h | 6 +- third_party/libwebrtc/modules/pacing/BUILD.gn | 1 + .../libwebrtc/modules/pacing/pacing_controller.cc | 22 +- .../libwebrtc/modules/pacing/pacing_controller.h | 44 +- .../modules/pacing/pacing_controller_unittest.cc | 38 + .../modules/pacing/prioritized_packet_queue.cc | 149 +- .../modules/pacing/prioritized_packet_queue.h | 26 +- .../pacing/prioritized_packet_queue_unittest.cc | 171 +- .../remote_estimator_proxy.cc | 7 +- .../rtp_rtcp/source/receive_statistics_impl.cc | 8 +- .../rtp_rtcp/source/receive_statistics_unittest.cc | 17 + .../modules/rtp_rtcp/source/rtcp_receiver.cc | 4 +- .../source/rtp_dependency_descriptor_extension.cc | 13 + .../source/rtp_dependency_descriptor_extension.h | 10 + .../modules/rtp_rtcp/source/rtp_format_h264.cc | 27 +- .../rtp_rtcp/source/rtp_format_h264_unittest.cc | 186 + .../modules/rtp_rtcp/source/rtp_format_vp8.cc | 4 +- .../rtp_rtcp/source/rtp_format_vp8_unittest.cc | 12 + .../modules/rtp_rtcp/source/rtp_format_vp9.cc | 5 +- .../rtp_rtcp/source/rtp_format_vp9_unittest.cc | 5 + .../libwebrtc/modules/rtp_rtcp/source/rtp_packet.h | 8 +- .../modules/rtp_rtcp/source/rtp_packet_to_send.cc | 11 + .../modules/rtp_rtcp/source/rtp_packet_to_send.h | 10 +- .../modules/rtp_rtcp/source/rtp_packet_unittest.cc | 35 + .../rtp_rtcp/source/rtp_packetizer_av1_unittest.cc | 6 + .../libwebrtc/modules/video_capture/BUILD.gn | 1 + .../video_capture/test/video_capture_unittest.cc | 21 +- .../libwebrtc/modules/video_coding/BUILD.gn | 3 +- .../video_coding/codecs/av1/dav1d_decoder.cc | 2 + .../video_coding/codecs/av1/libaom_av1_unittest.cc | 3 +- .../video_coding/codecs/h264/h264_decoder_impl.cc | 6 +- .../video_coding/codecs/test/video_codec_test.cc | 34 +- .../codecs/test/videocodec_test_fixture_impl.cc | 2 +- .../modules/video_coding/fec_controller_default.cc | 30 +- .../modules/video_coding/fec_controller_default.h | 11 +- .../video_coding/fec_controller_unittest.cc | 4 +- .../modules/video_coding/nack_requester.cc | 56 +- .../modules/video_coding/nack_requester.h | 10 +- .../video_coding/nack_requester_unittest.cc | 160 +- .../modules/video_coding/utility/qp_parser.cc | 16 +- .../modules/video_coding/utility/qp_parser.h | 18 + third_party/libwebrtc/moz-patch-stack/0001.patch | 10 +- third_party/libwebrtc/moz-patch-stack/0006.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0007.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0008.patch | 6 +- third_party/libwebrtc/moz-patch-stack/0009.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0030.patch | 114 +- third_party/libwebrtc/moz-patch-stack/0031.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0033.patch | 12 +- third_party/libwebrtc/moz-patch-stack/0034.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0042.patch | 6 +- third_party/libwebrtc/moz-patch-stack/0044.patch | 12 +- third_party/libwebrtc/moz-patch-stack/0046.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0047.patch | 139 +- third_party/libwebrtc/moz-patch-stack/0049.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0050.patch | 14 +- third_party/libwebrtc/moz-patch-stack/0052.patch | 48 +- third_party/libwebrtc/moz-patch-stack/0053.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0054.patch | 43 +- third_party/libwebrtc/moz-patch-stack/0064.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0068.patch | 12 +- third_party/libwebrtc/moz-patch-stack/0069.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0070.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0071.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0076.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0078.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0079.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0081.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0083.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0084.patch | 4 +- third_party/libwebrtc/moz-patch-stack/0085.patch | 2 +- third_party/libwebrtc/moz-patch-stack/0097.patch | 37056 ++++++++++++++++++- third_party/libwebrtc/moz-patch-stack/0098.patch | 35372 +----------------- third_party/libwebrtc/moz-patch-stack/0099.patch | 78 +- third_party/libwebrtc/moz-patch-stack/0100.patch | 88 +- third_party/libwebrtc/moz-patch-stack/0101.patch | 145 +- third_party/libwebrtc/moz-patch-stack/0102.patch | 212 +- third_party/libwebrtc/moz-patch-stack/0103.patch | 134 +- third_party/libwebrtc/moz-patch-stack/0104.patch | 95 +- third_party/libwebrtc/moz-patch-stack/0105.patch | 145 +- third_party/libwebrtc/moz-patch-stack/0106.patch | 187 +- third_party/libwebrtc/moz-patch-stack/0107.patch | 28 + third_party/libwebrtc/moz-patch-stack/0108.patch | 27 + third_party/libwebrtc/moz-patch-stack/0109.patch | 243 + third_party/libwebrtc/moz-patch-stack/0110.patch | 207 + .../058bfe3ae3.no-op-cherry-pick-msg | 1 - .../16ac10d9f7.no-op-cherry-pick-msg | 1 - .../334e9133dc.no-op-cherry-pick-msg | 1 - .../6a992129fb.no-op-cherry-pick-msg | 1 - .../de3c726121.no-op-cherry-pick-msg | 1 + third_party/libwebrtc/moz.build | 3 +- .../libwebrtc/net/dcsctp/public/dcsctp_socket.h | 11 + .../net/dcsctp/public/mock_dcsctp_socket.h | 8 + .../dcsctp/rx/traditional_reassembly_streams.cc | 57 +- .../net/dcsctp/rx/traditional_reassembly_streams.h | 6 + third_party/libwebrtc/net/dcsctp/socket/BUILD.gn | 2 +- .../net/dcsctp/socket/callback_deferrer.cc | 119 +- .../net/dcsctp/socket/callback_deferrer.h | 17 +- .../libwebrtc/net/dcsctp/socket/dcsctp_socket.cc | 130 +- .../libwebrtc/net/dcsctp/socket/dcsctp_socket.h | 10 +- .../net/dcsctp/socket/dcsctp_socket_test.cc | 172 + .../libwebrtc/net/dcsctp/socket/state_cookie.cc | 52 +- .../libwebrtc/net/dcsctp/socket/state_cookie.h | 28 +- .../net/dcsctp/socket/state_cookie_test.cc | 14 +- .../libwebrtc/net/dcsctp/tx/rr_send_queue.cc | 5 +- .../libwebrtc/p2p/base/basic_ice_controller.cc | 6 +- .../libwebrtc/p2p/base/basic_ice_controller.h | 3 + third_party/libwebrtc/p2p/base/connection.cc | 9 +- .../libwebrtc/p2p/base/ice_controller_interface.h | 15 +- .../libwebrtc/p2p/base/mock_ice_controller.h | 4 + .../libwebrtc/p2p/base/p2p_transport_channel.cc | 50 +- .../libwebrtc/p2p/base/p2p_transport_channel.h | 4 - .../p2p/base/p2p_transport_channel_unittest.cc | 119 +- third_party/libwebrtc/p2p/base/port.cc | 7 - third_party/libwebrtc/p2p/base/port.h | 5 - third_party/libwebrtc/p2p/base/port_allocator.cc | 9 +- third_party/libwebrtc/p2p/base/port_unittest.cc | 91 +- third_party/libwebrtc/p2p/base/pseudo_tcp.cc | 5 +- third_party/libwebrtc/p2p/base/stun_dictionary.cc | 3 +- third_party/libwebrtc/p2p/base/stun_port.cc | 4 +- .../libwebrtc/p2p/base/stun_port_unittest.cc | 8 +- .../libwebrtc/p2p/base/stun_server_unittest.cc | 3 +- third_party/libwebrtc/p2p/base/turn_port.cc | 26 +- third_party/libwebrtc/p2p/base/turn_port.h | 9 +- .../libwebrtc/p2p/base/turn_port_unittest.cc | 3 +- third_party/libwebrtc/p2p/base/turn_server.cc | 3 +- .../libwebrtc/p2p/client/basic_port_allocator.cc | 35 +- .../libwebrtc/p2p/client/basic_port_allocator.h | 3 - .../p2p/client/basic_port_allocator_unittest.cc | 28 +- .../libwebrtc/p2p/stunprober/stun_prober.cc | 4 +- third_party/libwebrtc/pc/BUILD.gn | 155 +- third_party/libwebrtc/pc/connection_context.cc | 7 +- third_party/libwebrtc/pc/connection_context.h | 8 - third_party/libwebrtc/pc/dtls_transport.cc | 34 +- third_party/libwebrtc/pc/dtls_transport.h | 18 +- .../libwebrtc/pc/jsep_session_description.cc | 36 +- third_party/libwebrtc/pc/legacy_stats_collector.cc | 63 +- third_party/libwebrtc/pc/legacy_stats_collector.h | 3 +- .../pc/legacy_stats_collector_unittest.cc | 4 +- third_party/libwebrtc/pc/media_session.cc | 52 +- third_party/libwebrtc/pc/media_session_unittest.cc | 74 + third_party/libwebrtc/pc/peer_connection.cc | 40 +- third_party/libwebrtc/pc/peer_connection.h | 3 - .../pc/peer_connection_crypto_unittest.cc | 11 +- .../peer_connection_encodings_integrationtest.cc | 29 +- .../pc/peer_connection_end_to_end_unittest.cc | 6 +- .../libwebrtc/pc/peer_connection_factory.cc | 10 +- third_party/libwebrtc/pc/peer_connection_factory.h | 5 +- .../pc/peer_connection_field_trial_tests.cc | 2 +- .../peer_connection_header_extension_unittest.cc | 3 +- .../pc/peer_connection_histogram_unittest.cc | 1 - .../pc/peer_connection_integrationtest.cc | 24 +- .../pc/peer_connection_interface_unittest.cc | 7 +- .../libwebrtc/pc/peer_connection_media_unittest.cc | 13 +- .../libwebrtc/pc/peer_connection_rampup_tests.cc | 8 +- .../libwebrtc/pc/peer_connection_rtp_unittest.cc | 37 +- .../pc/peer_connection_signaling_unittest.cc | 42 +- .../pc/peer_connection_simulcast_unittest.cc | 48 - third_party/libwebrtc/pc/rtc_stats_collector.cc | 44 +- third_party/libwebrtc/pc/rtc_stats_collector.h | 5 - .../libwebrtc/pc/rtc_stats_collector_unittest.cc | 36 +- .../libwebrtc/pc/rtc_stats_integrationtest.cc | 866 +- third_party/libwebrtc/pc/rtc_stats_traversal.cc | 2 +- third_party/libwebrtc/pc/rtp_transceiver.cc | 14 +- third_party/libwebrtc/pc/sctp_utils_unittest.cc | 8 +- third_party/libwebrtc/pc/sdp_offer_answer.cc | 27 +- .../libwebrtc/pc/sdp_offer_answer_unittest.cc | 119 + third_party/libwebrtc/pc/session_description.h | 26 +- .../libwebrtc/pc/test/integration_test_helpers.cc | 1 - .../libwebrtc/pc/test/integration_test_helpers.h | 11 +- third_party/libwebrtc/pc/test/svc_e2e_tests.cc | 9 +- third_party/libwebrtc/pc/webrtc_sdp.cc | 114 +- third_party/libwebrtc/pc/webrtc_sdp.h | 2 +- third_party/libwebrtc/pc/webrtc_sdp_unittest.cc | 131 +- third_party/libwebrtc/rtc_base/BUILD.gn | 16 +- .../libwebrtc/rtc_base/async_packet_socket.cc | 13 - .../libwebrtc/rtc_base/async_packet_socket.h | 12 - .../rtc_base/async_packet_socket_unittest.cc | 43 - third_party/libwebrtc/rtc_base/async_udp_socket.cc | 40 +- third_party/libwebrtc/rtc_base/async_udp_socket.h | 7 +- third_party/libwebrtc/rtc_base/bitstream_reader.h | 5 +- third_party/libwebrtc/rtc_base/byte_buffer.cc | 22 +- third_party/libwebrtc/rtc_base/byte_buffer.h | 56 +- .../libwebrtc/rtc_base/byte_buffer_unittest.cc | 41 +- .../libwebrtc/rtc_base/experiments/BUILD.gn | 3 +- .../rtc_base/experiments/alr_experiment.cc | 21 +- .../rtc_base/experiments/alr_experiment.h | 10 +- third_party/libwebrtc/rtc_base/gunit.cc | 43 - third_party/libwebrtc/rtc_base/gunit.h | 12 - third_party/libwebrtc/rtc_base/nat_server.cc | 76 +- third_party/libwebrtc/rtc_base/nat_server.h | 18 +- .../libwebrtc/rtc_base/nat_socket_factory.cc | 11 +- .../libwebrtc/rtc_base/nat_socket_factory.h | 1 + third_party/libwebrtc/rtc_base/nat_unittest.cc | 23 +- third_party/libwebrtc/rtc_base/network/BUILD.gn | 1 + .../libwebrtc/rtc_base/network/received_packet.cc | 6 +- .../libwebrtc/rtc_base/network/received_packet.h | 9 + .../libwebrtc/rtc_base/server_socket_adapters.cc | 4 +- third_party/libwebrtc/rtc_base/socket.cc | 22 +- third_party/libwebrtc/rtc_base/socket.h | 18 +- third_party/libwebrtc/rtc_base/socket_adapters.cc | 2 +- .../libwebrtc/rtc_base/task_queue_for_test.cc | 22 +- .../libwebrtc/rtc_base/task_queue_for_test.h | 41 +- .../libwebrtc/rtc_base/task_queue_unittest.cc | 30 +- third_party/libwebrtc/rtc_base/thread_unittest.cc | 17 +- .../libwebrtc/rtc_base/virtual_socket_unittest.cc | 22 +- third_party/libwebrtc/rtc_tools/BUILD.gn | 1 + .../libwebrtc/rtc_tools/network_tester/BUILD.gn | 3 +- .../rtc_tools/network_tester/test_controller.cc | 25 +- .../rtc_tools/network_tester/test_controller.h | 11 +- third_party/libwebrtc/rtc_tools/video_replay.cc | 8 +- .../api/peerconnection/RTCPeerConnectionFactory.mm | 3 +- .../objc/api/peerconnection/RTCStatisticsReport.mm | 187 +- .../sdk/objc/native/src/audio/audio_device_ios.h | 4 + .../sdk/objc/native/src/audio/audio_device_ios.mm | 12 +- third_party/libwebrtc/stats/BUILD.gn | 3 + third_party/libwebrtc/stats/attribute.cc | 172 + third_party/libwebrtc/stats/g3doc/stats.md | 27 +- third_party/libwebrtc/stats/rtc_stats.cc | 271 +- third_party/libwebrtc/stats/rtc_stats_member.cc | 62 + .../libwebrtc/stats/rtc_stats_report_unittest.cc | 22 +- third_party/libwebrtc/stats/rtc_stats_unittest.cc | 76 +- third_party/libwebrtc/stats/rtcstats_objects.cc | 733 +- third_party/libwebrtc/stats/test/rtc_test_stats.cc | 70 +- third_party/libwebrtc/stats/test/rtc_test_stats.h | 2 - third_party/libwebrtc/test/BUILD.gn | 11 +- third_party/libwebrtc/test/OWNERS | 1 - third_party/libwebrtc/test/call_test.cc | 2 +- third_party/libwebrtc/test/fake_decoder.cc | 2 +- .../libwebrtc/test/frame_generator_capturer.cc | 10 +- .../libwebrtc/test/frame_generator_capturer.h | 6 +- third_party/libwebrtc/test/fuzzers/BUILD.gn | 38 +- .../fuzzers/audio_processing_configs_fuzzer.cc | 17 +- .../receive-side-cc/testcase-5414098152390656 | Bin 0 -> 87 bytes .../test/fuzzers/rtp_format_h264_fuzzer.cc | 75 + .../test/fuzzers/rtp_format_vp8_fuzzer.cc | 73 + .../test/fuzzers/rtp_format_vp9_fuzzer.cc | 73 + third_party/libwebrtc/test/network/BUILD.gn | 4 +- .../test/network/cross_traffic_unittest.cc | 2 +- .../libwebrtc/test/network/network_emulation.cc | 17 +- .../libwebrtc/test/network/network_emulation.h | 16 +- .../test/network/network_emulation_manager.cc | 19 +- .../test/network/network_emulation_manager.h | 4 +- .../test/network/network_emulation_pc_unittest.cc | 3 +- third_party/libwebrtc/test/pc/e2e/BUILD.gn | 3 +- .../audio/default_audio_quality_analyzer.cc | 24 +- .../video/video_quality_metrics_reporter.cc | 16 +- .../test/pc/e2e/cross_media_metrics_reporter.cc | 12 +- .../pc/e2e/network_quality_metrics_reporter.cc | 9 +- .../test/pc/e2e/peer_connection_quality_test.cc | 2 +- ...stats_based_network_quality_metrics_reporter.cc | 18 +- .../libwebrtc/test/pc/e2e/test_peer_factory.cc | 9 +- .../libwebrtc/test/pc/e2e/test_peer_factory.h | 6 +- .../test/peer_scenario/peer_scenario_client.cc | 3 +- third_party/libwebrtc/test/run_loop_unittest.cc | 2 +- .../libwebrtc/test/scenario/audio_stream.cc | 2 +- .../libwebrtc/test/scenario/video_stream.cc | 3 +- .../libwebrtc/test/time_controller/BUILD.gn | 3 +- .../external_time_controller_unittest.cc | 42 +- .../test/time_controller/real_time_controller.cc | 5 +- .../test/time_controller/real_time_controller.h | 3 +- .../time_controller/simulated_time_controller.cc | 3 - .../time_controller/simulated_time_controller.h | 1 - .../simulated_time_controller_unittest.cc | 38 +- third_party/libwebrtc/test/video_codec_tester.cc | 338 +- .../libwebrtc/test/video_codec_tester_unittest.cc | 513 +- third_party/libwebrtc/tools_webrtc/OWNERS | 1 - .../tools_webrtc/libs/generate_licenses.py | 2 +- .../libwebrtc/tools_webrtc/mb/mb_config.pyl | 14 + third_party/libwebrtc/video/BUILD.gn | 20 +- third_party/libwebrtc/video/config/simulcast.cc | 6 +- .../libwebrtc/video/frame_cadence_adapter.cc | 344 +- .../libwebrtc/video/frame_cadence_adapter.h | 3 + .../video/frame_cadence_adapter_unittest.cc | 249 +- third_party/libwebrtc/video/full_stack_tests.cc | 2 +- third_party/libwebrtc/video/render/BUILD.gn | 1 - .../video/render/incoming_video_stream.cc | 16 +- .../libwebrtc/video/render/incoming_video_stream.h | 8 +- .../libwebrtc/video/rtp_video_stream_receiver2.cc | 121 +- .../libwebrtc/video/rtp_video_stream_receiver2.h | 13 +- .../video/rtp_video_stream_receiver2_unittest.cc | 151 +- third_party/libwebrtc/video/video_gn/moz.build | 1 - .../libwebrtc/video/video_receive_stream2.cc | 74 +- .../libwebrtc/video/video_receive_stream2.h | 37 +- .../video/video_receive_stream2_unittest.cc | 63 +- third_party/libwebrtc/video/video_send_stream.cc | 344 - third_party/libwebrtc/video/video_send_stream.h | 140 - .../libwebrtc/video/video_send_stream_impl.cc | 420 +- .../libwebrtc/video/video_send_stream_impl.h | 113 +- .../video/video_send_stream_impl_unittest.cc | 164 +- .../libwebrtc/video/video_send_stream_tests.cc | 6 +- .../libwebrtc/video/video_stream_encoder.cc | 125 +- third_party/libwebrtc/video/video_stream_encoder.h | 132 +- .../video/video_stream_encoder_unittest.cc | 7 +- third_party/libwebrtc/webrtc_lib_link_test.cc | 3 +- third_party/libwebrtc/whitespace.txt | 2 +- .../glean_parser-13.0.0.dist-info/AUTHORS.md | 17 - .../glean_parser-13.0.0.dist-info/LICENSE | 373 - .../glean_parser-13.0.0.dist-info/METADATA | 786 - .../glean_parser-13.0.0.dist-info/RECORD | 48 - .../glean_parser-13.0.0.dist-info/WHEEL | 5 - .../glean_parser-13.0.0.dist-info/entry_points.txt | 2 - .../glean_parser-13.0.0.dist-info/top_level.txt | 1 - .../glean_parser-13.0.1.dist-info/AUTHORS.md | 17 + .../glean_parser-13.0.1.dist-info/LICENSE | 373 + .../glean_parser-13.0.1.dist-info/METADATA | 790 + .../glean_parser-13.0.1.dist-info/RECORD | 48 + .../glean_parser-13.0.1.dist-info/WHEEL | 5 + .../glean_parser-13.0.1.dist-info/entry_points.txt | 2 + .../glean_parser-13.0.1.dist-info/top_level.txt | 1 + .../python/glean_parser/glean_parser/go_server.py | 1 + .../glean_parser/glean_parser/javascript_server.py | 1 + .../glean_parser/glean_parser/python_server.py | 1 + .../glean_parser/glean_parser/ruby_server.py | 1 + .../python/glean_parser/glean_parser/util.py | 7 +- third_party/python/poetry.lock | 9 +- third_party/python/requirements.in | 2 +- third_party/python/requirements.txt | 7 +- .../audio_thread_priority/.cargo-checksum.json | 2 +- third_party/rust/audio_thread_priority/Cargo.toml | 4 +- third_party/rust/audio_thread_priority/src/lib.rs | 9 + .../rust/audio_thread_priority/src/rt_win.rs | 233 +- .../rust/audioipc2-client/.cargo-checksum.json | 2 +- third_party/rust/audioipc2-client/Cargo.toml | 2 +- .../rust/audioipc2-server/.cargo-checksum.json | 2 +- third_party/rust/audioipc2-server/Cargo.toml | 2 +- third_party/rust/audioipc2-server/src/lib.rs | 4 +- third_party/rust/audioipc2-server/src/server.rs | 2 +- third_party/rust/audioipc2/.cargo-checksum.json | 2 +- third_party/rust/audioipc2/Cargo.toml | 2 +- third_party/rust/audioipc2/src/codec.rs | 2 +- third_party/rust/audioipc2/src/messages.rs | 2 +- third_party/rust/audioipc2/src/sys/unix/cmsg.rs | 2 +- third_party/rust/bumpalo/.cargo-checksum.json | 2 +- third_party/rust/bumpalo/CHANGELOG.md | 124 +- third_party/rust/bumpalo/Cargo.toml | 11 +- third_party/rust/bumpalo/README.md | 23 +- third_party/rust/bumpalo/src/alloc.rs | 2 +- .../rust/bumpalo/src/collections/raw_vec.rs | 86 +- third_party/rust/bumpalo/src/collections/string.rs | 17 +- third_party/rust/bumpalo/src/collections/vec.rs | 148 + third_party/rust/bumpalo/src/lib.rs | 192 +- .../rust/coreaudio-sys-utils/.cargo-checksum.json | 2 +- .../src/audio_device_extensions.rs | 2 + .../rust/coreaudio-sys-utils/src/audio_object.rs | 4 + .../rust/coreaudio-sys-utils/src/audio_unit.rs | 13 + .../rust/coreaudio-sys-utils/src/dispatch.rs | 268 +- .../rust/cubeb-coreaudio/.cargo-checksum.json | 2 +- .../cubeb-coreaudio/.github/workflows/test.yml | 30 +- third_party/rust/cubeb-coreaudio/Cargo.toml | 1 + .../rust/cubeb-coreaudio/run_device_tests.sh | 2 - third_party/rust/cubeb-coreaudio/run_tests.sh | 5 +- .../src/backend/aggregate_device.rs | 45 +- .../rust/cubeb-coreaudio/src/backend/mod.rs | 834 +- .../src/backend/tests/aggregate_device.rs | 347 +- .../rust/cubeb-coreaudio/src/backend/tests/api.rs | 444 +- .../src/backend/tests/device_change.rs | 36 +- .../src/backend/tests/device_property.rs | 176 +- .../src/backend/tests/interfaces.rs | 697 +- .../cubeb-coreaudio/src/backend/tests/manual.rs | 288 +- .../cubeb-coreaudio/src/backend/tests/parallel.rs | 18 +- .../rust/cubeb-coreaudio/src/backend/tests/tone.rs | 4 +- .../cubeb-coreaudio/src/backend/tests/utils.rs | 507 +- third_party/rust/d3d12/.cargo-checksum.json | 2 +- third_party/rust/d3d12/Cargo.toml | 2 +- .../rust/embed-manifest/.cargo-checksum.json | 1 + third_party/rust/embed-manifest/CHANGELOG.md | 59 + third_party/rust/embed-manifest/Cargo.toml | 38 + third_party/rust/embed-manifest/LICENSE | 23 + third_party/rust/embed-manifest/README.md | 62 + third_party/rust/embed-manifest/rustfmt.toml | 2 + third_party/rust/embed-manifest/src/embed/coff.rs | 192 + third_party/rust/embed-manifest/src/embed/error.rs | 57 + third_party/rust/embed-manifest/src/embed/mod.rs | 139 + third_party/rust/embed-manifest/src/embed/test.rs | 173 + third_party/rust/embed-manifest/src/lib.rs | 134 + .../rust/embed-manifest/src/manifest/mod.rs | 882 + .../rust/embed-manifest/src/manifest/test.rs | 117 + .../rust/embed-manifest/src/manifest/xml.rs | 140 + .../embed-manifest/testdata/sample.exe.manifest | 11 + .../rust/error-support/.cargo-checksum.json | 2 +- third_party/rust/error-support/Cargo.toml | 4 +- third_party/rust/glean-core/.cargo-checksum.json | 2 +- third_party/rust/glean-core/Cargo.toml | 6 +- .../rust/glean-core/src/common_metric_data.rs | 1 - third_party/rust/glean-core/src/core/mod.rs | 9 +- third_party/rust/glean-core/src/database/mod.rs | 1 - third_party/rust/glean-core/src/debug.rs | 1 - third_party/rust/glean-core/src/dispatcher/mod.rs | 5 +- third_party/rust/glean-core/src/error_recording.rs | 1 - .../rust/glean-core/src/event_database/mod.rs | 3 +- third_party/rust/glean-core/src/glean.udl | 1 + third_party/rust/glean-core/src/histogram/mod.rs | 1 - third_party/rust/glean-core/src/internal_pings.rs | 11 +- third_party/rust/glean-core/src/lib.rs | 5 +- third_party/rust/glean-core/src/lib_unit_tests.rs | 82 +- third_party/rust/glean-core/src/metrics/event.rs | 16 +- .../rust/glean-core/src/metrics/memory_unit.rs | 2 - .../src/metrics/metrics_enabled_config.rs | 2 +- third_party/rust/glean-core/src/metrics/ping.rs | 31 + third_party/rust/glean-core/src/metrics/string.rs | 2 - third_party/rust/glean-core/src/metrics/text.rs | 2 - .../rust/glean-core/src/metrics/time_unit.rs | 1 - .../rust/glean-core/src/metrics/timespan.rs | 1 - .../glean-core/src/metrics/timing_distribution.rs | 2 +- third_party/rust/glean-core/src/metrics/url.rs | 2 - third_party/rust/glean-core/src/storage/mod.rs | 4 +- third_party/rust/glean-core/src/traits/event.rs | 1 - .../rust/glean-core/src/upload/directory.rs | 2 - third_party/rust/glean-core/src/upload/mod.rs | 4 - third_party/rust/glean-core/src/upload/request.rs | 2 +- third_party/rust/glean-core/tests/common/mod.rs | 1 + third_party/rust/glean-core/tests/event.rs | 1 + third_party/rust/glean-core/tests/ping_maker.rs | 2 + third_party/rust/glean/.cargo-checksum.json | 2 +- third_party/rust/glean/Cargo.toml | 4 +- third_party/rust/glean/src/common_test.rs | 1 - third_party/rust/glean/src/configuration.rs | 12 + third_party/rust/glean/src/lib.rs | 1 + third_party/rust/glean/tests/schema.rs | 3 +- third_party/rust/goblin/.cargo-checksum.json | 2 +- third_party/rust/goblin/CHANGELOG.md | 27 +- third_party/rust/goblin/Cargo.toml | 10 +- third_party/rust/goblin/README.md | 7 +- third_party/rust/goblin/src/elf/reloc.rs | 2 +- third_party/rust/goblin/src/error.rs | 7 + third_party/rust/goblin/src/lib.rs | 24 +- third_party/rust/goblin/src/mach/load_command.rs | 3 + third_party/rust/goblin/src/pe/authenticode.rs | 200 +- .../rust/goblin/src/pe/certificate_table.rs | 28 +- third_party/rust/goblin/src/pe/data_directories.rs | 175 +- third_party/rust/goblin/src/pe/header.rs | 150 +- third_party/rust/goblin/src/pe/mod.rs | 249 +- third_party/rust/goblin/src/pe/optional_header.rs | 83 + third_party/rust/goblin/src/pe/options.rs | 10 +- third_party/rust/goblin/src/pe/section_table.rs | 41 +- third_party/rust/goblin/src/pe/symbol.rs | 9 + third_party/rust/goblin/src/pe/utils.rs | 16 + third_party/rust/goblin/src/strtab.rs | 5 + third_party/rust/naga/.cargo-checksum.json | 2 +- third_party/rust/naga/Cargo.toml | 4 +- third_party/rust/naga/README.md | 4 +- third_party/rust/naga/src/back/mod.rs | 58 +- third_party/rust/naga/src/back/spv/index.rs | 116 +- third_party/rust/naga/src/back/spv/mod.rs | 9 + third_party/rust/naga/src/back/spv/writer.rs | 70 +- third_party/rust/naga/src/front/glsl/variables.rs | 2 +- third_party/rust/naga/src/span.rs | 9 +- third_party/rust/naga/src/valid/analyzer.rs | 69 +- third_party/rust/naga/src/valid/type.rs | 2 +- third_party/rust/neqo-common/.cargo-checksum.json | 2 +- third_party/rust/neqo-common/Cargo.toml | 28 +- third_party/rust/neqo-common/benches/timer.rs | 39 + third_party/rust/neqo-common/src/datagram.rs | 15 +- third_party/rust/neqo-common/src/lib.rs | 2 - third_party/rust/neqo-common/src/log.rs | 21 +- third_party/rust/neqo-common/src/timer.rs | 46 +- third_party/rust/neqo-common/src/tos.rs | 48 +- third_party/rust/neqo-common/src/udp.rs | 222 - third_party/rust/neqo-crypto/.cargo-checksum.json | 2 +- third_party/rust/neqo-crypto/Cargo.toml | 8 +- .../rust/neqo-crypto/bindings/bindings.toml | 5 - third_party/rust/neqo-crypto/bindings/mozpkix.hpp | 1 - third_party/rust/neqo-crypto/build.rs | 105 +- third_party/rust/neqo-crypto/min_version.txt | 1 + third_party/rust/neqo-crypto/src/aead.rs | 8 +- third_party/rust/neqo-crypto/src/aead_fuzzing.rs | 103 - third_party/rust/neqo-crypto/src/aead_null.rs | 78 + third_party/rust/neqo-crypto/src/agent.rs | 11 +- third_party/rust/neqo-crypto/src/err.rs | 30 +- third_party/rust/neqo-crypto/src/lib.rs | 68 +- third_party/rust/neqo-crypto/src/min_version.rs | 9 + third_party/rust/neqo-crypto/src/selfencrypt.rs | 2 +- third_party/rust/neqo-crypto/src/time.rs | 4 +- third_party/rust/neqo-crypto/tests/aead.rs | 3 +- third_party/rust/neqo-crypto/tests/init.rs | 51 +- third_party/rust/neqo-crypto/tests/selfencrypt.rs | 6 +- third_party/rust/neqo-http3/.cargo-checksum.json | 2 +- third_party/rust/neqo-http3/Cargo.toml | 8 +- third_party/rust/neqo-http3/src/connection.rs | 20 +- .../rust/neqo-http3/src/connection_client.rs | 17 +- .../rust/neqo-http3/src/connection_server.rs | 17 +- third_party/rust/neqo-http3/src/recv_message.rs | 2 +- third_party/rust/neqo-http3/src/send_message.rs | 6 +- third_party/rust/neqo-http3/src/server_events.rs | 8 +- third_party/rust/neqo-qpack/.cargo-checksum.json | 2 +- third_party/rust/neqo-qpack/Cargo.toml | 2 +- third_party/rust/neqo-qpack/src/table.rs | 2 +- .../rust/neqo-transport/.cargo-checksum.json | 2 +- third_party/rust/neqo-transport/Cargo.toml | 4 +- .../rust/neqo-transport/benches/range_tracker.rs | 16 +- .../neqo-transport/benches/rx_stream_orderer.rs | 4 +- .../rust/neqo-transport/benches/transfer.rs | 16 +- .../rust/neqo-transport/src/cc/classic_cc.rs | 27 +- .../rust/neqo-transport/src/connection/dump.rs | 16 +- .../rust/neqo-transport/src/connection/mod.rs | 160 +- .../rust/neqo-transport/src/connection/params.rs | 13 - .../rust/neqo-transport/src/connection/state.rs | 5 +- .../neqo-transport/src/connection/tests/fuzzing.rs | 42 - .../src/connection/tests/handshake.rs | 11 +- .../neqo-transport/src/connection/tests/mod.rs | 85 +- .../neqo-transport/src/connection/tests/null.rs | 42 + .../neqo-transport/src/connection/tests/stream.rs | 6 - third_party/rust/neqo-transport/src/crypto.rs | 98 +- third_party/rust/neqo-transport/src/frame.rs | 86 +- third_party/rust/neqo-transport/src/lib.rs | 8 +- third_party/rust/neqo-transport/src/packet/mod.rs | 99 +- .../rust/neqo-transport/src/packet/retry.rs | 1 - third_party/rust/neqo-transport/src/path.rs | 2 +- third_party/rust/neqo-transport/src/qlog.rs | 347 +- third_party/rust/neqo-transport/src/stats.rs | 6 +- .../rust/neqo-transport/tests/common/mod.rs | 9 +- .../rust/neqo-transport/tests/conn_vectors.rs | 2 +- .../rust/neqo-transport/tests/connection.rs | 70 + third_party/rust/neqo-transport/tests/retry.rs | 2 +- .../rust/oneshot-uniffi/.cargo-checksum.json | 2 +- third_party/rust/oneshot-uniffi/CHANGELOG.md | 7 + third_party/rust/oneshot-uniffi/Cargo.lock | 2 +- third_party/rust/oneshot-uniffi/Cargo.toml | 2 +- third_party/rust/oneshot-uniffi/src/errors.rs | 15 +- third_party/rust/oneshot-uniffi/src/lib.rs | 51 +- third_party/rust/oneshot-uniffi/tests/raw.rs | 46 + third_party/rust/relevancy/.cargo-checksum.json | 1 + third_party/rust/relevancy/Cargo.toml | 47 + third_party/rust/relevancy/build.rs | 8 + .../rust/relevancy/src/bin/generate-test-data.rs | 43 + third_party/rust/relevancy/src/db.rs | 118 + third_party/rust/relevancy/src/error.rs | 44 + third_party/rust/relevancy/src/interest.rs | 167 + third_party/rust/relevancy/src/lib.rs | 81 + .../rust/relevancy/src/populate_interests.rs | 157 + third_party/rust/relevancy/src/relevancy.udl | 106 + third_party/rust/relevancy/src/schema.rs | 53 + third_party/rust/relevancy/src/url_hash.rs | 63 + third_party/rust/relevancy/test-data | Bin 0 -> 192 bytes .../rust/remote_settings/.cargo-checksum.json | 2 +- third_party/rust/remote_settings/Cargo.toml | 4 +- third_party/rust/remote_settings/src/client.rs | 54 +- third_party/rust/rure/src/lib.rs | 4 + third_party/rust/scroll/.cargo-checksum.json | 2 +- third_party/rust/scroll/CHANGELOG.md | 17 - third_party/rust/scroll/Cargo.lock | 205 - third_party/rust/scroll/Cargo.toml | 33 +- third_party/rust/scroll/README.md | 13 +- third_party/rust/scroll/benches/bench.rs | 157 - third_party/rust/scroll/examples/data_ctx.rs | 24 - third_party/rust/scroll/src/ctx.rs | 107 +- third_party/rust/scroll/src/endian.rs | 5 +- third_party/rust/scroll/src/error.rs | 26 +- third_party/rust/scroll/src/leb128.rs | 18 +- third_party/rust/scroll/src/lesser.rs | 7 +- third_party/rust/scroll/src/lib.rs | 67 +- third_party/rust/scroll/src/pread.rs | 7 +- third_party/rust/scroll/src/pwrite.rs | 9 +- third_party/rust/scroll/tests/api.rs | 292 - .../rust/scroll_derive/.cargo-checksum.json | 2 +- third_party/rust/scroll_derive/Cargo.toml | 2 +- third_party/rust/scroll_derive/README.md | 2 +- third_party/rust/smawk/.cargo-checksum.json | 1 + third_party/rust/smawk/Cargo.toml | 53 + third_party/rust/smawk/LICENSE | 21 + third_party/rust/smawk/README.md | 151 + third_party/rust/smawk/dprint.json | 19 + third_party/rust/smawk/rustfmt.toml | 2 + third_party/rust/smawk/src/brute_force.rs | 150 + third_party/rust/smawk/src/lib.rs | 570 + third_party/rust/smawk/src/monge.rs | 121 + third_party/rust/smawk/src/recursive.rs | 191 + third_party/rust/smawk/tests/agreement.rs | 104 + third_party/rust/smawk/tests/complexity.rs | 83 + third_party/rust/smawk/tests/monge.rs | 83 + third_party/rust/smawk/tests/random_monge/mod.rs | 83 + third_party/rust/smawk/tests/version-numbers.rs | 9 + third_party/rust/sql-support/.cargo-checksum.json | 2 +- third_party/rust/sql-support/src/open_database.rs | 6 + third_party/rust/suggest/.cargo-checksum.json | 2 +- third_party/rust/suggest/Cargo.toml | 28 +- third_party/rust/suggest/README.md | 110 +- third_party/rust/suggest/benches/benchmark_all.rs | 25 + third_party/rust/suggest/src/benchmarks/README.md | 28 + third_party/rust/suggest/src/benchmarks/client.rs | 97 + third_party/rust/suggest/src/benchmarks/ingest.rs | 116 + third_party/rust/suggest/src/benchmarks/mod.rs | 40 + .../rust/suggest/src/bin/debug_ingestion_sizes.rs | 9 + third_party/rust/suggest/src/config.rs | 5 + third_party/rust/suggest/src/db.rs | 720 +- third_party/rust/suggest/src/lib.rs | 4 +- third_party/rust/suggest/src/pocket.rs | 2 +- third_party/rust/suggest/src/provider.rs | 48 + third_party/rust/suggest/src/rs.rs | 223 +- third_party/rust/suggest/src/schema.rs | 187 +- third_party/rust/suggest/src/store.rs | 1113 +- third_party/rust/suggest/src/suggest.udl | 11 + third_party/rust/suggest/src/suggestion.rs | 34 + third_party/rust/suggest/src/yelp.rs | 28 +- third_party/rust/sync15/.cargo-checksum.json | 2 +- third_party/rust/sync15/Cargo.toml | 4 +- third_party/rust/tabs/.cargo-checksum.json | 2 +- third_party/rust/tabs/Cargo.toml | 4 +- third_party/rust/textwrap/.cargo-checksum.json | 1 + third_party/rust/textwrap/CHANGELOG.md | 616 + third_party/rust/textwrap/Cargo.lock | 657 + third_party/rust/textwrap/Cargo.toml | 91 + third_party/rust/textwrap/LICENSE | 21 + third_party/rust/textwrap/README.md | 176 + third_party/rust/textwrap/rustfmt.toml | 1 + third_party/rust/textwrap/src/columns.rs | 193 + third_party/rust/textwrap/src/core.rs | 461 + third_party/rust/textwrap/src/fill.rs | 298 + third_party/rust/textwrap/src/fuzzing.rs | 23 + third_party/rust/textwrap/src/indentation.rs | 347 + third_party/rust/textwrap/src/lib.rs | 235 + third_party/rust/textwrap/src/line_ending.rs | 88 + third_party/rust/textwrap/src/options.rs | 300 + third_party/rust/textwrap/src/refill.rs | 352 + third_party/rust/textwrap/src/termwidth.rs | 52 + third_party/rust/textwrap/src/word_separators.rs | 481 + third_party/rust/textwrap/src/word_splitters.rs | 314 + third_party/rust/textwrap/src/wrap.rs | 686 + third_party/rust/textwrap/src/wrap_algorithms.rs | 413 + .../textwrap/src/wrap_algorithms/optimal_fit.rs | 433 + third_party/rust/textwrap/tests/indent.rs | 88 + third_party/rust/textwrap/tests/version-numbers.rs | 22 + .../rust/unicode-linebreak/.cargo-checksum.json | 1 + third_party/rust/unicode-linebreak/Cargo.toml | 32 + third_party/rust/unicode-linebreak/LICENSE | 201 + third_party/rust/unicode-linebreak/src/lib.rs | 160 + third_party/rust/unicode-linebreak/src/shared.rs | 134 + third_party/rust/unicode-linebreak/src/tables.rs | 10 + .../uniffi-example-arithmetic/.cargo-checksum.json | 2 +- .../rust/uniffi-example-arithmetic/Cargo.toml | 6 +- .../uniffi-example-geometry/.cargo-checksum.json | 2 +- .../rust/uniffi-example-geometry/Cargo.toml | 6 +- .../tests/bindings/test_geometry.py | 6 +- .../tests/bindings/test_geometry.rb | 6 +- .../uniffi-example-rondpoint/.cargo-checksum.json | 2 +- .../rust/uniffi-example-rondpoint/Cargo.toml | 6 +- .../tests/bindings/test_rondpoint.py | 2 +- .../tests/bindings/test_rondpoint.rb | 7 +- .../uniffi-example-sprites/.cargo-checksum.json | 2 +- third_party/rust/uniffi-example-sprites/Cargo.toml | 6 +- .../tests/bindings/test_sprites.py | 18 +- .../tests/bindings/test_sprites.rb | 18 +- .../uniffi-example-todolist/.cargo-checksum.json | 2 +- .../rust/uniffi-example-todolist/Cargo.toml | 6 +- .../tests/bindings/test_todolist.py | 4 +- .../tests/bindings/test_todolist.rb | 6 +- third_party/rust/uniffi/.cargo-checksum.json | 2 +- third_party/rust/uniffi/Cargo.toml | 11 +- third_party/rust/uniffi/README.md | 81 + third_party/rust/uniffi/src/cli.rs | 21 +- third_party/rust/uniffi/src/lib.rs | 7 +- .../rust/uniffi_bindgen/.cargo-checksum.json | 2 +- third_party/rust/uniffi_bindgen/Cargo.toml | 15 +- third_party/rust/uniffi_bindgen/README.md | 81 + .../rust/uniffi_bindgen/src/backend/filters.rs | 4 +- .../kotlin/gen_kotlin/callback_interface.rs | 2 +- .../src/bindings/kotlin/gen_kotlin/compounds.rs | 115 +- .../src/bindings/kotlin/gen_kotlin/executor.rs | 24 - .../src/bindings/kotlin/gen_kotlin/external.rs | 4 +- .../src/bindings/kotlin/gen_kotlin/mod.rs | 251 +- .../src/bindings/kotlin/gen_kotlin/object.rs | 19 +- .../src/bindings/kotlin/gen_kotlin/primitives.rs | 10 +- .../src/bindings/kotlin/templates/Async.kt | 107 +- .../src/bindings/kotlin/templates/BooleanHelper.kt | 2 +- .../bindings/kotlin/templates/ByteArrayHelper.kt | 4 +- .../kotlin/templates/CallbackInterfaceImpl.kt | 117 + .../kotlin/templates/CallbackInterfaceRuntime.kt | 65 +- .../kotlin/templates/CallbackInterfaceTemplate.kt | 140 +- .../kotlin/templates/CustomTypeTemplate.kt | 2 +- .../bindings/kotlin/templates/DurationHelper.kt | 2 +- .../src/bindings/kotlin/templates/EnumTemplate.kt | 30 +- .../src/bindings/kotlin/templates/ErrorTemplate.kt | 18 +- .../kotlin/templates/ExternalTypeTemplate.kt | 2 +- .../kotlin/templates/FfiConverterTemplate.kt | 6 +- .../src/bindings/kotlin/templates/Float32Helper.kt | 2 +- .../src/bindings/kotlin/templates/Float64Helper.kt | 2 +- .../kotlin/templates/ForeignExecutorTemplate.kt | 83 - .../src/bindings/kotlin/templates/HandleMap.kt | 27 + .../src/bindings/kotlin/templates/Helpers.kt | 152 +- .../src/bindings/kotlin/templates/Int16Helper.kt | 2 +- .../src/bindings/kotlin/templates/Int32Helper.kt | 2 +- .../src/bindings/kotlin/templates/Int64Helper.kt | 2 +- .../src/bindings/kotlin/templates/Int8Helper.kt | 2 +- .../src/bindings/kotlin/templates/Interface.kt | 14 + .../src/bindings/kotlin/templates/MapTemplate.kt | 4 +- .../kotlin/templates/NamespaceLibraryTemplate.kt | 61 +- .../kotlin/templates/ObjectCleanerHelper.kt | 40 + .../kotlin/templates/ObjectCleanerHelperAndroid.kt | 26 + .../kotlin/templates/ObjectCleanerHelperJvm.kt | 25 + .../src/bindings/kotlin/templates/ObjectRuntime.kt | 161 - .../bindings/kotlin/templates/ObjectTemplate.kt | 343 +- .../bindings/kotlin/templates/OptionalTemplate.kt | 6 +- .../src/bindings/kotlin/templates/README.md | 13 + .../bindings/kotlin/templates/RecordTemplate.kt | 29 +- .../kotlin/templates/RustBufferTemplate.kt | 39 +- .../bindings/kotlin/templates/SequenceTemplate.kt | 6 +- .../src/bindings/kotlin/templates/StringHelper.kt | 10 +- .../bindings/kotlin/templates/TimestampHelper.kt | 2 +- .../kotlin/templates/TopLevelFunctionTemplate.kt | 52 +- .../src/bindings/kotlin/templates/Types.kt | 40 +- .../src/bindings/kotlin/templates/UInt16Helper.kt | 2 +- .../src/bindings/kotlin/templates/UInt32Helper.kt | 2 +- .../src/bindings/kotlin/templates/UInt64Helper.kt | 2 +- .../src/bindings/kotlin/templates/UInt8Helper.kt | 2 +- .../src/bindings/kotlin/templates/macros.kt | 140 +- .../src/bindings/kotlin/templates/wrapper.kt | 4 + .../uniffi_bindgen/src/bindings/kotlin/test.rs | 16 +- .../src/bindings/python/gen_python/compounds.rs | 16 +- .../src/bindings/python/gen_python/executor.rs | 18 - .../src/bindings/python/gen_python/external.rs | 2 +- .../src/bindings/python/gen_python/mod.rs | 177 +- .../src/bindings/python/templates/Async.py | 86 +- .../src/bindings/python/templates/BooleanHelper.py | 18 +- .../src/bindings/python/templates/BytesHelper.py | 5 +- .../python/templates/CallbackInterfaceImpl.py | 98 + .../python/templates/CallbackInterfaceRuntime.py | 59 +- .../python/templates/CallbackInterfaceTemplate.py | 112 +- .../src/bindings/python/templates/CustomType.py | 9 + .../bindings/python/templates/DurationHelper.py | 8 +- .../src/bindings/python/templates/EnumTemplate.py | 71 +- .../src/bindings/python/templates/ErrorTemplate.py | 19 + .../bindings/python/templates/ExternalTemplate.py | 8 +- .../src/bindings/python/templates/Float32Helper.py | 2 +- .../src/bindings/python/templates/Float64Helper.py | 2 +- .../python/templates/ForeignExecutorTemplate.py | 63 - .../src/bindings/python/templates/HandleMap.py | 33 + .../src/bindings/python/templates/Helpers.py | 36 +- .../src/bindings/python/templates/Int16Helper.py | 2 +- .../src/bindings/python/templates/Int32Helper.py | 2 +- .../src/bindings/python/templates/Int64Helper.py | 2 +- .../src/bindings/python/templates/Int8Helper.py | 2 +- .../src/bindings/python/templates/MapTemplate.py | 6 + .../python/templates/NamespaceLibraryTemplate.py | 45 +- .../bindings/python/templates/ObjectTemplate.py | 124 +- .../bindings/python/templates/OptionalTemplate.py | 5 + .../bindings/python/templates/PointerManager.py | 68 - .../src/bindings/python/templates/Protocol.py | 9 + .../bindings/python/templates/RecordTemplate.py | 24 +- .../bindings/python/templates/RustBufferHelper.py | 18 +- .../python/templates/RustBufferTemplate.py | 11 +- .../bindings/python/templates/SequenceTemplate.py | 5 + .../src/bindings/python/templates/StringHelper.py | 4 +- .../bindings/python/templates/TimestampHelper.py | 4 + .../python/templates/TopLevelFunctionTemplate.py | 24 +- .../src/bindings/python/templates/Types.py | 5 +- .../src/bindings/python/templates/UInt16Helper.py | 2 +- .../src/bindings/python/templates/UInt32Helper.py | 2 +- .../src/bindings/python/templates/UInt64Helper.py | 2 +- .../src/bindings/python/templates/UInt8Helper.py | 2 +- .../src/bindings/python/templates/macros.py | 95 +- .../src/bindings/python/templates/wrapper.py | 17 +- .../uniffi_bindgen/src/bindings/python/test.rs | 14 +- .../src/bindings/ruby/gen_ruby/mod.rs | 79 +- .../src/bindings/ruby/templates/ObjectTemplate.rb | 36 +- .../src/bindings/ruby/templates/RecordTemplate.rb | 7 +- .../bindings/ruby/templates/RustBufferBuilder.rb | 2 +- .../bindings/ruby/templates/RustBufferStream.rb | 4 +- .../bindings/ruby/templates/RustBufferTemplate.rb | 42 +- .../ruby/templates/TopLevelFunctionTemplate.rb | 4 +- .../src/bindings/ruby/templates/macros.rb | 10 +- .../rust/uniffi_bindgen/src/bindings/ruby/test.rs | 15 +- .../bindings/swift/gen_swift/callback_interface.rs | 12 +- .../src/bindings/swift/gen_swift/compounds.rs | 5 +- .../src/bindings/swift/gen_swift/executor.rs | 23 - .../src/bindings/swift/gen_swift/external.rs | 2 +- .../src/bindings/swift/gen_swift/mod.rs | 209 +- .../src/bindings/swift/gen_swift/object.rs | 18 +- .../src/bindings/swift/gen_swift/primitives.rs | 8 +- .../src/bindings/swift/templates/Async.swift | 100 +- .../swift/templates/BridgingHeaderTemplate.h | 48 +- .../swift/templates/CallbackInterfaceImpl.swift | 113 + .../swift/templates/CallbackInterfaceRuntime.swift | 57 - .../templates/CallbackInterfaceTemplate.swift | 145 +- .../bindings/swift/templates/EnumTemplate.swift | 27 +- .../bindings/swift/templates/ErrorTemplate.swift | 12 +- .../swift/templates/ForeignExecutorTemplate.swift | 69 - .../src/bindings/swift/templates/HandleMap.swift | 40 + .../src/bindings/swift/templates/Helpers.swift | 44 +- .../bindings/swift/templates/ObjectTemplate.swift | 201 +- .../src/bindings/swift/templates/Protocol.swift | 12 + .../bindings/swift/templates/RecordTemplate.swift | 17 +- .../swift/templates/RustBufferTemplate.swift | 4 + .../swift/templates/TopLevelFunctionTemplate.swift | 49 +- .../src/bindings/swift/templates/Types.swift | 3 - .../src/bindings/swift/templates/macros.swift | 125 +- .../src/bindings/swift/templates/wrapper.swift | 8 + .../rust/uniffi_bindgen/src/bindings/swift/test.rs | 24 +- .../rust/uniffi_bindgen/src/interface/callbacks.rs | 207 +- .../rust/uniffi_bindgen/src/interface/enum_.rs | 224 +- .../rust/uniffi_bindgen/src/interface/ffi.rs | 195 +- .../rust/uniffi_bindgen/src/interface/function.rs | 32 + .../rust/uniffi_bindgen/src/interface/mod.rs | 342 +- .../rust/uniffi_bindgen/src/interface/object.rs | 199 +- .../rust/uniffi_bindgen/src/interface/record.rs | 53 + .../rust/uniffi_bindgen/src/interface/universe.rs | 5 +- third_party/rust/uniffi_bindgen/src/lib.rs | 138 +- .../rust/uniffi_bindgen/src/library_mode.rs | 40 +- .../rust/uniffi_bindgen/src/macro_metadata/ci.rs | 21 +- .../uniffi_bindgen/src/macro_metadata/extract.rs | 2 +- .../rust/uniffi_bindgen/src/scaffolding/mod.rs | 36 +- .../templates/CallbackInterfaceTemplate.rs | 93 +- .../src/scaffolding/templates/EnumTemplate.rs | 13 +- .../src/scaffolding/templates/ErrorTemplate.rs | 10 +- .../scaffolding/templates/ExternalTypesTemplate.rs | 2 + .../src/scaffolding/templates/ObjectTemplate.rs | 34 +- .../src/scaffolding/templates/RecordTemplate.rs | 8 +- .../templates/TopLevelFunctionTemplate.rs | 5 +- third_party/rust/uniffi_build/.cargo-checksum.json | 2 +- third_party/rust/uniffi_build/Cargo.toml | 5 +- third_party/rust/uniffi_build/README.md | 81 + .../uniffi_checksum_derive/.cargo-checksum.json | 2 +- third_party/rust/uniffi_checksum_derive/Cargo.toml | 3 +- third_party/rust/uniffi_checksum_derive/README.md | 81 + third_party/rust/uniffi_core/.cargo-checksum.json | 2 +- third_party/rust/uniffi_core/Cargo.toml | 6 +- third_party/rust/uniffi_core/README.md | 81 + .../rust/uniffi_core/src/ffi/callbackinterface.rs | 125 +- third_party/rust/uniffi_core/src/ffi/ffidefault.rs | 11 +- .../rust/uniffi_core/src/ffi/foreigncallbacks.rs | 116 +- .../rust/uniffi_core/src/ffi/foreignexecutor.rs | 487 - .../rust/uniffi_core/src/ffi/foreignfuture.rs | 241 + third_party/rust/uniffi_core/src/ffi/handle.rs | 46 + third_party/rust/uniffi_core/src/ffi/mod.rs | 6 +- third_party/rust/uniffi_core/src/ffi/rustbuffer.rs | 122 +- third_party/rust/uniffi_core/src/ffi/rustcalls.rs | 9 +- third_party/rust/uniffi_core/src/ffi/rustfuture.rs | 735 - .../rust/uniffi_core/src/ffi/rustfuture/future.rs | 320 + .../rust/uniffi_core/src/ffi/rustfuture/mod.rs | 141 + .../uniffi_core/src/ffi/rustfuture/scheduler.rs | 96 + .../rust/uniffi_core/src/ffi/rustfuture/tests.rs | 223 + .../rust/uniffi_core/src/ffi_converter_impls.rs | 75 +- .../rust/uniffi_core/src/ffi_converter_traits.rs | 151 +- third_party/rust/uniffi_core/src/lib.rs | 6 +- third_party/rust/uniffi_core/src/metadata.rs | 53 +- .../rust/uniffi_macros/.cargo-checksum.json | 2 +- third_party/rust/uniffi_macros/Cargo.toml | 10 +- third_party/rust/uniffi_macros/README.md | 81 + third_party/rust/uniffi_macros/src/default.rs | 133 + third_party/rust/uniffi_macros/src/enum_.rs | 308 +- third_party/rust/uniffi_macros/src/error.rs | 101 +- third_party/rust/uniffi_macros/src/export.rs | 211 +- .../rust/uniffi_macros/src/export/attributes.rs | 306 +- .../uniffi_macros/src/export/callback_interface.rs | 204 +- third_party/rust/uniffi_macros/src/export/item.rs | 88 +- .../rust/uniffi_macros/src/export/scaffolding.rs | 123 +- .../uniffi_macros/src/export/trait_interface.rs | 183 + .../rust/uniffi_macros/src/export/utrait.rs | 23 +- third_party/rust/uniffi_macros/src/fnsig.rs | 248 +- third_party/rust/uniffi_macros/src/lib.rs | 73 +- third_party/rust/uniffi_macros/src/object.rs | 76 +- third_party/rust/uniffi_macros/src/record.rs | 113 +- .../rust/uniffi_macros/src/setup_scaffolding.rs | 57 +- third_party/rust/uniffi_macros/src/util.rs | 47 +- third_party/rust/uniffi_meta/.cargo-checksum.json | 2 +- third_party/rust/uniffi_meta/Cargo.toml | 5 +- third_party/rust/uniffi_meta/README.md | 81 + third_party/rust/uniffi_meta/src/ffi_names.rs | 13 +- third_party/rust/uniffi_meta/src/group.rs | 9 +- third_party/rust/uniffi_meta/src/lib.rs | 65 +- third_party/rust/uniffi_meta/src/metadata.rs | 13 +- third_party/rust/uniffi_meta/src/reader.rs | 148 +- third_party/rust/uniffi_meta/src/types.rs | 22 +- .../rust/uniffi_testing/.cargo-checksum.json | 2 +- third_party/rust/uniffi_testing/Cargo.toml | 2 +- third_party/rust/uniffi_udl/.cargo-checksum.json | 2 +- third_party/rust/uniffi_udl/Cargo.toml | 12 +- third_party/rust/uniffi_udl/README.md | 81 + third_party/rust/uniffi_udl/src/attributes.rs | 199 +- third_party/rust/uniffi_udl/src/collectors.rs | 18 +- .../rust/uniffi_udl/src/converters/callables.rs | 16 +- .../rust/uniffi_udl/src/converters/enum_.rs | 79 +- .../rust/uniffi_udl/src/converters/interface.rs | 6 +- third_party/rust/uniffi_udl/src/converters/mod.rs | 10 + third_party/rust/uniffi_udl/src/finder.rs | 60 +- third_party/rust/uniffi_udl/src/lib.rs | 2 +- third_party/rust/uniffi_udl/src/literal.rs | 8 +- third_party/rust/uniffi_udl/src/resolver.rs | 1 - third_party/rust/wasm-encoder/.cargo-checksum.json | 2 +- third_party/rust/wasm-encoder/Cargo.toml | 10 +- .../rust/wasm-encoder/src/component/names.rs | 2 +- third_party/rust/wasm-encoder/src/core/code.rs | 89 + third_party/rust/wasm-smith/.cargo-checksum.json | 2 +- third_party/rust/wasm-smith/Cargo.toml | 18 +- third_party/rust/wasm-smith/src/component.rs | 53 +- third_party/rust/wasm-smith/src/config.rs | 108 +- third_party/rust/wasm-smith/src/core.rs | 806 +- .../rust/wasm-smith/src/core/code_builder.rs | 141 +- .../wasm-smith/src/core/code_builder/no_traps.rs | 2 +- third_party/rust/wasm-smith/src/core/encode.rs | 41 +- third_party/rust/wasm-smith/src/core/terminate.rs | 30 +- third_party/rust/wasm-smith/src/lib.rs | 7 +- .../rust/wasm-smith/tests/available_imports.rs | 46 +- third_party/rust/wasm-smith/tests/common/mod.rs | 43 + third_party/rust/wasm-smith/tests/core.rs | 3 +- third_party/rust/wasm-smith/tests/exports.rs | 147 + third_party/rust/wast/.cargo-checksum.json | 2 +- third_party/rust/wast/Cargo.toml | 13 +- third_party/rust/wast/src/component/component.rs | 1 + third_party/rust/wast/src/core/binary.rs | 124 +- third_party/rust/wast/src/core/expr.rs | 53 +- third_party/rust/wast/src/core/memory.rs | 2 + third_party/rust/wast/src/core/module.rs | 1 + .../src/core/resolve/deinline_import_export.rs | 2 + third_party/rust/wast/src/core/table.rs | 1 + third_party/rust/wast/src/lib.rs | 1 + third_party/rust/wast/src/parser.rs | 12 +- third_party/rust/wast/src/wat.rs | 1 + .../rust/webext-storage/.cargo-checksum.json | 2 +- third_party/rust/webext-storage/Cargo.toml | 4 +- third_party/rust/weedle2/.cargo-checksum.json | 2 +- third_party/rust/weedle2/Cargo.toml | 5 +- third_party/rust/weedle2/README.md | 2 +- third_party/rust/weedle2/src/common.rs | 45 + third_party/rust/weedle2/src/dictionary.rs | 3 +- third_party/rust/weedle2/src/interface.rs | 4 +- third_party/rust/weedle2/src/lib.rs | 16 +- third_party/rust/weedle2/src/namespace.rs | 4 +- third_party/rust/weedle2/src/whitespace.rs | 1 + third_party/rust/wgpu-core/.cargo-checksum.json | 2 +- third_party/rust/wgpu-core/Cargo.toml | 4 +- third_party/rust/wgpu-core/src/command/bundle.rs | 21 +- third_party/rust/wgpu-core/src/command/clear.rs | 7 +- third_party/rust/wgpu-core/src/command/compute.rs | 9 +- .../rust/wgpu-core/src/command/memory_init.rs | 11 +- third_party/rust/wgpu-core/src/command/render.rs | 15 +- third_party/rust/wgpu-core/src/command/transfer.rs | 19 +- third_party/rust/wgpu-core/src/device/global.rs | 33 +- third_party/rust/wgpu-core/src/device/life.rs | 15 +- third_party/rust/wgpu-core/src/device/mod.rs | 11 +- third_party/rust/wgpu-core/src/device/queue.rs | 17 +- third_party/rust/wgpu-core/src/device/resource.rs | 20 +- third_party/rust/wgpu-core/src/snatch.rs | 35 +- third_party/rust/wgpu-core/src/track/buffer.rs | 12 +- third_party/rust/wgpu-core/src/track/metadata.rs | 5 + third_party/rust/wgpu-core/src/track/mod.rs | 50 +- third_party/rust/wgpu-core/src/track/texture.rs | 13 +- third_party/rust/wgpu-hal/.cargo-checksum.json | 2 +- third_party/rust/wgpu-hal/Cargo.toml | 12 +- third_party/rust/wgpu-hal/src/dx12/adapter.rs | 4 +- third_party/rust/wgpu-hal/src/dx12/command.rs | 4 +- third_party/rust/wgpu-hal/src/dx12/device.rs | 15 +- third_party/rust/wgpu-hal/src/dx12/instance.rs | 4 +- third_party/rust/wgpu-hal/src/dx12/mod.rs | 8 +- third_party/rust/wgpu-hal/src/empty.rs | 24 +- third_party/rust/wgpu-hal/src/gles/adapter.rs | 4 +- third_party/rust/wgpu-hal/src/gles/command.rs | 4 +- third_party/rust/wgpu-hal/src/gles/device.rs | 21 +- third_party/rust/wgpu-hal/src/gles/egl.rs | 8 +- third_party/rust/wgpu-hal/src/gles/queue.rs | 4 +- third_party/rust/wgpu-hal/src/gles/web.rs | 8 +- third_party/rust/wgpu-hal/src/gles/wgl.rs | 8 +- third_party/rust/wgpu-hal/src/lib.rs | 253 +- third_party/rust/wgpu-hal/src/metal/adapter.rs | 4 +- third_party/rust/wgpu-hal/src/metal/command.rs | 4 +- third_party/rust/wgpu-hal/src/metal/device.rs | 15 +- third_party/rust/wgpu-hal/src/metal/mod.rs | 8 +- third_party/rust/wgpu-hal/src/metal/surface.rs | 4 +- third_party/rust/wgpu-hal/src/vulkan/adapter.rs | 181 +- third_party/rust/wgpu-hal/src/vulkan/command.rs | 4 +- third_party/rust/wgpu-hal/src/vulkan/device.rs | 4 +- third_party/rust/wgpu-hal/src/vulkan/instance.rs | 8 +- third_party/rust/wgpu-hal/src/vulkan/mod.rs | 6 +- third_party/rust/wgpu-types/.cargo-checksum.json | 2 +- third_party/rust/wgpu-types/Cargo.toml | 6 +- third_party/rust/wgpu-types/src/lib.rs | 29 +- third_party/rust/zip/src/read.rs | 9 +- third_party/rust/zip/src/types.rs | 2 - third_party/rust/zip/src/write.rs | 1 + .../xsimd/include/xsimd/config/xsimd_arch.hpp | 28 +- .../include/xsimd/types/xsimd_avx2_register.hpp | 1 - .../xsimd/types/xsimd_avx512bw_register.hpp | 1 - .../xsimd/types/xsimd_avx512cd_register.hpp | 1 - .../xsimd/types/xsimd_avx512dq_register.hpp | 1 - .../xsimd/types/xsimd_avx512er_register.hpp | 1 - .../include/xsimd/types/xsimd_avx512f_register.hpp | 1 - .../xsimd/types/xsimd_avx512ifma_register.hpp | 1 - .../xsimd/types/xsimd_avx512pf_register.hpp | 1 - .../xsimd/types/xsimd_avx512vbmi_register.hpp | 1 - .../types/xsimd_avx512vnni_avx512bw_register.hpp | 1 - .../types/xsimd_avx512vnni_avx512vbmi_register.hpp | 1 - .../include/xsimd/types/xsimd_avx_register.hpp | 1 - .../include/xsimd/types/xsimd_avxvnni_register.hpp | 1 - .../xsimd/include/xsimd/types/xsimd_batch.hpp | 4 +- .../xsimd/types/xsimd_fma3_avx2_register.hpp | 1 - .../xsimd/types/xsimd_fma3_avx_register.hpp | 1 - .../xsimd/types/xsimd_fma3_sse_register.hpp | 1 - .../include/xsimd/types/xsimd_fma4_register.hpp | 1 - .../include/xsimd/types/xsimd_generic_arch.hpp | 5 - .../xsimd/types/xsimd_i8mm_neon64_register.hpp | 6 +- .../include/xsimd/types/xsimd_neon64_register.hpp | 1 - .../include/xsimd/types/xsimd_neon_register.hpp | 1 - .../include/xsimd/types/xsimd_rvv_register.hpp | 1 - .../include/xsimd/types/xsimd_sse2_register.hpp | 1 - .../include/xsimd/types/xsimd_sse3_register.hpp | 1 - .../include/xsimd/types/xsimd_sse4_1_register.hpp | 1 - .../include/xsimd/types/xsimd_sse4_2_register.hpp | 1 - .../include/xsimd/types/xsimd_ssse3_register.hpp | 1 - .../include/xsimd/types/xsimd_sve_register.hpp | 1 - .../include/xsimd/types/xsimd_wasm_register.hpp | 1 - third_party/xsimd/moz.yaml | 4 +- third_party/zstd/COPYING | 339 + third_party/zstd/LICENSE | 30 + third_party/zstd/lib/.gitignore | 3 + third_party/zstd/lib/BUCK | 232 + third_party/zstd/lib/Makefile | 369 + third_party/zstd/lib/README.md | 237 + third_party/zstd/lib/common/allocations.h | 55 + third_party/zstd/lib/common/bits.h | 200 + third_party/zstd/lib/common/bitstream.h | 457 + third_party/zstd/lib/common/compiler.h | 450 + third_party/zstd/lib/common/cpu.h | 249 + third_party/zstd/lib/common/debug.c | 30 + third_party/zstd/lib/common/debug.h | 116 + third_party/zstd/lib/common/entropy_common.c | 340 + third_party/zstd/lib/common/error_private.c | 63 + third_party/zstd/lib/common/error_private.h | 168 + third_party/zstd/lib/common/fse.h | 640 + third_party/zstd/lib/common/fse_decompress.c | 313 + third_party/zstd/lib/common/huf.h | 286 + third_party/zstd/lib/common/mem.h | 426 + third_party/zstd/lib/common/pool.c | 371 + third_party/zstd/lib/common/pool.h | 90 + third_party/zstd/lib/common/portability_macros.h | 158 + third_party/zstd/lib/common/threading.c | 182 + third_party/zstd/lib/common/threading.h | 150 + third_party/zstd/lib/common/xxhash.c | 18 + third_party/zstd/lib/common/xxhash.h | 7020 ++++ third_party/zstd/lib/common/zstd_common.c | 48 + third_party/zstd/lib/common/zstd_deps.h | 111 + third_party/zstd/lib/common/zstd_internal.h | 392 + third_party/zstd/lib/common/zstd_trace.h | 163 + third_party/zstd/lib/decompress/huf_decompress.c | 1944 + .../zstd/lib/decompress/huf_decompress_amd64.S | 595 + third_party/zstd/lib/decompress/zstd_ddict.c | 244 + third_party/zstd/lib/decompress/zstd_ddict.h | 44 + third_party/zstd/lib/decompress/zstd_decompress.c | 2407 ++ .../zstd/lib/decompress/zstd_decompress_block.c | 2215 ++ .../zstd/lib/decompress/zstd_decompress_block.h | 73 + .../zstd/lib/decompress/zstd_decompress_internal.h | 240 + third_party/zstd/lib/libzstd.mk | 235 + third_party/zstd/lib/libzstd.pc.in | 16 + third_party/zstd/lib/module.modulemap | 35 + third_party/zstd/lib/zdict.h | 474 + third_party/zstd/lib/zstd.h | 3089 ++ third_party/zstd/lib/zstd_errors.h | 114 + third_party/zstd/moz.build | 107 + third_party/zstd/moz.yaml | 44 + third_party/zstd/preprocess_asm.py | 25 + 1577 files changed, 122018 insertions(+), 66540 deletions(-) create mode 100644 third_party/aom/aom_dsp/arm/aom_filter.h create mode 100644 third_party/aom/aom_dsp/arm/aom_neon_sve2_bridge.h create mode 100644 third_party/aom/aom_dsp/arm/aom_neon_sve_bridge.h delete mode 100644 third_party/aom/aom_dsp/arm/dot_sve.h create mode 100644 third_party/aom/aom_dsp/arm/highbd_convolve8_sve.c create mode 100644 third_party/aom/aom_dsp/flow_estimation/x86/disflow_avx2.c delete mode 100644 third_party/aom/aom_dsp/rect.h delete mode 100644 third_party/aom/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c delete mode 100644 third_party/aom/aom_dsp/x86/aom_subpixel_8t_sse2.asm delete mode 100644 third_party/aom/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm delete mode 100644 third_party/aom/aom_dsp/x86/subpel_variance_sse2.asm create mode 100644 third_party/aom/aom_dsp/x86/subpel_variance_ssse3.asm create mode 100644 third_party/aom/aom_util/aom_pthread.h create mode 100644 third_party/aom/av1/common/arm/highbd_compound_convolve_neon.h create mode 100644 third_party/aom/av1/common/arm/highbd_compound_convolve_sve2.c create mode 100644 third_party/aom/av1/common/arm/highbd_convolve_sve2.c create mode 100644 third_party/aom/av1/common/arm/highbd_convolve_sve2.h delete mode 100644 third_party/aom/av1/common/x86/cdef_block_sse2.c create mode 100644 third_party/aom/av1/encoder/arm/neon/wedge_utils_sve.c delete mode 100644 third_party/content_analysis_sdk/.gitignore create mode 100644 third_party/content_analysis_sdk/agent_improvements.patch create mode 100644 third_party/content_analysis_sdk/moz.yaml delete mode 100644 third_party/libwebrtc/api/call/call_factory_interface.h delete mode 100644 third_party/libwebrtc/api/callfactory_api_gn/moz.build create mode 100644 third_party/libwebrtc/api/environment/environment_factory_gn/moz.build create mode 100644 third_party/libwebrtc/api/stats/attribute.h create mode 100644 third_party/libwebrtc/api/stats/rtc_stats_member.h create mode 100644 third_party/libwebrtc/api/task_queue/default_task_queue_factory_gn/moz.build delete mode 100644 third_party/libwebrtc/call/call_factory.cc delete mode 100644 third_party/libwebrtc/call/call_factory.h create mode 100644 third_party/libwebrtc/call/create_call.cc create mode 100644 third_party/libwebrtc/call/create_call.h create mode 100644 third_party/libwebrtc/docs/native-code/development/fuzzers/README.md create mode 100644 third_party/libwebrtc/moz-patch-stack/0107.patch create mode 100644 third_party/libwebrtc/moz-patch-stack/0108.patch create mode 100644 third_party/libwebrtc/moz-patch-stack/0109.patch create mode 100644 third_party/libwebrtc/moz-patch-stack/0110.patch delete mode 100644 third_party/libwebrtc/moz-patch-stack/058bfe3ae3.no-op-cherry-pick-msg delete mode 100644 third_party/libwebrtc/moz-patch-stack/16ac10d9f7.no-op-cherry-pick-msg delete mode 100644 third_party/libwebrtc/moz-patch-stack/334e9133dc.no-op-cherry-pick-msg delete mode 100644 third_party/libwebrtc/moz-patch-stack/6a992129fb.no-op-cherry-pick-msg create mode 100644 third_party/libwebrtc/moz-patch-stack/de3c726121.no-op-cherry-pick-msg delete mode 100644 third_party/libwebrtc/rtc_base/gunit.cc create mode 100644 third_party/libwebrtc/stats/attribute.cc create mode 100644 third_party/libwebrtc/stats/rtc_stats_member.cc create mode 100644 third_party/libwebrtc/test/fuzzers/corpora/receive-side-cc/testcase-5414098152390656 create mode 100644 third_party/libwebrtc/test/fuzzers/rtp_format_h264_fuzzer.cc create mode 100644 third_party/libwebrtc/test/fuzzers/rtp_format_vp8_fuzzer.cc create mode 100644 third_party/libwebrtc/test/fuzzers/rtp_format_vp9_fuzzer.cc delete mode 100644 third_party/libwebrtc/video/video_send_stream.cc delete mode 100644 third_party/libwebrtc/video/video_send_stream.h delete mode 100644 third_party/python/glean_parser/glean_parser-13.0.0.dist-info/AUTHORS.md delete mode 100644 third_party/python/glean_parser/glean_parser-13.0.0.dist-info/LICENSE delete mode 100644 third_party/python/glean_parser/glean_parser-13.0.0.dist-info/METADATA delete mode 100644 third_party/python/glean_parser/glean_parser-13.0.0.dist-info/RECORD delete mode 100644 third_party/python/glean_parser/glean_parser-13.0.0.dist-info/WHEEL delete mode 100644 third_party/python/glean_parser/glean_parser-13.0.0.dist-info/entry_points.txt delete mode 100644 third_party/python/glean_parser/glean_parser-13.0.0.dist-info/top_level.txt create mode 100644 third_party/python/glean_parser/glean_parser-13.0.1.dist-info/AUTHORS.md create mode 100644 third_party/python/glean_parser/glean_parser-13.0.1.dist-info/LICENSE create mode 100644 third_party/python/glean_parser/glean_parser-13.0.1.dist-info/METADATA create mode 100644 third_party/python/glean_parser/glean_parser-13.0.1.dist-info/RECORD create mode 100644 third_party/python/glean_parser/glean_parser-13.0.1.dist-info/WHEEL create mode 100644 third_party/python/glean_parser/glean_parser-13.0.1.dist-info/entry_points.txt create mode 100644 third_party/python/glean_parser/glean_parser-13.0.1.dist-info/top_level.txt mode change 100644 => 100755 third_party/rust/bumpalo/src/lib.rs create mode 100644 third_party/rust/embed-manifest/.cargo-checksum.json create mode 100644 third_party/rust/embed-manifest/CHANGELOG.md create mode 100644 third_party/rust/embed-manifest/Cargo.toml create mode 100644 third_party/rust/embed-manifest/LICENSE create mode 100644 third_party/rust/embed-manifest/README.md create mode 100644 third_party/rust/embed-manifest/rustfmt.toml create mode 100644 third_party/rust/embed-manifest/src/embed/coff.rs create mode 100644 third_party/rust/embed-manifest/src/embed/error.rs create mode 100644 third_party/rust/embed-manifest/src/embed/mod.rs create mode 100644 third_party/rust/embed-manifest/src/embed/test.rs create mode 100644 third_party/rust/embed-manifest/src/lib.rs create mode 100644 third_party/rust/embed-manifest/src/manifest/mod.rs create mode 100644 third_party/rust/embed-manifest/src/manifest/test.rs create mode 100644 third_party/rust/embed-manifest/src/manifest/xml.rs create mode 100644 third_party/rust/embed-manifest/testdata/sample.exe.manifest create mode 100644 third_party/rust/neqo-common/benches/timer.rs delete mode 100644 third_party/rust/neqo-common/src/udp.rs delete mode 100644 third_party/rust/neqo-crypto/bindings/mozpkix.hpp create mode 100644 third_party/rust/neqo-crypto/min_version.txt delete mode 100644 third_party/rust/neqo-crypto/src/aead_fuzzing.rs create mode 100644 third_party/rust/neqo-crypto/src/aead_null.rs create mode 100644 third_party/rust/neqo-crypto/src/min_version.rs delete mode 100644 third_party/rust/neqo-transport/src/connection/tests/fuzzing.rs create mode 100644 third_party/rust/neqo-transport/src/connection/tests/null.rs create mode 100644 third_party/rust/oneshot-uniffi/tests/raw.rs create mode 100644 third_party/rust/relevancy/.cargo-checksum.json create mode 100644 third_party/rust/relevancy/Cargo.toml create mode 100644 third_party/rust/relevancy/build.rs create mode 100644 third_party/rust/relevancy/src/bin/generate-test-data.rs create mode 100644 third_party/rust/relevancy/src/db.rs create mode 100644 third_party/rust/relevancy/src/error.rs create mode 100644 third_party/rust/relevancy/src/interest.rs create mode 100644 third_party/rust/relevancy/src/lib.rs create mode 100644 third_party/rust/relevancy/src/populate_interests.rs create mode 100644 third_party/rust/relevancy/src/relevancy.udl create mode 100644 third_party/rust/relevancy/src/schema.rs create mode 100644 third_party/rust/relevancy/src/url_hash.rs create mode 100644 third_party/rust/relevancy/test-data delete mode 100644 third_party/rust/scroll/CHANGELOG.md delete mode 100644 third_party/rust/scroll/Cargo.lock delete mode 100644 third_party/rust/scroll/benches/bench.rs delete mode 100644 third_party/rust/scroll/examples/data_ctx.rs delete mode 100644 third_party/rust/scroll/tests/api.rs create mode 100644 third_party/rust/smawk/.cargo-checksum.json create mode 100644 third_party/rust/smawk/Cargo.toml create mode 100644 third_party/rust/smawk/LICENSE create mode 100644 third_party/rust/smawk/README.md create mode 100644 third_party/rust/smawk/dprint.json create mode 100644 third_party/rust/smawk/rustfmt.toml create mode 100644 third_party/rust/smawk/src/brute_force.rs create mode 100644 third_party/rust/smawk/src/lib.rs create mode 100644 third_party/rust/smawk/src/monge.rs create mode 100644 third_party/rust/smawk/src/recursive.rs create mode 100644 third_party/rust/smawk/tests/agreement.rs create mode 100644 third_party/rust/smawk/tests/complexity.rs create mode 100644 third_party/rust/smawk/tests/monge.rs create mode 100644 third_party/rust/smawk/tests/random_monge/mod.rs create mode 100644 third_party/rust/smawk/tests/version-numbers.rs create mode 100644 third_party/rust/suggest/benches/benchmark_all.rs create mode 100644 third_party/rust/suggest/src/benchmarks/README.md create mode 100644 third_party/rust/suggest/src/benchmarks/client.rs create mode 100644 third_party/rust/suggest/src/benchmarks/ingest.rs create mode 100644 third_party/rust/suggest/src/benchmarks/mod.rs create mode 100644 third_party/rust/suggest/src/bin/debug_ingestion_sizes.rs create mode 100644 third_party/rust/textwrap/.cargo-checksum.json create mode 100644 third_party/rust/textwrap/CHANGELOG.md create mode 100644 third_party/rust/textwrap/Cargo.lock create mode 100644 third_party/rust/textwrap/Cargo.toml create mode 100644 third_party/rust/textwrap/LICENSE create mode 100644 third_party/rust/textwrap/README.md create mode 100644 third_party/rust/textwrap/rustfmt.toml create mode 100644 third_party/rust/textwrap/src/columns.rs create mode 100644 third_party/rust/textwrap/src/core.rs create mode 100644 third_party/rust/textwrap/src/fill.rs create mode 100644 third_party/rust/textwrap/src/fuzzing.rs create mode 100644 third_party/rust/textwrap/src/indentation.rs create mode 100644 third_party/rust/textwrap/src/lib.rs create mode 100644 third_party/rust/textwrap/src/line_ending.rs create mode 100644 third_party/rust/textwrap/src/options.rs create mode 100644 third_party/rust/textwrap/src/refill.rs create mode 100644 third_party/rust/textwrap/src/termwidth.rs create mode 100644 third_party/rust/textwrap/src/word_separators.rs create mode 100644 third_party/rust/textwrap/src/word_splitters.rs create mode 100644 third_party/rust/textwrap/src/wrap.rs create mode 100644 third_party/rust/textwrap/src/wrap_algorithms.rs create mode 100644 third_party/rust/textwrap/src/wrap_algorithms/optimal_fit.rs create mode 100644 third_party/rust/textwrap/tests/indent.rs create mode 100644 third_party/rust/textwrap/tests/version-numbers.rs create mode 100644 third_party/rust/unicode-linebreak/.cargo-checksum.json create mode 100644 third_party/rust/unicode-linebreak/Cargo.toml create mode 100644 third_party/rust/unicode-linebreak/LICENSE create mode 100644 third_party/rust/unicode-linebreak/src/lib.rs create mode 100644 third_party/rust/unicode-linebreak/src/shared.rs create mode 100644 third_party/rust/unicode-linebreak/src/tables.rs create mode 100644 third_party/rust/uniffi/README.md create mode 100644 third_party/rust/uniffi_bindgen/README.md delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ForeignExecutorTemplate.kt create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Interface.kt create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelper.kt create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperAndroid.kt create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperJvm.kt delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectRuntime.kt create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/README.md delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/executor.rs create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceImpl.py delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/ForeignExecutorTemplate.py create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/HandleMap.py delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/PointerManager.py create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/Protocol.py delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceImpl.swift delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ForeignExecutorTemplate.swift create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/HandleMap.swift create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Protocol.swift create mode 100644 third_party/rust/uniffi_build/README.md create mode 100644 third_party/rust/uniffi_checksum_derive/README.md create mode 100644 third_party/rust/uniffi_core/README.md delete mode 100644 third_party/rust/uniffi_core/src/ffi/foreignexecutor.rs create mode 100644 third_party/rust/uniffi_core/src/ffi/foreignfuture.rs create mode 100644 third_party/rust/uniffi_core/src/ffi/handle.rs delete mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture.rs create mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture/future.rs create mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture/mod.rs create mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture/scheduler.rs create mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture/tests.rs create mode 100644 third_party/rust/uniffi_macros/README.md create mode 100644 third_party/rust/uniffi_macros/src/default.rs create mode 100644 third_party/rust/uniffi_macros/src/export/trait_interface.rs create mode 100644 third_party/rust/uniffi_meta/README.md create mode 100644 third_party/rust/uniffi_udl/README.md create mode 100644 third_party/rust/wasm-smith/tests/common/mod.rs create mode 100644 third_party/rust/wasm-smith/tests/exports.rs create mode 100644 third_party/zstd/COPYING create mode 100644 third_party/zstd/LICENSE create mode 100644 third_party/zstd/lib/.gitignore create mode 100644 third_party/zstd/lib/BUCK create mode 100644 third_party/zstd/lib/Makefile create mode 100644 third_party/zstd/lib/README.md create mode 100644 third_party/zstd/lib/common/allocations.h create mode 100644 third_party/zstd/lib/common/bits.h create mode 100644 third_party/zstd/lib/common/bitstream.h create mode 100644 third_party/zstd/lib/common/compiler.h create mode 100644 third_party/zstd/lib/common/cpu.h create mode 100644 third_party/zstd/lib/common/debug.c create mode 100644 third_party/zstd/lib/common/debug.h create mode 100644 third_party/zstd/lib/common/entropy_common.c create mode 100644 third_party/zstd/lib/common/error_private.c create mode 100644 third_party/zstd/lib/common/error_private.h create mode 100644 third_party/zstd/lib/common/fse.h create mode 100644 third_party/zstd/lib/common/fse_decompress.c create mode 100644 third_party/zstd/lib/common/huf.h create mode 100644 third_party/zstd/lib/common/mem.h create mode 100644 third_party/zstd/lib/common/pool.c create mode 100644 third_party/zstd/lib/common/pool.h create mode 100644 third_party/zstd/lib/common/portability_macros.h create mode 100644 third_party/zstd/lib/common/threading.c create mode 100644 third_party/zstd/lib/common/threading.h create mode 100644 third_party/zstd/lib/common/xxhash.c create mode 100644 third_party/zstd/lib/common/xxhash.h create mode 100644 third_party/zstd/lib/common/zstd_common.c create mode 100644 third_party/zstd/lib/common/zstd_deps.h create mode 100644 third_party/zstd/lib/common/zstd_internal.h create mode 100644 third_party/zstd/lib/common/zstd_trace.h create mode 100644 third_party/zstd/lib/decompress/huf_decompress.c create mode 100644 third_party/zstd/lib/decompress/huf_decompress_amd64.S create mode 100644 third_party/zstd/lib/decompress/zstd_ddict.c create mode 100644 third_party/zstd/lib/decompress/zstd_ddict.h create mode 100644 third_party/zstd/lib/decompress/zstd_decompress.c create mode 100644 third_party/zstd/lib/decompress/zstd_decompress_block.c create mode 100644 third_party/zstd/lib/decompress/zstd_decompress_block.h create mode 100644 third_party/zstd/lib/decompress/zstd_decompress_internal.h create mode 100644 third_party/zstd/lib/libzstd.mk create mode 100644 third_party/zstd/lib/libzstd.pc.in create mode 100644 third_party/zstd/lib/module.modulemap create mode 100644 third_party/zstd/lib/zdict.h create mode 100644 third_party/zstd/lib/zstd.h create mode 100644 third_party/zstd/lib/zstd_errors.h create mode 100644 third_party/zstd/moz.build create mode 100644 third_party/zstd/moz.yaml create mode 100644 third_party/zstd/preprocess_asm.py (limited to 'third_party') diff --git a/third_party/aom/CHANGELOG b/third_party/aom/CHANGELOG index b5c1afbba2..b8a3e4a6a5 100644 --- a/third_party/aom/CHANGELOG +++ b/third_party/aom/CHANGELOG @@ -1,3 +1,22 @@ +2024-03-08 v3.8.2 + This release includes several bug fixes. This release is ABI + compatible with the last release. See + https://aomedia.googlesource.com/aom/+log/v3.8.1..v3.8.2 for all the + commits in this release. + + - Bug Fixes + * aomedia:3523: SIGFPE in av1_twopass_postencode_update() + pass2_strategy.c:4261. + * aomedia:3535, b/317646516: Over reads in aom_convolve_copy_neon(). + * aomedia:3543: invalid feature modifier when compiling + aom_dsp/arm/aom_convolve8_neon_i8mm.c on Debian 10 with arm64 + architecture. + * aomedia:3545: Failed to parse configurations due to inconsistent + elements between two arrays "av1_ctrl_args" and "av1_arg_ctrl_map" + in aomenc.c. + * oss-fuzz:66474, b/319140742: Integer-overflow in search_wiener. + * Zero initialize an array in cdef search. + 2024-01-17 v3.8.1 This release includes several bug fixes. This release is ABI compatible with the last release. See diff --git a/third_party/aom/CMakeLists.txt b/third_party/aom/CMakeLists.txt index a02b220bdb..00a7e2bca9 100644 --- a/third_party/aom/CMakeLists.txt +++ b/third_party/aom/CMakeLists.txt @@ -59,7 +59,7 @@ endif() # # We set SO_FILE_VERSION = [c-a].a.r set(LT_CURRENT 11) -set(LT_REVISION 1) +set(LT_REVISION 2) set(LT_AGE 8) math(EXPR SO_VERSION "${LT_CURRENT} - ${LT_AGE}") set(SO_FILE_VERSION "${SO_VERSION}.${LT_AGE}.${LT_REVISION}") @@ -374,6 +374,7 @@ file(WRITE "${AOM_GEN_SRC_DIR}/usage_exit.c" # if(ENABLE_EXAMPLES OR ENABLE_TESTS OR ENABLE_TOOLS) add_library(aom_common_app_util OBJECT ${AOM_COMMON_APP_UTIL_SOURCES}) + add_library(aom_usage_exit OBJECT "${AOM_GEN_SRC_DIR}/usage_exit.c") set_property(TARGET ${example} PROPERTY FOLDER examples) if(CONFIG_AV1_DECODER) add_library(aom_decoder_app_util OBJECT ${AOM_DECODER_APP_UTIL_SOURCES}) @@ -508,10 +509,10 @@ if(CONFIG_AV1_ENCODER) # aom_entropy_optimizer.c won't work on macos, but dragging in all the # helper machinery allows the link to succeed. add_executable(aom_entropy_optimizer - "${AOM_GEN_SRC_DIR}/usage_exit.c" "${AOM_ROOT}/tools/aom_entropy_optimizer.c" $ - $) + $ + $) # Maintain a list of encoder tool targets. list(APPEND AOM_ENCODER_TOOL_TARGETS aom_entropy_optimizer) @@ -661,12 +662,12 @@ endif() if(ENABLE_TOOLS) if(CONFIG_AV1_DECODER) - add_executable(dump_obu "${AOM_GEN_SRC_DIR}/usage_exit.c" - "${AOM_ROOT}/tools/dump_obu.cc" + add_executable(dump_obu "${AOM_ROOT}/tools/dump_obu.cc" "${AOM_ROOT}/tools/obu_parser.cc" "${AOM_ROOT}/tools/obu_parser.h" $ - $) + $ + $) list(APPEND AOM_TOOL_TARGETS dump_obu) list(APPEND AOM_APP_TARGETS dump_obu) @@ -825,7 +826,8 @@ if(BUILD_SHARED_LIBS) # Clang's AddressSanitizer documentation says "When linking shared libraries, # the AddressSanitizer run-time is not linked, so -Wl,-z,defs may cause link # errors (don't use it with AddressSanitizer)." See - # https://clang.llvm.org/docs/AddressSanitizer.html#usage. + # https://clang.llvm.org/docs/AddressSanitizer.html#usage. Similarly, see + # https://clang.llvm.org/docs/MemorySanitizer.html#usage. if(NOT WIN32 AND NOT APPLE AND NOT (CMAKE_C_COMPILER_ID MATCHES "Clang" AND SANITIZE)) @@ -843,12 +845,6 @@ if(BUILD_SHARED_LIBS) setup_exports_target() endif() -# Do not allow implicit vector type conversions on Clang builds (this is already -# the default on GCC builds). -if(CMAKE_C_COMPILER_ID MATCHES "Clang") - append_compiler_flag("-flax-vector-conversions=none") -endif() - # Handle user supplied compile and link flags last to ensure they're obeyed. set_user_flags() diff --git a/third_party/aom/README.md b/third_party/aom/README.md index 4e2eb2756c..f81e13e9bd 100644 --- a/third_party/aom/README.md +++ b/third_party/aom/README.md @@ -46,17 +46,23 @@ README.md {#LREADME} ### Prerequisites {#prerequisites} - 1. [CMake](https://cmake.org). See CMakeLists.txt for the minimum version - required. - 2. [Git](https://git-scm.com/). - 3. [Perl](https://www.perl.org/). - 4. For x86 targets, [yasm](http://yasm.tortall.net/), which is preferred, or a - recent version of [nasm](http://www.nasm.us/). If you download yasm with - the intention to work with Visual Studio, please download win32.exe or - win64.exe and rename it into yasm.exe. DO NOT download or use vsyasm.exe. - 5. Building the documentation requires +1. [CMake](https://cmake.org). See CMakeLists.txt for the minimum version + required. +2. [Git](https://git-scm.com/). +3. A modern C compiler. gcc 6+, clang 7+, Microsoft Visual Studio 2019+ or + the latest version of MinGW-w64 (clang64 or ucrt toolchains) are + recommended. A C++ compiler is necessary to build the unit tests and some + features contained in the examples. +4. [Perl](https://www.perl.org/). +5. For x86 targets, [yasm](http://yasm.tortall.net/) or a recent version (2.14 + or later) of [nasm](http://www.nasm.us/). (If both yasm and nasm are + present, yasm will be used by default. Pass -DENABLE_NASM=ON to cmake to + select nasm.) If you download yasm with the intention to work with Visual + Studio, please download win32.exe or win64.exe and rename it into yasm.exe. + DO NOT download or use vsyasm.exe. +6. Building the documentation requires [doxygen version 1.8.10 or newer](http://doxygen.org). - 6. Emscripten builds require the portable +7. Emscripten builds require the portable [EMSDK](https://kripken.github.io/emscripten-site/index.html). ### Get the code {#get-the-code} diff --git a/third_party/aom/aom/aom_encoder.h b/third_party/aom/aom/aom_encoder.h index 6a6254dafe..9bdadd6938 100644 --- a/third_party/aom/aom/aom_encoder.h +++ b/third_party/aom/aom/aom_encoder.h @@ -1044,6 +1044,11 @@ aom_fixed_buf_t *aom_codec_get_global_headers(aom_codec_ctx_t *ctx); * Interface is not an encoder interface. * \retval #AOM_CODEC_INVALID_PARAM * A parameter was NULL, the image format is unsupported, etc. + * + * \note + * `duration` is of the unsigned long type, which can be 32 or 64 bits. + * `duration` must be less than or equal to UINT32_MAX so that its range is + * independent of the size of unsigned long. */ aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, unsigned long duration, diff --git a/third_party/aom/aom/aomdx.h b/third_party/aom/aom/aomdx.h index 02ea19597c..2dd7bb3375 100644 --- a/third_party/aom/aom/aomdx.h +++ b/third_party/aom/aom/aomdx.h @@ -234,8 +234,11 @@ enum aom_dec_control_id { */ AV1D_GET_IMG_FORMAT, - /*!\brief Codec control function to get the size of the tile, unsigned int* - * parameter + /*!\brief Codec control function to get the width and height (in pixels) of + * the tiles in a tile list, unsigned int* parameter + * + * Tile width is in the high 16 bits of the output value, and tile height is + * in the low 16 bits of the output value. */ AV1D_GET_TILE_SIZE, diff --git a/third_party/aom/aom/src/aom_encoder.c b/third_party/aom/aom/src/aom_encoder.c index 70e0b75bcd..f188567b94 100644 --- a/third_party/aom/aom/src/aom_encoder.c +++ b/third_party/aom/aom/src/aom_encoder.c @@ -23,6 +23,7 @@ #endif #include +#include #include #include "aom/aom_encoder.h" @@ -178,6 +179,10 @@ aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img, else if (img && ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) != 0) != ((ctx->init_flags & AOM_CODEC_USE_HIGHBITDEPTH) != 0)) { res = AOM_CODEC_INVALID_PARAM; +#if ULONG_MAX > UINT32_MAX + } else if (duration > UINT32_MAX) { + res = AOM_CODEC_INVALID_PARAM; +#endif } else { /* Execute in a normalized floating point environment, if the platform * requires it. diff --git a/third_party/aom/aom/src/aom_image.c b/third_party/aom/aom/src/aom_image.c index 8e94d5dd4f..3b1c33d056 100644 --- a/third_party/aom/aom/src/aom_image.c +++ b/third_party/aom/aom/src/aom_image.c @@ -41,6 +41,8 @@ static aom_image_t *img_alloc_helper( if (img != NULL) memset(img, 0, sizeof(aom_image_t)); + if (fmt == AOM_IMG_FMT_NONE) goto fail; + /* Treat align==0 like align==1 */ if (!buf_align) buf_align = 1; diff --git a/third_party/aom/aom_dsp/aom_dsp.cmake b/third_party/aom/aom_dsp/aom_dsp.cmake index 653f690741..de987cbd23 100644 --- a/third_party/aom/aom_dsp/aom_dsp.cmake +++ b/third_party/aom/aom_dsp/aom_dsp.cmake @@ -52,15 +52,12 @@ list(APPEND AOM_DSP_COMMON_SOURCES list(APPEND AOM_DSP_COMMON_ASM_SSE2 "${AOM_ROOT}/aom_dsp/x86/aom_high_subpixel_8t_sse2.asm" "${AOM_ROOT}/aom_dsp/x86/aom_high_subpixel_bilinear_sse2.asm" - "${AOM_ROOT}/aom_dsp/x86/aom_subpixel_8t_sse2.asm" - "${AOM_ROOT}/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm" "${AOM_ROOT}/aom_dsp/x86/highbd_intrapred_asm_sse2.asm" "${AOM_ROOT}/aom_dsp/x86/intrapred_asm_sse2.asm" "${AOM_ROOT}/aom_dsp/x86/inv_wht_sse2.asm") list(APPEND AOM_DSP_COMMON_INTRIN_SSE2 "${AOM_ROOT}/aom_dsp/x86/aom_convolve_copy_sse2.c" - "${AOM_ROOT}/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c" "${AOM_ROOT}/aom_dsp/x86/aom_asm_stubs.c" "${AOM_ROOT}/aom_dsp/x86/convolve.h" "${AOM_ROOT}/aom_dsp/x86/convolve_sse2.h" @@ -145,6 +142,9 @@ if(CONFIG_AV1_HIGHBITDEPTH) "${AOM_ROOT}/aom_dsp/arm/highbd_convolve8_neon.c" "${AOM_ROOT}/aom_dsp/arm/highbd_intrapred_neon.c" "${AOM_ROOT}/aom_dsp/arm/highbd_loopfilter_neon.c") + + list(APPEND AOM_DSP_COMMON_INTRIN_SVE + "${AOM_ROOT}/aom_dsp/arm/highbd_convolve8_sve.c") endif() if(CONFIG_AV1_DECODER) @@ -200,7 +200,8 @@ if(CONFIG_AV1_ENCODER) "${AOM_ROOT}/aom_dsp/flow_estimation/x86/disflow_sse4.c") list(APPEND AOM_DSP_ENCODER_INTRIN_AVX2 - "${AOM_ROOT}/aom_dsp/flow_estimation/x86/corner_match_avx2.c") + "${AOM_ROOT}/aom_dsp/flow_estimation/x86/corner_match_avx2.c" + "${AOM_ROOT}/aom_dsp/flow_estimation/x86/disflow_avx2.c") list(APPEND AOM_DSP_ENCODER_INTRIN_NEON "${AOM_ROOT}/aom_dsp/flow_estimation/arm/disflow_neon.c") @@ -208,7 +209,6 @@ if(CONFIG_AV1_ENCODER) list(APPEND AOM_DSP_ENCODER_ASM_SSE2 "${AOM_ROOT}/aom_dsp/x86/sad4d_sse2.asm" "${AOM_ROOT}/aom_dsp/x86/sad_sse2.asm" - "${AOM_ROOT}/aom_dsp/x86/subpel_variance_sse2.asm" "${AOM_ROOT}/aom_dsp/x86/subtract_sse2.asm") list(APPEND AOM_DSP_ENCODER_ASM_SSE2_X86_64 @@ -227,6 +227,9 @@ if(CONFIG_AV1_ENCODER) "${AOM_ROOT}/aom_dsp/x86/variance_sse2.c" "${AOM_ROOT}/aom_dsp/x86/jnt_sad_sse2.c") + list(APPEND AOM_DSP_ENCODER_ASM_SSSE3 + "${AOM_ROOT}/aom_dsp/x86/subpel_variance_ssse3.asm") + list(APPEND AOM_DSP_ENCODER_ASM_SSSE3_X86_64 "${AOM_ROOT}/aom_dsp/x86/fwd_txfm_ssse3_x86_64.asm" "${AOM_ROOT}/aom_dsp/x86/quantize_ssse3_x86_64.asm") @@ -493,6 +496,8 @@ function(setup_aom_dsp_targets) endif() if(HAVE_SVE) + add_intrinsics_object_library("${AOM_SVE_FLAG}" "sve" "aom_dsp_common" + "AOM_DSP_COMMON_INTRIN_SVE") if(CONFIG_AV1_ENCODER) add_intrinsics_object_library("${AOM_SVE_FLAG}" "sve" "aom_dsp_encoder" "AOM_DSP_ENCODER_INTRIN_SVE") diff --git a/third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl b/third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl index 7bb156ac59..7e746e9cb9 100755 --- a/third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl +++ b/third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl @@ -498,8 +498,8 @@ add_proto qw/void aom_convolve8_horiz/, "const uint8_t *src, ptrdiff_t add_proto qw/void aom_convolve8_vert/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int x_step_q4, const int16_t *filter_y, int y_step_q4, int w, int h"; specialize qw/aom_convolve_copy neon sse2 avx2/; -specialize qw/aom_convolve8_horiz neon neon_dotprod neon_i8mm sse2 ssse3/, "$avx2_ssse3"; -specialize qw/aom_convolve8_vert neon neon_dotprod neon_i8mm sse2 ssse3/, "$avx2_ssse3"; +specialize qw/aom_convolve8_horiz neon neon_dotprod neon_i8mm ssse3/, "$avx2_ssse3"; +specialize qw/aom_convolve8_vert neon neon_dotprod neon_i8mm ssse3/, "$avx2_ssse3"; add_proto qw/void aom_scaled_2d/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const InterpKernel *filter, int x0_q4, int x_step_q4, int y0_q4, int y_step_q4, int w, int h"; specialize qw/aom_scaled_2d ssse3 neon/; @@ -509,10 +509,10 @@ if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") { specialize qw/aom_highbd_convolve_copy sse2 avx2 neon/; add_proto qw/void aom_highbd_convolve8_horiz/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int x_step_q4, const int16_t *filter_y, int y_step_q4, int w, int h, int bd"; - specialize qw/aom_highbd_convolve8_horiz sse2 avx2 neon/; + specialize qw/aom_highbd_convolve8_horiz sse2 avx2 neon sve/; add_proto qw/void aom_highbd_convolve8_vert/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int x_step_q4, const int16_t *filter_y, int y_step_q4, int w, int h, int bd"; - specialize qw/aom_highbd_convolve8_vert sse2 avx2 neon/; + specialize qw/aom_highbd_convolve8_vert sse2 avx2 neon sve/; } # @@ -1087,7 +1087,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_sad_skip_16x32x4d avx2 sse2 neon neon_dotprod/; specialize qw/aom_sad_skip_16x16x4d avx2 sse2 neon neon_dotprod/; specialize qw/aom_sad_skip_16x8x4d avx2 sse2 neon neon_dotprod/; - specialize qw/aom_sad_skip_16x4x4d neon neon_dotprod/; + specialize qw/aom_sad_skip_16x4x4d avx2 neon neon_dotprod/; specialize qw/aom_sad_skip_8x32x4d sse2 neon/; specialize qw/aom_sad_skip_8x16x4d sse2 neon/; specialize qw/aom_sad_skip_8x8x4d sse2 neon/; @@ -1116,7 +1116,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_sad64x16x3d avx2 neon neon_dotprod/; specialize qw/aom_sad32x8x3d avx2 neon neon_dotprod/; specialize qw/aom_sad16x64x3d avx2 neon neon_dotprod/; - specialize qw/aom_sad16x4x3d neon neon_dotprod/; + specialize qw/aom_sad16x4x3d avx2 neon neon_dotprod/; specialize qw/aom_sad8x32x3d neon/; specialize qw/aom_sad4x16x3d neon/; @@ -1264,8 +1264,6 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/int aom_vector_var/, "const int16_t *ref, const int16_t *src, int bwl"; specialize qw/aom_vector_var avx2 sse4_1 neon sve/; - # TODO(kyslov@) bring back SSE2 by extending it to 128 block size - #specialize qw/aom_vector_var neon sse2/; # # hamadard transform and satd for implmenting temporal dependency model @@ -1357,6 +1355,11 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize "aom_highbd_${bd}_mse16x8", qw/neon neon_dotprod/; specialize "aom_highbd_${bd}_mse8x16", qw/neon neon_dotprod/; specialize "aom_highbd_${bd}_mse8x8", qw/sse2 neon neon_dotprod/; + } elsif ($bd eq 10) { + specialize "aom_highbd_${bd}_mse16x16", qw/avx2 sse2 neon sve/; + specialize "aom_highbd_${bd}_mse16x8", qw/neon sve/; + specialize "aom_highbd_${bd}_mse8x16", qw/neon sve/; + specialize "aom_highbd_${bd}_mse8x8", qw/sse2 neon sve/; } else { specialize "aom_highbd_${bd}_mse16x16", qw/sse2 neon sve/; specialize "aom_highbd_${bd}_mse16x8", qw/neon sve/; @@ -1406,39 +1409,39 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_variance4x8 sse2 neon neon_dotprod/; specialize qw/aom_variance4x4 sse2 neon neon_dotprod/; - specialize qw/aom_sub_pixel_variance128x128 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance128x64 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance64x128 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance64x64 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance64x32 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance32x64 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance32x32 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance32x16 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x32 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x16 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x8 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance8x16 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance8x8 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance8x4 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance4x8 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance4x4 neon sse2 ssse3/; - - specialize qw/aom_sub_pixel_avg_variance128x128 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance128x64 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance64x128 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance64x64 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance64x32 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance32x64 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance32x32 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance32x16 avx2 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance16x32 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance16x16 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance16x8 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance8x16 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance8x8 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance8x4 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance4x8 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance4x4 neon sse2 ssse3/; + specialize qw/aom_sub_pixel_variance128x128 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance128x64 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance64x128 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance64x64 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance64x32 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance32x64 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance32x32 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance32x16 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance16x32 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance16x16 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance16x8 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_variance8x16 neon ssse3/; + specialize qw/aom_sub_pixel_variance8x8 neon ssse3/; + specialize qw/aom_sub_pixel_variance8x4 neon ssse3/; + specialize qw/aom_sub_pixel_variance4x8 neon ssse3/; + specialize qw/aom_sub_pixel_variance4x4 neon ssse3/; + + specialize qw/aom_sub_pixel_avg_variance128x128 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance128x64 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance64x128 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance64x64 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance64x32 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance32x64 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance32x32 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance32x16 avx2 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance16x32 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance16x16 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance16x8 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance8x16 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance8x8 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance8x4 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance4x8 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance4x4 neon ssse3/; if (aom_config("CONFIG_REALTIME_ONLY") ne "yes") { specialize qw/aom_variance4x16 neon neon_dotprod sse2/; @@ -1448,18 +1451,18 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_variance16x64 neon neon_dotprod sse2 avx2/; specialize qw/aom_variance64x16 neon neon_dotprod sse2 avx2/; - specialize qw/aom_sub_pixel_variance4x16 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x4 neon avx2 sse2 ssse3/; - specialize qw/aom_sub_pixel_variance8x32 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance32x8 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x64 neon avx2 sse2 ssse3/; - specialize qw/aom_sub_pixel_variance64x16 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance4x16 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance16x4 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance8x32 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance32x8 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance16x64 neon sse2 ssse3/; - specialize qw/aom_sub_pixel_avg_variance64x16 neon sse2 ssse3/; + specialize qw/aom_sub_pixel_variance4x16 neon ssse3/; + specialize qw/aom_sub_pixel_variance16x4 neon avx2 ssse3/; + specialize qw/aom_sub_pixel_variance8x32 neon ssse3/; + specialize qw/aom_sub_pixel_variance32x8 neon ssse3/; + specialize qw/aom_sub_pixel_variance16x64 neon avx2 ssse3/; + specialize qw/aom_sub_pixel_variance64x16 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance4x16 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance16x4 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance8x32 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance32x8 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance16x64 neon ssse3/; + specialize qw/aom_sub_pixel_avg_variance64x16 neon ssse3/; specialize qw/aom_dist_wtd_sub_pixel_avg_variance4x16 neon ssse3/; specialize qw/aom_dist_wtd_sub_pixel_avg_variance16x4 neon ssse3/; @@ -1789,11 +1792,14 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { # Flow estimation library if (aom_config("CONFIG_REALTIME_ONLY") ne "yes") { - add_proto qw/double av1_compute_cross_correlation/, "const unsigned char *frame1, int stride1, int x1, int y1, const unsigned char *frame2, int stride2, int x2, int y2"; - specialize qw/av1_compute_cross_correlation sse4_1 avx2/; + add_proto qw/bool aom_compute_mean_stddev/, "const unsigned char *frame, int stride, int x, int y, double *mean, double *one_over_stddev"; + specialize qw/aom_compute_mean_stddev sse4_1 avx2/; + + add_proto qw/double aom_compute_correlation/, "const unsigned char *frame1, int stride1, int x1, int y1, double mean1, double one_over_stddev1, const unsigned char *frame2, int stride2, int x2, int y2, double mean2, double one_over_stddev2"; + specialize qw/aom_compute_correlation sse4_1 avx2/; add_proto qw/void aom_compute_flow_at_point/, "const uint8_t *src, const uint8_t *ref, int x, int y, int width, int height, int stride, double *u, double *v"; - specialize qw/aom_compute_flow_at_point sse4_1 neon/; + specialize qw/aom_compute_flow_at_point sse4_1 avx2 neon/; } } # CONFIG_AV1_ENCODER diff --git a/third_party/aom/aom_dsp/arm/aom_convolve8_neon_dotprod.c b/third_party/aom/aom_dsp/arm/aom_convolve8_neon_dotprod.c index ac0a6efd00..c82125ba17 100644 --- a/third_party/aom/aom_dsp/arm/aom_convolve8_neon_dotprod.c +++ b/third_party/aom/aom_dsp/arm/aom_convolve8_neon_dotprod.c @@ -267,8 +267,6 @@ void aom_convolve8_vert_neon_dotprod(const uint8_t *src, ptrdiff_t src_stride, const int32x4_t correction = vdupq_n_s32((int32_t)vaddvq_s16(correct_tmp)); const uint8x8_t range_limit = vdup_n_u8(128); const uint8x16x3_t merge_block_tbl = vld1q_u8_x3(dot_prod_merge_block_tbl); - uint8x8_t t0, t1, t2, t3, t4, t5, t6; - int8x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10; int8x16x2_t samples_LUT; assert((intptr_t)dst % 4 == 0); @@ -282,46 +280,39 @@ void aom_convolve8_vert_neon_dotprod(const uint8_t *src, ptrdiff_t src_stride, if (w == 4) { const uint8x16_t tran_concat_tbl = vld1q_u8(dot_prod_tran_concat_tbl); - int8x16_t s0123, s1234, s2345, s3456, s4567, s5678, s6789, s78910; - int16x4_t d0, d1, d2, d3; - uint8x8_t d01, d23; + uint8x8_t t0, t1, t2, t3, t4, t5, t6; load_u8_8x7(src, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6); src += 7 * src_stride; /* Clamp sample range to [-128, 127] for 8-bit signed dot product. */ - s0 = vreinterpret_s8_u8(vsub_u8(t0, range_limit)); - s1 = vreinterpret_s8_u8(vsub_u8(t1, range_limit)); - s2 = vreinterpret_s8_u8(vsub_u8(t2, range_limit)); - s3 = vreinterpret_s8_u8(vsub_u8(t3, range_limit)); - s4 = vreinterpret_s8_u8(vsub_u8(t4, range_limit)); - s5 = vreinterpret_s8_u8(vsub_u8(t5, range_limit)); - s6 = vreinterpret_s8_u8(vsub_u8(t6, range_limit)); - s7 = vdup_n_s8(0); - s8 = vdup_n_s8(0); - s9 = vdup_n_s8(0); + int8x8_t s0 = vreinterpret_s8_u8(vsub_u8(t0, range_limit)); + int8x8_t s1 = vreinterpret_s8_u8(vsub_u8(t1, range_limit)); + int8x8_t s2 = vreinterpret_s8_u8(vsub_u8(t2, range_limit)); + int8x8_t s3 = vreinterpret_s8_u8(vsub_u8(t3, range_limit)); + int8x8_t s4 = vreinterpret_s8_u8(vsub_u8(t4, range_limit)); + int8x8_t s5 = vreinterpret_s8_u8(vsub_u8(t5, range_limit)); + int8x8_t s6 = vreinterpret_s8_u8(vsub_u8(t6, range_limit)); /* This operation combines a conventional transpose and the sample permute * (see horizontal case) required before computing the dot product. */ + int8x16_t s0123, s1234, s2345, s3456; transpose_concat_4x4(s0, s1, s2, s3, &s0123, tran_concat_tbl); transpose_concat_4x4(s1, s2, s3, s4, &s1234, tran_concat_tbl); transpose_concat_4x4(s2, s3, s4, s5, &s2345, tran_concat_tbl); transpose_concat_4x4(s3, s4, s5, s6, &s3456, tran_concat_tbl); - transpose_concat_4x4(s4, s5, s6, s7, &s4567, tran_concat_tbl); - transpose_concat_4x4(s5, s6, s7, s8, &s5678, tran_concat_tbl); - transpose_concat_4x4(s6, s7, s8, s9, &s6789, tran_concat_tbl); do { uint8x8_t t7, t8, t9, t10; - load_u8_8x4(src, src_stride, &t7, &t8, &t9, &t10); - s7 = vreinterpret_s8_u8(vsub_u8(t7, range_limit)); - s8 = vreinterpret_s8_u8(vsub_u8(t8, range_limit)); - s9 = vreinterpret_s8_u8(vsub_u8(t9, range_limit)); - s10 = vreinterpret_s8_u8(vsub_u8(t10, range_limit)); + int8x8_t s7 = vreinterpret_s8_u8(vsub_u8(t7, range_limit)); + int8x8_t s8 = vreinterpret_s8_u8(vsub_u8(t8, range_limit)); + int8x8_t s9 = vreinterpret_s8_u8(vsub_u8(t9, range_limit)); + int8x8_t s10 = vreinterpret_s8_u8(vsub_u8(t10, range_limit)); + int8x16_t s4567, s5678, s6789, s78910; transpose_concat_4x4(s7, s8, s9, s10, &s78910, tran_concat_tbl); /* Merge new data into block from previous iteration. */ @@ -331,12 +322,13 @@ void aom_convolve8_vert_neon_dotprod(const uint8_t *src, ptrdiff_t src_stride, s5678 = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[1]); s6789 = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[2]); - d0 = convolve8_4_sdot_partial(s0123, s4567, correction, filter); - d1 = convolve8_4_sdot_partial(s1234, s5678, correction, filter); - d2 = convolve8_4_sdot_partial(s2345, s6789, correction, filter); - d3 = convolve8_4_sdot_partial(s3456, s78910, correction, filter); - d01 = vqrshrun_n_s16(vcombine_s16(d0, d1), FILTER_BITS); - d23 = vqrshrun_n_s16(vcombine_s16(d2, d3), FILTER_BITS); + int16x4_t d0 = convolve8_4_sdot_partial(s0123, s4567, correction, filter); + int16x4_t d1 = convolve8_4_sdot_partial(s1234, s5678, correction, filter); + int16x4_t d2 = convolve8_4_sdot_partial(s2345, s6789, correction, filter); + int16x4_t d3 = + convolve8_4_sdot_partial(s3456, s78910, correction, filter); + uint8x8_t d01 = vqrshrun_n_s16(vcombine_s16(d0, d1), FILTER_BITS); + uint8x8_t d23 = vqrshrun_n_s16(vcombine_s16(d2, d3), FILTER_BITS); store_u8x4_strided_x2(dst + 0 * dst_stride, dst_stride, d01); store_u8x4_strided_x2(dst + 2 * dst_stride, dst_stride, d23); @@ -354,37 +346,30 @@ void aom_convolve8_vert_neon_dotprod(const uint8_t *src, ptrdiff_t src_stride, } while (h != 0); } else { const uint8x16x2_t tran_concat_tbl = vld1q_u8_x2(dot_prod_tran_concat_tbl); - int8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, - s3456_lo, s3456_hi, s4567_lo, s4567_hi, s5678_lo, s5678_hi, s6789_lo, - s6789_hi, s78910_lo, s78910_hi; - uint8x8_t d0, d1, d2, d3; - const uint8_t *s; - uint8_t *d; - int height; do { - height = h; - s = src; - d = dst; + int height = h; + const uint8_t *s = src; + uint8_t *d = dst; + uint8x8_t t0, t1, t2, t3, t4, t5, t6; load_u8_8x7(s, src_stride, &t0, &t1, &t2, &t3, &t4, &t5, &t6); s += 7 * src_stride; /* Clamp sample range to [-128, 127] for 8-bit signed dot product. */ - s0 = vreinterpret_s8_u8(vsub_u8(t0, range_limit)); - s1 = vreinterpret_s8_u8(vsub_u8(t1, range_limit)); - s2 = vreinterpret_s8_u8(vsub_u8(t2, range_limit)); - s3 = vreinterpret_s8_u8(vsub_u8(t3, range_limit)); - s4 = vreinterpret_s8_u8(vsub_u8(t4, range_limit)); - s5 = vreinterpret_s8_u8(vsub_u8(t5, range_limit)); - s6 = vreinterpret_s8_u8(vsub_u8(t6, range_limit)); - s7 = vdup_n_s8(0); - s8 = vdup_n_s8(0); - s9 = vdup_n_s8(0); + int8x8_t s0 = vreinterpret_s8_u8(vsub_u8(t0, range_limit)); + int8x8_t s1 = vreinterpret_s8_u8(vsub_u8(t1, range_limit)); + int8x8_t s2 = vreinterpret_s8_u8(vsub_u8(t2, range_limit)); + int8x8_t s3 = vreinterpret_s8_u8(vsub_u8(t3, range_limit)); + int8x8_t s4 = vreinterpret_s8_u8(vsub_u8(t4, range_limit)); + int8x8_t s5 = vreinterpret_s8_u8(vsub_u8(t5, range_limit)); + int8x8_t s6 = vreinterpret_s8_u8(vsub_u8(t6, range_limit)); /* This operation combines a conventional transpose and the sample permute * (see horizontal case) required before computing the dot product. */ + int8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, + s3456_lo, s3456_hi; transpose_concat_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi, tran_concat_tbl); transpose_concat_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi, @@ -393,23 +378,18 @@ void aom_convolve8_vert_neon_dotprod(const uint8_t *src, ptrdiff_t src_stride, tran_concat_tbl); transpose_concat_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi, tran_concat_tbl); - transpose_concat_8x4(s4, s5, s6, s7, &s4567_lo, &s4567_hi, - tran_concat_tbl); - transpose_concat_8x4(s5, s6, s7, s8, &s5678_lo, &s5678_hi, - tran_concat_tbl); - transpose_concat_8x4(s6, s7, s8, s9, &s6789_lo, &s6789_hi, - tran_concat_tbl); do { uint8x8_t t7, t8, t9, t10; - load_u8_8x4(s, src_stride, &t7, &t8, &t9, &t10); - s7 = vreinterpret_s8_u8(vsub_u8(t7, range_limit)); - s8 = vreinterpret_s8_u8(vsub_u8(t8, range_limit)); - s9 = vreinterpret_s8_u8(vsub_u8(t9, range_limit)); - s10 = vreinterpret_s8_u8(vsub_u8(t10, range_limit)); + int8x8_t s7 = vreinterpret_s8_u8(vsub_u8(t7, range_limit)); + int8x8_t s8 = vreinterpret_s8_u8(vsub_u8(t8, range_limit)); + int8x8_t s9 = vreinterpret_s8_u8(vsub_u8(t9, range_limit)); + int8x8_t s10 = vreinterpret_s8_u8(vsub_u8(t10, range_limit)); + int8x16_t s4567_lo, s4567_hi, s5678_lo, s5678_hi, s6789_lo, s6789_hi, + s78910_lo, s78910_hi; transpose_concat_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi, tran_concat_tbl); @@ -426,14 +406,14 @@ void aom_convolve8_vert_neon_dotprod(const uint8_t *src, ptrdiff_t src_stride, s5678_hi = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[1]); s6789_hi = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[2]); - d0 = convolve8_8_sdot_partial(s0123_lo, s4567_lo, s0123_hi, s4567_hi, - correction, filter); - d1 = convolve8_8_sdot_partial(s1234_lo, s5678_lo, s1234_hi, s5678_hi, - correction, filter); - d2 = convolve8_8_sdot_partial(s2345_lo, s6789_lo, s2345_hi, s6789_hi, - correction, filter); - d3 = convolve8_8_sdot_partial(s3456_lo, s78910_lo, s3456_hi, s78910_hi, - correction, filter); + uint8x8_t d0 = convolve8_8_sdot_partial(s0123_lo, s4567_lo, s0123_hi, + s4567_hi, correction, filter); + uint8x8_t d1 = convolve8_8_sdot_partial(s1234_lo, s5678_lo, s1234_hi, + s5678_hi, correction, filter); + uint8x8_t d2 = convolve8_8_sdot_partial(s2345_lo, s6789_lo, s2345_hi, + s6789_hi, correction, filter); + uint8x8_t d3 = convolve8_8_sdot_partial(s3456_lo, s78910_lo, s3456_hi, + s78910_hi, correction, filter); store_u8_8x4(d, dst_stride, d0, d1, d2, d3); diff --git a/third_party/aom/aom_dsp/arm/aom_convolve8_neon_i8mm.c b/third_party/aom/aom_dsp/arm/aom_convolve8_neon_i8mm.c index c314c0a192..df6e4d2ab5 100644 --- a/third_party/aom/aom_dsp/arm/aom_convolve8_neon_i8mm.c +++ b/third_party/aom/aom_dsp/arm/aom_convolve8_neon_i8mm.c @@ -15,7 +15,6 @@ #include #include "config/aom_config.h" -#include "config/aom_dsp_rtcd.h" #include "aom/aom_integer.h" #include "aom_dsp/aom_dsp_common.h" @@ -246,7 +245,6 @@ void aom_convolve8_vert_neon_i8mm(const uint8_t *src, ptrdiff_t src_stride, int h) { const int8x8_t filter = vmovn_s16(vld1q_s16(filter_y)); const uint8x16x3_t merge_block_tbl = vld1q_u8_x3(dot_prod_merge_block_tbl); - uint8x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10; uint8x16x2_t samples_LUT; assert((intptr_t)dst % 4 == 0); @@ -260,31 +258,25 @@ void aom_convolve8_vert_neon_i8mm(const uint8_t *src, ptrdiff_t src_stride, if (w == 4) { const uint8x16_t tran_concat_tbl = vld1q_u8(dot_prod_tran_concat_tbl); - uint8x16_t s0123, s1234, s2345, s3456, s4567, s5678, s6789, s78910; - int16x4_t d0, d1, d2, d3; - uint8x8_t d01, d23; + uint8x8_t s0, s1, s2, s3, s4, s5, s6; load_u8_8x7(src, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); src += 7 * src_stride; - s7 = vdup_n_u8(0); - s8 = vdup_n_u8(0); - s9 = vdup_n_u8(0); - /* This operation combines a conventional transpose and the sample permute * (see horizontal case) required before computing the dot product. */ + uint8x16_t s0123, s1234, s2345, s3456; transpose_concat_4x4(s0, s1, s2, s3, &s0123, tran_concat_tbl); transpose_concat_4x4(s1, s2, s3, s4, &s1234, tran_concat_tbl); transpose_concat_4x4(s2, s3, s4, s5, &s2345, tran_concat_tbl); transpose_concat_4x4(s3, s4, s5, s6, &s3456, tran_concat_tbl); - transpose_concat_4x4(s4, s5, s6, s7, &s4567, tran_concat_tbl); - transpose_concat_4x4(s5, s6, s7, s8, &s5678, tran_concat_tbl); - transpose_concat_4x4(s6, s7, s8, s9, &s6789, tran_concat_tbl); do { + uint8x8_t s7, s8, s9, s10; load_u8_8x4(src, src_stride, &s7, &s8, &s9, &s10); + uint8x16_t s4567, s5678, s6789, s78910; transpose_concat_4x4(s7, s8, s9, s10, &s78910, tran_concat_tbl); /* Merge new data into block from previous iteration. */ @@ -294,12 +286,12 @@ void aom_convolve8_vert_neon_i8mm(const uint8_t *src, ptrdiff_t src_stride, s5678 = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[1]); s6789 = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[2]); - d0 = convolve8_4_usdot_partial(s0123, s4567, filter); - d1 = convolve8_4_usdot_partial(s1234, s5678, filter); - d2 = convolve8_4_usdot_partial(s2345, s6789, filter); - d3 = convolve8_4_usdot_partial(s3456, s78910, filter); - d01 = vqrshrun_n_s16(vcombine_s16(d0, d1), FILTER_BITS); - d23 = vqrshrun_n_s16(vcombine_s16(d2, d3), FILTER_BITS); + int16x4_t d0 = convolve8_4_usdot_partial(s0123, s4567, filter); + int16x4_t d1 = convolve8_4_usdot_partial(s1234, s5678, filter); + int16x4_t d2 = convolve8_4_usdot_partial(s2345, s6789, filter); + int16x4_t d3 = convolve8_4_usdot_partial(s3456, s78910, filter); + uint8x8_t d01 = vqrshrun_n_s16(vcombine_s16(d0, d1), FILTER_BITS); + uint8x8_t d23 = vqrshrun_n_s16(vcombine_s16(d2, d3), FILTER_BITS); store_u8x4_strided_x2(dst + 0 * dst_stride, dst_stride, d01); store_u8x4_strided_x2(dst + 2 * dst_stride, dst_stride, d23); @@ -317,29 +309,21 @@ void aom_convolve8_vert_neon_i8mm(const uint8_t *src, ptrdiff_t src_stride, } while (h != 0); } else { const uint8x16x2_t tran_concat_tbl = vld1q_u8_x2(dot_prod_tran_concat_tbl); - uint8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, - s3456_lo, s3456_hi, s4567_lo, s4567_hi, s5678_lo, s5678_hi, s6789_lo, - s6789_hi, s78910_lo, s78910_hi; - uint8x8_t d0, d1, d2, d3; - const uint8_t *s; - uint8_t *d; - int height; do { - height = h; - s = src; - d = dst; + int height = h; + const uint8_t *s = src; + uint8_t *d = dst; + uint8x8_t s0, s1, s2, s3, s4, s5, s6; load_u8_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); s += 7 * src_stride; - s7 = vdup_n_u8(0); - s8 = vdup_n_u8(0); - s9 = vdup_n_u8(0); - /* This operation combines a conventional transpose and the sample permute * (see horizontal case) required before computing the dot product. */ + uint8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, + s3456_lo, s3456_hi; transpose_concat_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi, tran_concat_tbl); transpose_concat_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi, @@ -348,16 +332,13 @@ void aom_convolve8_vert_neon_i8mm(const uint8_t *src, ptrdiff_t src_stride, tran_concat_tbl); transpose_concat_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi, tran_concat_tbl); - transpose_concat_8x4(s4, s5, s6, s7, &s4567_lo, &s4567_hi, - tran_concat_tbl); - transpose_concat_8x4(s5, s6, s7, s8, &s5678_lo, &s5678_hi, - tran_concat_tbl); - transpose_concat_8x4(s6, s7, s8, s9, &s6789_lo, &s6789_hi, - tran_concat_tbl); do { + uint8x8_t s7, s8, s9, s10; load_u8_8x4(s, src_stride, &s7, &s8, &s9, &s10); + uint8x16_t s4567_lo, s4567_hi, s5678_lo, s5678_hi, s6789_lo, s6789_hi, + s78910_lo, s78910_hi; transpose_concat_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi, tran_concat_tbl); @@ -374,14 +355,14 @@ void aom_convolve8_vert_neon_i8mm(const uint8_t *src, ptrdiff_t src_stride, s5678_hi = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[1]); s6789_hi = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[2]); - d0 = convolve8_8_usdot_partial(s0123_lo, s4567_lo, s0123_hi, s4567_hi, - filter); - d1 = convolve8_8_usdot_partial(s1234_lo, s5678_lo, s1234_hi, s5678_hi, - filter); - d2 = convolve8_8_usdot_partial(s2345_lo, s6789_lo, s2345_hi, s6789_hi, - filter); - d3 = convolve8_8_usdot_partial(s3456_lo, s78910_lo, s3456_hi, s78910_hi, - filter); + uint8x8_t d0 = convolve8_8_usdot_partial(s0123_lo, s4567_lo, s0123_hi, + s4567_hi, filter); + uint8x8_t d1 = convolve8_8_usdot_partial(s1234_lo, s5678_lo, s1234_hi, + s5678_hi, filter); + uint8x8_t d2 = convolve8_8_usdot_partial(s2345_lo, s6789_lo, s2345_hi, + s6789_hi, filter); + uint8x8_t d3 = convolve8_8_usdot_partial(s3456_lo, s78910_lo, s3456_hi, + s78910_hi, filter); store_u8_8x4(d, dst_stride, d0, d1, d2, d3); diff --git a/third_party/aom/aom_dsp/arm/aom_filter.h b/third_party/aom/aom_dsp/arm/aom_filter.h new file mode 100644 index 0000000000..9972d064fc --- /dev/null +++ b/third_party/aom/aom_dsp/arm/aom_filter.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#ifndef AOM_AOM_DSP_ARM_AOM_FILTER_H_ +#define AOM_AOM_DSP_ARM_AOM_FILTER_H_ + +#include + +#include "config/aom_config.h" +#include "config/aom_dsp_rtcd.h" + +static INLINE int get_filter_taps_convolve8(const int16_t *filter) { + if (filter[0] | filter[7]) { + return 8; + } + if (filter[1] | filter[6]) { + return 6; + } + if (filter[2] | filter[5]) { + return 4; + } + return 2; +} + +#endif // AOM_AOM_DSP_ARM_AOM_FILTER_H_ diff --git a/third_party/aom/aom_dsp/arm/aom_neon_sve2_bridge.h b/third_party/aom/aom_dsp/arm/aom_neon_sve2_bridge.h new file mode 100644 index 0000000000..6e7d2d6365 --- /dev/null +++ b/third_party/aom/aom_dsp/arm/aom_neon_sve2_bridge.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef AOM_AOM_DSP_ARM_AOM_NEON_SVE2_BRIDGE_H_ +#define AOM_AOM_DSP_ARM_AOM_NEON_SVE2_BRIDGE_H_ + +#include + +#include "config/aom_dsp_rtcd.h" +#include "config/aom_config.h" + +// We can access instructions exclusive to the SVE2 instruction set from a +// predominantly Neon context by making use of the Neon-SVE bridge intrinsics +// to reinterpret Neon vectors as SVE vectors - with the high part of the SVE +// vector (if it's longer than 128 bits) being "don't care". + +// While sub-optimal on machines that have SVE vector length > 128-bit - as the +// remainder of the vector is unused - this approach is still beneficial when +// compared to a Neon-only solution. + +static INLINE int16x8_t aom_tbl2_s16(int16x8_t s0, int16x8_t s1, + uint16x8_t tbl) { + svint16x2_t samples = svcreate2_s16(svset_neonq_s16(svundef_s16(), s0), + svset_neonq_s16(svundef_s16(), s1)); + return svget_neonq_s16( + svtbl2_s16(samples, svset_neonq_u16(svundef_u16(), tbl))); +} + +#endif // AOM_AOM_DSP_ARM_AOM_NEON_SVE2_BRIDGE_H_ diff --git a/third_party/aom/aom_dsp/arm/aom_neon_sve_bridge.h b/third_party/aom/aom_dsp/arm/aom_neon_sve_bridge.h new file mode 100644 index 0000000000..3da80e22ba --- /dev/null +++ b/third_party/aom/aom_dsp/arm/aom_neon_sve_bridge.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023, Alliance for Open Media. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef AOM_AOM_DSP_ARM_AOM_NEON_SVE_BRIDGE_H_ +#define AOM_AOM_DSP_ARM_AOM_NEON_SVE_BRIDGE_H_ + +#include + +#include "config/aom_dsp_rtcd.h" +#include "config/aom_config.h" + +// We can access instructions exclusive to the SVE instruction set from a +// predominantly Neon context by making use of the Neon-SVE bridge intrinsics +// to reinterpret Neon vectors as SVE vectors - with the high part of the SVE +// vector (if it's longer than 128 bits) being "don't care". + +// While sub-optimal on machines that have SVE vector length > 128-bit - as the +// remainder of the vector is unused - this approach is still beneficial when +// compared to a Neon-only solution. + +static INLINE uint64x2_t aom_udotq_u16(uint64x2_t acc, uint16x8_t x, + uint16x8_t y) { + return svget_neonq_u64(svdot_u64(svset_neonq_u64(svundef_u64(), acc), + svset_neonq_u16(svundef_u16(), x), + svset_neonq_u16(svundef_u16(), y))); +} + +static INLINE int64x2_t aom_sdotq_s16(int64x2_t acc, int16x8_t x, int16x8_t y) { + return svget_neonq_s64(svdot_s64(svset_neonq_s64(svundef_s64(), acc), + svset_neonq_s16(svundef_s16(), x), + svset_neonq_s16(svundef_s16(), y))); +} + +#define aom_svdot_lane_s16(sum, s0, f, lane) \ + svget_neonq_s64(svdot_lane_s64(svset_neonq_s64(svundef_s64(), sum), \ + svset_neonq_s16(svundef_s16(), s0), \ + svset_neonq_s16(svundef_s16(), f), lane)) + +static INLINE uint16x8_t aom_tbl_u16(uint16x8_t s, uint16x8_t tbl) { + return svget_neonq_u16(svtbl_u16(svset_neonq_u16(svundef_u16(), s), + svset_neonq_u16(svundef_u16(), tbl))); +} + +static INLINE int16x8_t aom_tbl_s16(int16x8_t s, uint16x8_t tbl) { + return svget_neonq_s16(svtbl_s16(svset_neonq_s16(svundef_s16(), s), + svset_neonq_u16(svundef_u16(), tbl))); +} + +#endif // AOM_AOM_DSP_ARM_AOM_NEON_SVE_BRIDGE_H_ diff --git a/third_party/aom/aom_dsp/arm/avg_sve.c b/third_party/aom/aom_dsp/arm/avg_sve.c index bbf5a9447c..57a546501a 100644 --- a/third_party/aom/aom_dsp/arm/avg_sve.c +++ b/third_party/aom/aom_dsp/arm/avg_sve.c @@ -14,7 +14,7 @@ #include "config/aom_config.h" #include "config/aom_dsp_rtcd.h" #include "aom/aom_integer.h" -#include "aom_dsp/arm/dot_sve.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" #include "aom_dsp/arm/mem_neon.h" #include "aom_ports/mem.h" diff --git a/third_party/aom/aom_dsp/arm/blk_sse_sum_sve.c b/third_party/aom/aom_dsp/arm/blk_sse_sum_sve.c index 18bdc5dbfe..f538346d8b 100644 --- a/third_party/aom/aom_dsp/arm/blk_sse_sum_sve.c +++ b/third_party/aom/aom_dsp/arm/blk_sse_sum_sve.c @@ -15,7 +15,7 @@ #include "config/aom_dsp_rtcd.h" #include "config/aom_config.h" -#include "aom_dsp/arm/dot_sve.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" #include "aom_dsp/arm/mem_neon.h" static INLINE void get_blk_sse_sum_4xh_sve(const int16_t *data, int stride, diff --git a/third_party/aom/aom_dsp/arm/dot_sve.h b/third_party/aom/aom_dsp/arm/dot_sve.h deleted file mode 100644 index cf49f23606..0000000000 --- a/third_party/aom/aom_dsp/arm/dot_sve.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023, Alliance for Open Media. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef AOM_AOM_DSP_ARM_DOT_SVE_H_ -#define AOM_AOM_DSP_ARM_DOT_SVE_H_ - -#include - -#include "config/aom_dsp_rtcd.h" -#include "config/aom_config.h" - -// Dot product instructions operating on 16-bit input elements are exclusive to -// the SVE instruction set. However, we can access these instructions from a -// predominantly Neon context by making use of the Neon-SVE bridge intrinsics -// to reinterpret Neon vectors as SVE vectors - with the high part of the SVE -// vector (if it's longer than 128 bits) being "don't care". - -// While sub-optimal on machines that have SVE vector length > 128-bit - as the -// remainder of the vector is unused - this approach is still beneficial when -// compared to a Neon-only solution. - -static INLINE uint64x2_t aom_udotq_u16(uint64x2_t acc, uint16x8_t x, - uint16x8_t y) { - return svget_neonq_u64(svdot_u64(svset_neonq_u64(svundef_u64(), acc), - svset_neonq_u16(svundef_u16(), x), - svset_neonq_u16(svundef_u16(), y))); -} - -static INLINE int64x2_t aom_sdotq_s16(int64x2_t acc, int16x8_t x, int16x8_t y) { - return svget_neonq_s64(svdot_s64(svset_neonq_s64(svundef_s64(), acc), - svset_neonq_s16(svundef_s16(), x), - svset_neonq_s16(svundef_s16(), y))); -} - -#endif // AOM_AOM_DSP_ARM_DOT_SVE_H_ diff --git a/third_party/aom/aom_dsp/arm/highbd_convolve8_sve.c b/third_party/aom/aom_dsp/arm/highbd_convolve8_sve.c new file mode 100644 index 0000000000..e57c41a0b0 --- /dev/null +++ b/third_party/aom/aom_dsp/arm/highbd_convolve8_sve.c @@ -0,0 +1,681 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include +#include +#include + +#include "config/aom_config.h" +#include "config/aom_dsp_rtcd.h" + +#include "aom_dsp/arm/aom_neon_sve_bridge.h" +#include "aom_dsp/arm/aom_filter.h" +#include "aom_dsp/arm/mem_neon.h" + +static INLINE uint16x4_t highbd_convolve8_4_h(int16x8_t s[4], int16x8_t filter, + uint16x4_t max) { + int64x2_t sum[4]; + + sum[0] = aom_sdotq_s16(vdupq_n_s64(0), s[0], filter); + sum[1] = aom_sdotq_s16(vdupq_n_s64(0), s[1], filter); + sum[2] = aom_sdotq_s16(vdupq_n_s64(0), s[2], filter); + sum[3] = aom_sdotq_s16(vdupq_n_s64(0), s[3], filter); + + int64x2_t sum01 = vpaddq_s64(sum[0], sum[1]); + int64x2_t sum23 = vpaddq_s64(sum[2], sum[3]); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + + uint16x4_t res = vqrshrun_n_s32(sum0123, FILTER_BITS); + return vmin_u16(res, max); +} + +static INLINE uint16x8_t highbd_convolve8_8_h(int16x8_t s[8], int16x8_t filter, + uint16x8_t max) { + int64x2_t sum[8]; + + sum[0] = aom_sdotq_s16(vdupq_n_s64(0), s[0], filter); + sum[1] = aom_sdotq_s16(vdupq_n_s64(0), s[1], filter); + sum[2] = aom_sdotq_s16(vdupq_n_s64(0), s[2], filter); + sum[3] = aom_sdotq_s16(vdupq_n_s64(0), s[3], filter); + sum[4] = aom_sdotq_s16(vdupq_n_s64(0), s[4], filter); + sum[5] = aom_sdotq_s16(vdupq_n_s64(0), s[5], filter); + sum[6] = aom_sdotq_s16(vdupq_n_s64(0), s[6], filter); + sum[7] = aom_sdotq_s16(vdupq_n_s64(0), s[7], filter); + + int64x2_t sum01 = vpaddq_s64(sum[0], sum[1]); + int64x2_t sum23 = vpaddq_s64(sum[2], sum[3]); + int64x2_t sum45 = vpaddq_s64(sum[4], sum[5]); + int64x2_t sum67 = vpaddq_s64(sum[6], sum[7]); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0123, FILTER_BITS), + vqrshrun_n_s32(sum4567, FILTER_BITS)); + return vminq_u16(res, max); +} + +static INLINE void highbd_convolve8_horiz_8tap_sve( + const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, + ptrdiff_t dst_stride, const int16_t *filter_x, int width, int height, + int bd) { + const int16x8_t filter = vld1q_s16(filter_x); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + + do { + int16x8_t s0[4], s1[4], s2[4], s3[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + load_s16_8x4(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3]); + + uint16x4_t d0 = highbd_convolve8_4_h(s0, filter, max); + uint16x4_t d1 = highbd_convolve8_4_h(s1, filter, max); + uint16x4_t d2 = highbd_convolve8_4_h(s2, filter, max); + uint16x4_t d3 = highbd_convolve8_4_h(s3, filter, max); + + store_u16_4x4(d, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + d += 4 * dst_stride; + height -= 4; + } while (height > 0); + } else { + do { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[8], s1[8], s2[8], s3[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], + &s2[4], &s2[5], &s2[6], &s2[7]); + load_s16_8x8(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3], + &s3[4], &s3[5], &s3[6], &s3[7]); + + uint16x8_t d0 = highbd_convolve8_8_h(s0, filter, max); + uint16x8_t d1 = highbd_convolve8_8_h(s1, filter, max); + uint16x8_t d2 = highbd_convolve8_8_h(s2, filter, max); + uint16x8_t d3 = highbd_convolve8_8_h(s3, filter, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 0); + } +} + +// clang-format off +DECLARE_ALIGNED(16, static const uint16_t, kDotProdTbl[16]) = { + 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, +}; + +DECLARE_ALIGNED(16, static const uint16_t, kDeinterleaveTbl[8]) = { + 0, 2, 4, 6, 1, 3, 5, 7, +}; +// clang-format on + +static INLINE uint16x4_t highbd_convolve4_4_h(int16x8_t s, int16x8_t filter, + uint16x8x2_t permute_tbl, + uint16x4_t max) { + int16x8_t permuted_samples0 = aom_tbl_s16(s, permute_tbl.val[0]); + int16x8_t permuted_samples1 = aom_tbl_s16(s, permute_tbl.val[1]); + + int64x2_t sum0 = + aom_svdot_lane_s16(vdupq_n_s64(0), permuted_samples0, filter, 0); + int64x2_t sum1 = + aom_svdot_lane_s16(vdupq_n_s64(0), permuted_samples1, filter, 0); + + int32x4_t res_s32 = vcombine_s32(vmovn_s64(sum0), vmovn_s64(sum1)); + uint16x4_t res = vqrshrun_n_s32(res_s32, FILTER_BITS); + + return vmin_u16(res, max); +} + +static INLINE uint16x8_t highbd_convolve4_8_h(int16x8_t s[4], int16x8_t filter, + uint16x8_t idx, uint16x8_t max) { + int64x2_t sum04 = aom_svdot_lane_s16(vdupq_n_s64(0), s[0], filter, 0); + int64x2_t sum15 = aom_svdot_lane_s16(vdupq_n_s64(0), s[1], filter, 0); + int64x2_t sum26 = aom_svdot_lane_s16(vdupq_n_s64(0), s[2], filter, 0); + int64x2_t sum37 = aom_svdot_lane_s16(vdupq_n_s64(0), s[3], filter, 0); + + int32x4_t res0 = vcombine_s32(vmovn_s64(sum04), vmovn_s64(sum15)); + int32x4_t res1 = vcombine_s32(vmovn_s64(sum26), vmovn_s64(sum37)); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(res0, FILTER_BITS), + vqrshrun_n_s32(res1, FILTER_BITS)); + + res = aom_tbl_u16(res, idx); + + return vminq_u16(res, max); +} + +static INLINE void highbd_convolve8_horiz_4tap_sve( + const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, + ptrdiff_t dst_stride, const int16_t *filter_x, int width, int height, + int bd) { + const int16x8_t filter = vcombine_s16(vld1_s16(filter_x + 2), vdup_n_s16(0)); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + uint16x8x2_t permute_tbl = vld1q_u16_x2(kDotProdTbl); + + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + + do { + int16x8_t s0, s1, s2, s3; + load_s16_8x4(s, src_stride, &s0, &s1, &s2, &s3); + + uint16x4_t d0 = highbd_convolve4_4_h(s0, filter, permute_tbl, max); + uint16x4_t d1 = highbd_convolve4_4_h(s1, filter, permute_tbl, max); + uint16x4_t d2 = highbd_convolve4_4_h(s2, filter, permute_tbl, max); + uint16x4_t d3 = highbd_convolve4_4_h(s3, filter, permute_tbl, max); + + store_u16_4x4(d, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + d += 4 * dst_stride; + height -= 4; + } while (height > 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + uint16x8_t idx = vld1q_u16(kDeinterleaveTbl); + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[4], s1[4], s2[4], s3[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + load_s16_8x4(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3]); + + uint16x8_t d0 = highbd_convolve4_8_h(s0, filter, idx, max); + uint16x8_t d1 = highbd_convolve4_8_h(s1, filter, idx, max); + uint16x8_t d2 = highbd_convolve4_8_h(s2, filter, idx, max); + uint16x8_t d3 = highbd_convolve4_8_h(s3, filter, idx, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 0); + } +} + +void aom_highbd_convolve8_horiz_sve(const uint8_t *src8, ptrdiff_t src_stride, + uint8_t *dst8, ptrdiff_t dst_stride, + const int16_t *filter_x, int x_step_q4, + const int16_t *filter_y, int y_step_q4, + int width, int height, int bd) { + assert(x_step_q4 == 16); + assert(width >= 4 && height >= 4); + (void)filter_y; + (void)x_step_q4; + (void)y_step_q4; + + const uint16_t *src = CONVERT_TO_SHORTPTR(src8); + uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); + + src -= SUBPEL_TAPS / 2 - 1; + + if (get_filter_taps_convolve8(filter_x) <= 4) { + highbd_convolve8_horiz_4tap_sve(src + 2, src_stride, dst, dst_stride, + filter_x, width, height, bd); + } else { + highbd_convolve8_horiz_8tap_sve(src, src_stride, dst, dst_stride, filter_x, + width, height, bd); + } +} + +DECLARE_ALIGNED(16, static const uint8_t, kDotProdMergeBlockTbl[48]) = { + // Shift left and insert new last column in transposed 4x4 block. + 2, 3, 4, 5, 6, 7, 16, 17, 10, 11, 12, 13, 14, 15, 24, 25, + // Shift left and insert two new columns in transposed 4x4 block. + 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15, 24, 25, 26, 27, + // Shift left and insert three new columns in transposed 4x4 block. + 6, 7, 16, 17, 18, 19, 20, 21, 14, 15, 24, 25, 26, 27, 28, 29 +}; + +static INLINE void transpose_concat_4x4(int16x4_t s0, int16x4_t s1, + int16x4_t s2, int16x4_t s3, + int16x8_t res[2]) { + // Transpose 16-bit elements and concatenate result rows as follows: + // s0: 00, 01, 02, 03 + // s1: 10, 11, 12, 13 + // s2: 20, 21, 22, 23 + // s3: 30, 31, 32, 33 + // + // res[0]: 00 10 20 30 01 11 21 31 + // res[1]: 02 12 22 32 03 13 23 33 + + int16x8_t s0q = vcombine_s16(s0, vdup_n_s16(0)); + int16x8_t s1q = vcombine_s16(s1, vdup_n_s16(0)); + int16x8_t s2q = vcombine_s16(s2, vdup_n_s16(0)); + int16x8_t s3q = vcombine_s16(s3, vdup_n_s16(0)); + + int32x4_t s01 = vreinterpretq_s32_s16(vzip1q_s16(s0q, s1q)); + int32x4_t s23 = vreinterpretq_s32_s16(vzip1q_s16(s2q, s3q)); + + int32x4x2_t s0123 = vzipq_s32(s01, s23); + + res[0] = vreinterpretq_s16_s32(s0123.val[0]); + res[1] = vreinterpretq_s16_s32(s0123.val[1]); +} + +static INLINE void transpose_concat_8x4(int16x8_t s0, int16x8_t s1, + int16x8_t s2, int16x8_t s3, + int16x8_t res[4]) { + // Transpose 16-bit elements and concatenate result rows as follows: + // s0: 00, 01, 02, 03, 04, 05, 06, 07 + // s1: 10, 11, 12, 13, 14, 15, 16, 17 + // s2: 20, 21, 22, 23, 24, 25, 26, 27 + // s3: 30, 31, 32, 33, 34, 35, 36, 37 + // + // res_lo[0]: 00 10 20 30 01 11 21 31 + // res_lo[1]: 02 12 22 32 03 13 23 33 + // res_hi[0]: 04 14 24 34 05 15 25 35 + // res_hi[1]: 06 16 26 36 07 17 27 37 + + int16x8x2_t tr01_16 = vzipq_s16(s0, s1); + int16x8x2_t tr23_16 = vzipq_s16(s2, s3); + + int32x4x2_t tr01_32 = vzipq_s32(vreinterpretq_s32_s16(tr01_16.val[0]), + vreinterpretq_s32_s16(tr23_16.val[0])); + int32x4x2_t tr23_32 = vzipq_s32(vreinterpretq_s32_s16(tr01_16.val[1]), + vreinterpretq_s32_s16(tr23_16.val[1])); + + res[0] = vreinterpretq_s16_s32(tr01_32.val[0]); + res[1] = vreinterpretq_s16_s32(tr01_32.val[1]); + res[2] = vreinterpretq_s16_s32(tr23_32.val[0]); + res[3] = vreinterpretq_s16_s32(tr23_32.val[1]); +} + +static INLINE void aom_tbl2x4_s16(int16x8_t t0[4], int16x8_t t1[4], + uint8x16_t tbl, int16x8_t res[4]) { + int8x16x2_t samples0 = { vreinterpretq_s8_s16(t0[0]), + vreinterpretq_s8_s16(t1[0]) }; + int8x16x2_t samples1 = { vreinterpretq_s8_s16(t0[1]), + vreinterpretq_s8_s16(t1[1]) }; + int8x16x2_t samples2 = { vreinterpretq_s8_s16(t0[2]), + vreinterpretq_s8_s16(t1[2]) }; + int8x16x2_t samples3 = { vreinterpretq_s8_s16(t0[3]), + vreinterpretq_s8_s16(t1[3]) }; + + res[0] = vreinterpretq_s16_s8(vqtbl2q_s8(samples0, tbl)); + res[1] = vreinterpretq_s16_s8(vqtbl2q_s8(samples1, tbl)); + res[2] = vreinterpretq_s16_s8(vqtbl2q_s8(samples2, tbl)); + res[3] = vreinterpretq_s16_s8(vqtbl2q_s8(samples3, tbl)); +} + +static INLINE void aom_tbl2x2_s16(int16x8_t t0[2], int16x8_t t1[2], + uint8x16_t tbl, int16x8_t res[2]) { + int8x16x2_t samples0 = { vreinterpretq_s8_s16(t0[0]), + vreinterpretq_s8_s16(t1[0]) }; + int8x16x2_t samples1 = { vreinterpretq_s8_s16(t0[1]), + vreinterpretq_s8_s16(t1[1]) }; + + res[0] = vreinterpretq_s16_s8(vqtbl2q_s8(samples0, tbl)); + res[1] = vreinterpretq_s16_s8(vqtbl2q_s8(samples1, tbl)); +} + +static INLINE uint16x4_t highbd_convolve8_4_v(int16x8_t samples_lo[2], + int16x8_t samples_hi[2], + int16x8_t filter, + uint16x4_t max) { + int64x2_t sum[2]; + + sum[0] = aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[0], filter, 0); + sum[0] = aom_svdot_lane_s16(sum[0], samples_hi[0], filter, 1); + + sum[1] = aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[1], filter, 0); + sum[1] = aom_svdot_lane_s16(sum[1], samples_hi[1], filter, 1); + + int32x4_t res_s32 = vcombine_s32(vmovn_s64(sum[0]), vmovn_s64(sum[1])); + + uint16x4_t res = vqrshrun_n_s32(res_s32, FILTER_BITS); + + return vmin_u16(res, max); +} + +static INLINE uint16x8_t highbd_convolve8_8_v(int16x8_t samples_lo[4], + int16x8_t samples_hi[4], + int16x8_t filter, + uint16x8_t max) { + int64x2_t sum[4]; + + sum[0] = aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[0], filter, 0); + sum[0] = aom_svdot_lane_s16(sum[0], samples_hi[0], filter, 1); + + sum[1] = aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[1], filter, 0); + sum[1] = aom_svdot_lane_s16(sum[1], samples_hi[1], filter, 1); + + sum[2] = aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[2], filter, 0); + sum[2] = aom_svdot_lane_s16(sum[2], samples_hi[2], filter, 1); + + sum[3] = aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[3], filter, 0); + sum[3] = aom_svdot_lane_s16(sum[3], samples_hi[3], filter, 1); + + int32x4_t res0 = vcombine_s32(vmovn_s64(sum[0]), vmovn_s64(sum[1])); + int32x4_t res1 = vcombine_s32(vmovn_s64(sum[2]), vmovn_s64(sum[3])); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(res0, FILTER_BITS), + vqrshrun_n_s32(res1, FILTER_BITS)); + + return vminq_u16(res, max); +} + +static INLINE void highbd_convolve8_vert_8tap_sve( + const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, + ptrdiff_t dst_stride, const int16_t *filter_y, int width, int height, + int bd) { + const int16x8_t y_filter = vld1q_s16(filter_y); + + uint8x16_t merge_block_tbl[3]; + merge_block_tbl[0] = vld1q_u8(kDotProdMergeBlockTbl); + merge_block_tbl[1] = vld1q_u8(kDotProdMergeBlockTbl + 16); + merge_block_tbl[2] = vld1q_u8(kDotProdMergeBlockTbl + 32); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + int16_t *s = (int16_t *)src; + + int16x4_t s0, s1, s2, s3, s4, s5, s6; + load_s16_4x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + do { + int16x4_t s7, s8, s9, s10; + load_s16_4x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[2], s5678[2], s6789[2], s78910[2]; + + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_4x4(s7, s8, s9, s10, s78910); + + // Merge new data into block from previous iteration. + aom_tbl2x2_s16(s3456, s78910, merge_block_tbl[0], s4567); + aom_tbl2x2_s16(s3456, s78910, merge_block_tbl[1], s5678); + aom_tbl2x2_s16(s3456, s78910, merge_block_tbl[2], s6789); + + uint16x4_t d0 = highbd_convolve8_4_v(s0123, s4567, y_filter, max); + uint16x4_t d1 = highbd_convolve8_4_v(s1234, s5678, y_filter, max); + uint16x4_t d2 = highbd_convolve8_4_v(s2345, s6789, y_filter, max); + uint16x4_t d3 = highbd_convolve8_4_v(s3456, s78910, y_filter, max); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s78910[0]; + s3456[1] = s78910[1]; + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + do { + int h = height; + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + + int16x8_t s0, s1, s2, s3, s4, s5, s6; + load_s16_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + do { + int16x8_t s7, s8, s9, s10; + load_s16_8x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[4], s5678[4], s6789[4], s78910[4]; + + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_8x4(s7, s8, s9, s10, s78910); + + // Merge new data into block from previous iteration. + aom_tbl2x4_s16(s3456, s78910, merge_block_tbl[0], s4567); + aom_tbl2x4_s16(s3456, s78910, merge_block_tbl[1], s5678); + aom_tbl2x4_s16(s3456, s78910, merge_block_tbl[2], s6789); + + uint16x8_t d0 = highbd_convolve8_8_v(s0123, s4567, y_filter, max); + uint16x8_t d1 = highbd_convolve8_8_v(s1234, s5678, y_filter, max); + uint16x8_t d2 = highbd_convolve8_8_v(s2345, s6789, y_filter, max); + uint16x8_t d3 = highbd_convolve8_8_v(s3456, s78910, y_filter, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s0123[2] = s4567[2]; + s0123[3] = s4567[3]; + + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s1234[2] = s5678[2]; + s1234[3] = s5678[3]; + + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s2345[2] = s6789[2]; + s2345[3] = s6789[3]; + + s3456[0] = s78910[0]; + s3456[1] = s78910[1]; + s3456[2] = s78910[2]; + s3456[3] = s78910[3]; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +static INLINE uint16x4_t highbd_convolve4_4_v(int16x8_t s[2], int16x8_t filter, + uint16x4_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(vdupq_n_s64(0), s[0], filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(vdupq_n_s64(0), s[1], filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + uint16x4_t res = vqrshrun_n_s32(sum0123, FILTER_BITS); + + return vmin_u16(res, max); +} + +static INLINE uint16x8_t highbd_convolve4_8_v(int16x8_t s[4], int16x8_t filter, + uint16x8_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(vdupq_n_s64(0), s[0], filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(vdupq_n_s64(0), s[1], filter, 0); + int64x2_t sum45 = aom_svdot_lane_s16(vdupq_n_s64(0), s[2], filter, 0); + int64x2_t sum67 = aom_svdot_lane_s16(vdupq_n_s64(0), s[3], filter, 0); + + int32x4_t s0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t s4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(s0123, FILTER_BITS), + vqrshrun_n_s32(s4567, FILTER_BITS)); + + return vminq_u16(res, max); +} + +static INLINE void highbd_convolve8_vert_4tap_sve( + const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, + ptrdiff_t dst_stride, const int16_t *filter_y, int width, int height, + int bd) { + const int16x8_t y_filter = + vcombine_s16(vld1_s16(filter_y + 2), vdup_n_s16(0)); + + uint8x16_t merge_block_tbl[3]; + merge_block_tbl[0] = vld1q_u8(kDotProdMergeBlockTbl); + merge_block_tbl[1] = vld1q_u8(kDotProdMergeBlockTbl + 16); + merge_block_tbl[2] = vld1q_u8(kDotProdMergeBlockTbl + 32); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + int16_t *s = (int16_t *)src; + + int16x4_t s0, s1, s2; + load_s16_4x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x4_t s3, s4, s5, s6; + load_s16_4x4(s, src_stride, &s3, &s4, &s5, &s6); + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + uint16x4_t d0 = highbd_convolve4_4_v(s0123, y_filter, max); + uint16x4_t d1 = highbd_convolve4_4_v(s1234, y_filter, max); + uint16x4_t d2 = highbd_convolve4_4_v(s2345, y_filter, max); + uint16x4_t d3 = highbd_convolve4_4_v(s3456, y_filter, max); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Shuffle everything up four rows. + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + do { + int h = height; + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + + int16x8_t s0, s1, s2; + load_s16_8x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x8_t s3, s4, s5, s6; + load_s16_8x4(s, src_stride, &s3, &s4, &s5, &s6); + + // This operation combines a conventional transpose and the sample + // permute required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + uint16x8_t d0 = highbd_convolve4_8_v(s0123, y_filter, max); + uint16x8_t d1 = highbd_convolve4_8_v(s1234, y_filter, max); + uint16x8_t d2 = highbd_convolve4_8_v(s2345, y_filter, max); + uint16x8_t d3 = highbd_convolve4_8_v(s3456, y_filter, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Shuffle everything up four rows. + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +void aom_highbd_convolve8_vert_sve(const uint8_t *src8, ptrdiff_t src_stride, + uint8_t *dst8, ptrdiff_t dst_stride, + const int16_t *filter_x, int x_step_q4, + const int16_t *filter_y, int y_step_q4, + int width, int height, int bd) { + assert(y_step_q4 == 16); + assert(w >= 4 && h >= 4); + (void)filter_x; + (void)y_step_q4; + (void)x_step_q4; + + const uint16_t *src = CONVERT_TO_SHORTPTR(src8); + uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); + + src -= (SUBPEL_TAPS / 2 - 1) * src_stride; + + if (get_filter_taps_convolve8(filter_y) <= 4) { + highbd_convolve8_vert_4tap_sve(src + 2 * src_stride, src_stride, dst, + dst_stride, filter_y, width, height, bd); + } else { + highbd_convolve8_vert_8tap_sve(src, src_stride, dst, dst_stride, filter_y, + width, height, bd); + } +} diff --git a/third_party/aom/aom_dsp/arm/highbd_sse_sve.c b/third_party/aom/aom_dsp/arm/highbd_sse_sve.c index b267da5cfb..9ea13ab67a 100644 --- a/third_party/aom/aom_dsp/arm/highbd_sse_sve.c +++ b/third_party/aom/aom_dsp/arm/highbd_sse_sve.c @@ -10,7 +10,7 @@ #include -#include "aom_dsp/arm/dot_sve.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" #include "aom_dsp/arm/mem_neon.h" #include "config/aom_dsp_rtcd.h" diff --git a/third_party/aom/aom_dsp/arm/highbd_variance_sve.c b/third_party/aom/aom_dsp/arm/highbd_variance_sve.c index a2c30a1688..ad1f55e367 100644 --- a/third_party/aom/aom_dsp/arm/highbd_variance_sve.c +++ b/third_party/aom/aom_dsp/arm/highbd_variance_sve.c @@ -16,7 +16,7 @@ #include "config/aom_dsp_rtcd.h" #include "aom_dsp/aom_filter.h" -#include "aom_dsp/arm/dot_sve.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" #include "aom_dsp/arm/mem_neon.h" #include "aom_dsp/variance.h" diff --git a/third_party/aom/aom_dsp/arm/mem_neon.h b/third_party/aom/aom_dsp/arm/mem_neon.h index 52c7a34e3e..32a462a186 100644 --- a/third_party/aom/aom_dsp/arm/mem_neon.h +++ b/third_party/aom/aom_dsp/arm/mem_neon.h @@ -56,17 +56,10 @@ static INLINE uint16x8x4_t vld1q_u16_x4(const uint16_t *ptr) { #elif defined(__GNUC__) && !defined(__clang__) // GCC 64-bit. #if __GNUC__ < 8 - static INLINE uint8x16x2_t vld1q_u8_x2(const uint8_t *ptr) { uint8x16x2_t res = { { vld1q_u8(ptr + 0 * 16), vld1q_u8(ptr + 1 * 16) } }; return res; } - -static INLINE uint16x8x4_t vld1q_u16_x4(const uint16_t *ptr) { - uint16x8x4_t res = { { vld1q_u16(ptr + 0 * 8), vld1q_u16(ptr + 1 * 8), - vld1q_u16(ptr + 2 * 8), vld1q_u16(ptr + 3 * 8) } }; - return res; -} #endif // __GNUC__ < 8 #if __GNUC__ < 9 @@ -76,6 +69,15 @@ static INLINE uint8x16x3_t vld1q_u8_x3(const uint8_t *ptr) { return res; } #endif // __GNUC__ < 9 + +// vld1q_u16_x4 is defined from GCC 8.5.0 and onwards. +#if ((__GNUC__ << 8) | __GNUC_MINOR__) < 0x805 +static INLINE uint16x8x4_t vld1q_u16_x4(const uint16_t *ptr) { + uint16x8x4_t res = { { vld1q_u16(ptr + 0 * 8), vld1q_u16(ptr + 1 * 8), + vld1q_u16(ptr + 2 * 8), vld1q_u16(ptr + 3 * 8) } }; + return res; +} +#endif // ((__GNUC__ << 8) | __GNUC_MINOR__) < 0x805 #endif // defined(__GNUC__) && !defined(__clang__) static INLINE void store_u8_8x2(uint8_t *s, ptrdiff_t p, const uint8x8_t s0, @@ -457,6 +459,16 @@ static INLINE void load_s16_4x4(const int16_t *s, ptrdiff_t p, *s3 = vld1_s16(s); } +static INLINE void load_s16_4x3(const int16_t *s, ptrdiff_t p, + int16x4_t *const s0, int16x4_t *const s1, + int16x4_t *const s2) { + *s0 = vld1_s16(s); + s += p; + *s1 = vld1_s16(s); + s += p; + *s2 = vld1_s16(s); +} + static INLINE void store_u8_8x8(uint8_t *s, ptrdiff_t p, const uint8x8_t s0, const uint8x8_t s1, const uint8x8_t s2, const uint8x8_t s3, const uint8x8_t s4, @@ -525,6 +537,16 @@ static INLINE void store_u16_8x8(uint16_t *s, ptrdiff_t dst_stride, vst1q_u16(s, s7); } +static INLINE void store_u16_4x3(uint16_t *s, ptrdiff_t dst_stride, + const uint16x4_t s0, const uint16x4_t s1, + const uint16x4_t s2) { + vst1_u16(s, s0); + s += dst_stride; + vst1_u16(s, s1); + s += dst_stride; + vst1_u16(s, s2); +} + static INLINE void store_u16_4x4(uint16_t *s, ptrdiff_t dst_stride, const uint16x4_t s0, const uint16x4_t s1, const uint16x4_t s2, const uint16x4_t s3) { @@ -544,6 +566,16 @@ static INLINE void store_u16_8x2(uint16_t *s, ptrdiff_t dst_stride, vst1q_u16(s, s1); } +static INLINE void store_u16_8x3(uint16_t *s, ptrdiff_t dst_stride, + const uint16x8_t s0, const uint16x8_t s1, + const uint16x8_t s2) { + vst1q_u16(s, s0); + s += dst_stride; + vst1q_u16(s, s1); + s += dst_stride; + vst1q_u16(s, s2); +} + static INLINE void store_u16_8x4(uint16_t *s, ptrdiff_t dst_stride, const uint16x8_t s0, const uint16x8_t s1, const uint16x8_t s2, const uint16x8_t s3) { @@ -857,6 +889,16 @@ static INLINE void load_s16_8x4(const int16_t *s, ptrdiff_t p, *s3 = vld1q_s16(s); } +static INLINE void load_s16_8x3(const int16_t *s, ptrdiff_t p, + int16x8_t *const s0, int16x8_t *const s1, + int16x8_t *const s2) { + *s0 = vld1q_s16(s); + s += p; + *s1 = vld1q_s16(s); + s += p; + *s2 = vld1q_s16(s); +} + // Load 2 sets of 4 bytes when alignment is not guaranteed. static INLINE uint8x8_t load_unaligned_u8(const uint8_t *buf, int stride) { uint32_t a; diff --git a/third_party/aom/aom_dsp/arm/sum_squares_sve.c b/third_party/aom/aom_dsp/arm/sum_squares_sve.c index 724e43859e..c7e6dfcb02 100644 --- a/third_party/aom/aom_dsp/arm/sum_squares_sve.c +++ b/third_party/aom/aom_dsp/arm/sum_squares_sve.c @@ -11,7 +11,7 @@ #include -#include "aom_dsp/arm/dot_sve.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" #include "aom_dsp/arm/mem_neon.h" #include "config/aom_dsp_rtcd.h" diff --git a/third_party/aom/aom_dsp/flow_estimation/corner_detect.c b/third_party/aom/aom_dsp/flow_estimation/corner_detect.c index 284d1bd7b8..44d423dcdf 100644 --- a/third_party/aom/aom_dsp/flow_estimation/corner_detect.c +++ b/third_party/aom/aom_dsp/flow_estimation/corner_detect.c @@ -20,6 +20,7 @@ #include "aom_dsp/aom_dsp_common.h" #include "aom_dsp/flow_estimation/corner_detect.h" #include "aom_mem/aom_mem.h" +#include "aom_util/aom_pthread.h" #include "av1/common/common.h" #define FAST_BARRIER 18 @@ -39,11 +40,24 @@ CornerList *av1_alloc_corner_list(void) { return corners; } -static bool compute_corner_list(const ImagePyramid *pyr, CornerList *corners) { - const uint8_t *buf = pyr->layers[0].buffer; - int width = pyr->layers[0].width; - int height = pyr->layers[0].height; - int stride = pyr->layers[0].stride; +static bool compute_corner_list(const YV12_BUFFER_CONFIG *frame, int bit_depth, + int downsample_level, CornerList *corners) { + ImagePyramid *pyr = frame->y_pyramid; + const int layers = + aom_compute_pyramid(frame, bit_depth, downsample_level + 1, pyr); + + if (layers < 0) { + return false; + } + + // Clamp downsampling ratio base on max number of layers allowed + // for this frame size + downsample_level = layers - 1; + + const uint8_t *buf = pyr->layers[downsample_level].buffer; + int width = pyr->layers[downsample_level].width; + int height = pyr->layers[downsample_level].height; + int stride = pyr->layers[downsample_level].stride; int *scores = NULL; int num_corners; @@ -53,9 +67,11 @@ static bool compute_corner_list(const ImagePyramid *pyr, CornerList *corners) { if (num_corners <= MAX_CORNERS) { // Use all detected corners - if (num_corners != 0) { - memcpy(corners->corners, frame_corners_xy, - sizeof(*frame_corners_xy) * num_corners); + for (int i = 0; i < num_corners; i++) { + corners->corners[2 * i + 0] = + frame_corners_xy[i].x * (1 << downsample_level); + corners->corners[2 * i + 1] = + frame_corners_xy[i].y * (1 << downsample_level); } corners->num_corners = num_corners; } else { @@ -85,8 +101,10 @@ static bool compute_corner_list(const ImagePyramid *pyr, CornerList *corners) { for (int i = 0; i < num_corners; i++) { if (scores[i] > threshold) { assert(copied_corners < MAX_CORNERS); - corners->corners[2 * copied_corners + 0] = frame_corners_xy[i].x; - corners->corners[2 * copied_corners + 1] = frame_corners_xy[i].y; + corners->corners[2 * copied_corners + 0] = + frame_corners_xy[i].x * (1 << downsample_level); + corners->corners[2 * copied_corners + 1] = + frame_corners_xy[i].y * (1 << downsample_level); copied_corners += 1; } } @@ -99,7 +117,8 @@ static bool compute_corner_list(const ImagePyramid *pyr, CornerList *corners) { return true; } -bool av1_compute_corner_list(const ImagePyramid *pyr, CornerList *corners) { +bool av1_compute_corner_list(const YV12_BUFFER_CONFIG *frame, int bit_depth, + int downsample_level, CornerList *corners) { assert(corners); #if CONFIG_MULTITHREAD @@ -107,7 +126,8 @@ bool av1_compute_corner_list(const ImagePyramid *pyr, CornerList *corners) { #endif // CONFIG_MULTITHREAD if (!corners->valid) { - corners->valid = compute_corner_list(pyr, corners); + corners->valid = + compute_corner_list(frame, bit_depth, downsample_level, corners); } bool valid = corners->valid; diff --git a/third_party/aom/aom_dsp/flow_estimation/corner_detect.h b/third_party/aom/aom_dsp/flow_estimation/corner_detect.h index d05846ce5d..54d94309ed 100644 --- a/third_party/aom/aom_dsp/flow_estimation/corner_detect.h +++ b/third_party/aom/aom_dsp/flow_estimation/corner_detect.h @@ -18,7 +18,7 @@ #include #include "aom_dsp/pyramid.h" -#include "aom_util/aom_thread.h" +#include "aom_util/aom_pthread.h" #ifdef __cplusplus extern "C" { @@ -57,7 +57,8 @@ size_t av1_get_corner_list_size(void); CornerList *av1_alloc_corner_list(void); -bool av1_compute_corner_list(const ImagePyramid *pyr, CornerList *corners); +bool av1_compute_corner_list(const YV12_BUFFER_CONFIG *frame, int bit_depth, + int downsample_level, CornerList *corners); #ifndef NDEBUG // Check if a corner list has already been computed. diff --git a/third_party/aom/aom_dsp/flow_estimation/corner_match.c b/third_party/aom/aom_dsp/flow_estimation/corner_match.c index dc7589a8c6..c78edb8910 100644 --- a/third_party/aom/aom_dsp/flow_estimation/corner_match.c +++ b/third_party/aom/aom_dsp/flow_estimation/corner_match.c @@ -17,62 +17,84 @@ #include "aom_dsp/flow_estimation/corner_detect.h" #include "aom_dsp/flow_estimation/corner_match.h" +#include "aom_dsp/flow_estimation/disflow.h" #include "aom_dsp/flow_estimation/flow_estimation.h" #include "aom_dsp/flow_estimation/ransac.h" #include "aom_dsp/pyramid.h" #include "aom_scale/yv12config.h" -#define SEARCH_SZ 9 -#define SEARCH_SZ_BY2 ((SEARCH_SZ - 1) / 2) - #define THRESHOLD_NCC 0.75 -/* Compute var(frame) * MATCH_SZ_SQ over a MATCH_SZ by MATCH_SZ window of frame, - centered at (x, y). +/* Compute mean and standard deviation of pixels in a window of size + MATCH_SZ by MATCH_SZ centered at (x, y). + Store results into *mean and *one_over_stddev + + Note: The output of this function is scaled by MATCH_SZ, as in + *mean = MATCH_SZ * and + *one_over_stddev = 1 / (MATCH_SZ * ) + + Combined with the fact that we return 1/stddev rather than the standard + deviation itself, this allows us to completely avoid divisions in + aom_compute_correlation, which is much hotter than this function is. + + Returns true if this feature point is usable, false otherwise. */ -static double compute_variance(const unsigned char *frame, int stride, int x, - int y) { +bool aom_compute_mean_stddev_c(const unsigned char *frame, int stride, int x, + int y, double *mean, double *one_over_stddev) { int sum = 0; int sumsq = 0; - int var; - int i, j; - for (i = 0; i < MATCH_SZ; ++i) - for (j = 0; j < MATCH_SZ; ++j) { + for (int i = 0; i < MATCH_SZ; ++i) { + for (int j = 0; j < MATCH_SZ; ++j) { sum += frame[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)]; sumsq += frame[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)] * frame[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)]; } - var = sumsq * MATCH_SZ_SQ - sum * sum; - return (double)var; + } + *mean = (double)sum / MATCH_SZ; + const double variance = sumsq - (*mean) * (*mean); + if (variance < MIN_FEATURE_VARIANCE) { + *one_over_stddev = 0.0; + return false; + } + *one_over_stddev = 1.0 / sqrt(variance); + return true; } -/* Compute corr(frame1, frame2) * MATCH_SZ * stddev(frame1), where the - correlation/standard deviation are taken over MATCH_SZ by MATCH_SZ windows - of each image, centered at (x1, y1) and (x2, y2) respectively. +/* Compute corr(frame1, frame2) over a window of size MATCH_SZ by MATCH_SZ. + To save on computation, the mean and (1 divided by the) standard deviation + of the window in each frame are precomputed and passed into this function + as arguments. */ -double av1_compute_cross_correlation_c(const unsigned char *frame1, int stride1, - int x1, int y1, - const unsigned char *frame2, int stride2, - int x2, int y2) { +double aom_compute_correlation_c(const unsigned char *frame1, int stride1, + int x1, int y1, double mean1, + double one_over_stddev1, + const unsigned char *frame2, int stride2, + int x2, int y2, double mean2, + double one_over_stddev2) { int v1, v2; - int sum1 = 0; - int sum2 = 0; - int sumsq2 = 0; int cross = 0; - int var2, cov; - int i, j; - for (i = 0; i < MATCH_SZ; ++i) - for (j = 0; j < MATCH_SZ; ++j) { + for (int i = 0; i < MATCH_SZ; ++i) { + for (int j = 0; j < MATCH_SZ; ++j) { v1 = frame1[(i + y1 - MATCH_SZ_BY2) * stride1 + (j + x1 - MATCH_SZ_BY2)]; v2 = frame2[(i + y2 - MATCH_SZ_BY2) * stride2 + (j + x2 - MATCH_SZ_BY2)]; - sum1 += v1; - sum2 += v2; - sumsq2 += v2 * v2; cross += v1 * v2; } - var2 = sumsq2 * MATCH_SZ_SQ - sum2 * sum2; - cov = cross * MATCH_SZ_SQ - sum1 * sum2; - return cov / sqrt((double)var2); + } + + // Note: In theory, the calculations here "should" be + // covariance = cross / N^2 - mean1 * mean2 + // correlation = covariance / (stddev1 * stddev2). + // + // However, because of the scaling in aom_compute_mean_stddev, the + // lines below actually calculate + // covariance * N^2 = cross - (mean1 * N) * (mean2 * N) + // correlation = (covariance * N^2) / ((stddev1 * N) * (stddev2 * N)) + // + // ie. we have removed the need for a division, and still end up with the + // correct unscaled correlation (ie, in the range [-1, +1]) + double covariance = cross - mean1 * mean2; + double correlation = covariance * (one_over_stddev1 * one_over_stddev2); + return correlation; } static int is_eligible_point(int pointx, int pointy, int width, int height) { @@ -87,65 +109,14 @@ static int is_eligible_distance(int point1x, int point1y, int point2x, (point1y - point2y) * (point1y - point2y)) <= thresh * thresh; } -static void improve_correspondence(const unsigned char *src, - const unsigned char *ref, int width, - int height, int src_stride, int ref_stride, - Correspondence *correspondences, - int num_correspondences) { - int i; - for (i = 0; i < num_correspondences; ++i) { - int x, y, best_x = 0, best_y = 0; - double best_match_ncc = 0.0; - // For this algorithm, all points have integer coordinates. - // It's a little more efficient to convert them to ints once, - // before the inner loops - int x0 = (int)correspondences[i].x; - int y0 = (int)correspondences[i].y; - int rx0 = (int)correspondences[i].rx; - int ry0 = (int)correspondences[i].ry; - for (y = -SEARCH_SZ_BY2; y <= SEARCH_SZ_BY2; ++y) { - for (x = -SEARCH_SZ_BY2; x <= SEARCH_SZ_BY2; ++x) { - double match_ncc; - if (!is_eligible_point(rx0 + x, ry0 + y, width, height)) continue; - if (!is_eligible_distance(x0, y0, rx0 + x, ry0 + y, width, height)) - continue; - match_ncc = av1_compute_cross_correlation(src, src_stride, x0, y0, ref, - ref_stride, rx0 + x, ry0 + y); - if (match_ncc > best_match_ncc) { - best_match_ncc = match_ncc; - best_y = y; - best_x = x; - } - } - } - correspondences[i].rx += best_x; - correspondences[i].ry += best_y; - } - for (i = 0; i < num_correspondences; ++i) { - int x, y, best_x = 0, best_y = 0; - double best_match_ncc = 0.0; - int x0 = (int)correspondences[i].x; - int y0 = (int)correspondences[i].y; - int rx0 = (int)correspondences[i].rx; - int ry0 = (int)correspondences[i].ry; - for (y = -SEARCH_SZ_BY2; y <= SEARCH_SZ_BY2; ++y) - for (x = -SEARCH_SZ_BY2; x <= SEARCH_SZ_BY2; ++x) { - double match_ncc; - if (!is_eligible_point(x0 + x, y0 + y, width, height)) continue; - if (!is_eligible_distance(x0 + x, y0 + y, rx0, ry0, width, height)) - continue; - match_ncc = av1_compute_cross_correlation( - ref, ref_stride, rx0, ry0, src, src_stride, x0 + x, y0 + y); - if (match_ncc > best_match_ncc) { - best_match_ncc = match_ncc; - best_y = y; - best_x = x; - } - } - correspondences[i].x += best_x; - correspondences[i].y += best_y; - } -} +typedef struct { + int x; + int y; + double mean; + double one_over_stddev; + int best_match_idx; + double best_match_corr; +} PointInfo; static int determine_correspondence(const unsigned char *src, const int *src_corners, int num_src_corners, @@ -154,56 +125,136 @@ static int determine_correspondence(const unsigned char *src, int width, int height, int src_stride, int ref_stride, Correspondence *correspondences) { - // TODO(sarahparker) Improve this to include 2-way match - int i, j; + PointInfo *src_point_info = NULL; + PointInfo *ref_point_info = NULL; int num_correspondences = 0; - for (i = 0; i < num_src_corners; ++i) { - double best_match_ncc = 0.0; - double template_norm; - int best_match_j = -1; - if (!is_eligible_point(src_corners[2 * i], src_corners[2 * i + 1], width, - height)) + + src_point_info = + (PointInfo *)aom_calloc(num_src_corners, sizeof(*src_point_info)); + if (!src_point_info) { + goto finished; + } + + ref_point_info = + (PointInfo *)aom_calloc(num_ref_corners, sizeof(*ref_point_info)); + if (!ref_point_info) { + goto finished; + } + + // First pass (linear): + // Filter corner lists and compute per-patch means and standard deviations, + // for the src and ref frames independently + int src_point_count = 0; + for (int i = 0; i < num_src_corners; i++) { + int src_x = src_corners[2 * i]; + int src_y = src_corners[2 * i + 1]; + if (!is_eligible_point(src_x, src_y, width, height)) continue; + + PointInfo *point = &src_point_info[src_point_count]; + point->x = src_x; + point->y = src_y; + point->best_match_corr = THRESHOLD_NCC; + if (!aom_compute_mean_stddev(src, src_stride, src_x, src_y, &point->mean, + &point->one_over_stddev)) continue; - for (j = 0; j < num_ref_corners; ++j) { - double match_ncc; - if (!is_eligible_point(ref_corners[2 * j], ref_corners[2 * j + 1], width, - height)) - continue; - if (!is_eligible_distance(src_corners[2 * i], src_corners[2 * i + 1], - ref_corners[2 * j], ref_corners[2 * j + 1], - width, height)) + src_point_count++; + } + if (src_point_count == 0) { + goto finished; + } + + int ref_point_count = 0; + for (int j = 0; j < num_ref_corners; j++) { + int ref_x = ref_corners[2 * j]; + int ref_y = ref_corners[2 * j + 1]; + if (!is_eligible_point(ref_x, ref_y, width, height)) continue; + + PointInfo *point = &ref_point_info[ref_point_count]; + point->x = ref_x; + point->y = ref_y; + point->best_match_corr = THRESHOLD_NCC; + if (!aom_compute_mean_stddev(ref, ref_stride, ref_x, ref_y, &point->mean, + &point->one_over_stddev)) + continue; + ref_point_count++; + } + if (ref_point_count == 0) { + goto finished; + } + + // Second pass (quadratic): + // For each pair of points, compute correlation, and use this to determine + // the best match of each corner, in both directions + for (int i = 0; i < src_point_count; ++i) { + PointInfo *src_point = &src_point_info[i]; + for (int j = 0; j < ref_point_count; ++j) { + PointInfo *ref_point = &ref_point_info[j]; + if (!is_eligible_distance(src_point->x, src_point->y, ref_point->x, + ref_point->y, width, height)) continue; - match_ncc = av1_compute_cross_correlation( - src, src_stride, src_corners[2 * i], src_corners[2 * i + 1], ref, - ref_stride, ref_corners[2 * j], ref_corners[2 * j + 1]); - if (match_ncc > best_match_ncc) { - best_match_ncc = match_ncc; - best_match_j = j; + + double corr = aom_compute_correlation( + src, src_stride, src_point->x, src_point->y, src_point->mean, + src_point->one_over_stddev, ref, ref_stride, ref_point->x, + ref_point->y, ref_point->mean, ref_point->one_over_stddev); + + if (corr > src_point->best_match_corr) { + src_point->best_match_idx = j; + src_point->best_match_corr = corr; + } + if (corr > ref_point->best_match_corr) { + ref_point->best_match_idx = i; + ref_point->best_match_corr = corr; } } - // Note: We want to test if the best correlation is >= THRESHOLD_NCC, - // but need to account for the normalization in - // av1_compute_cross_correlation. - template_norm = compute_variance(src, src_stride, src_corners[2 * i], - src_corners[2 * i + 1]); - if (best_match_ncc > THRESHOLD_NCC * sqrt(template_norm)) { - correspondences[num_correspondences].x = src_corners[2 * i]; - correspondences[num_correspondences].y = src_corners[2 * i + 1]; - correspondences[num_correspondences].rx = ref_corners[2 * best_match_j]; - correspondences[num_correspondences].ry = - ref_corners[2 * best_match_j + 1]; + } + + // Third pass (linear): + // Scan through source corners, generating a correspondence for each corner + // iff ref_best_match[src_best_match[i]] == i + // Then refine the generated correspondences using optical flow + for (int i = 0; i < src_point_count; i++) { + PointInfo *point = &src_point_info[i]; + + // Skip corners which were not matched, or which didn't find + // a good enough match + if (point->best_match_corr < THRESHOLD_NCC) continue; + + PointInfo *match_point = &ref_point_info[point->best_match_idx]; + if (match_point->best_match_idx == i) { + // Refine match using optical flow and store + const int sx = point->x; + const int sy = point->y; + const int rx = match_point->x; + const int ry = match_point->y; + double u = (double)(rx - sx); + double v = (double)(ry - sy); + + const int patch_tl_x = sx - DISFLOW_PATCH_CENTER; + const int patch_tl_y = sy - DISFLOW_PATCH_CENTER; + + aom_compute_flow_at_point(src, ref, patch_tl_x, patch_tl_y, width, height, + src_stride, &u, &v); + + Correspondence *correspondence = &correspondences[num_correspondences]; + correspondence->x = (double)sx; + correspondence->y = (double)sy; + correspondence->rx = (double)sx + u; + correspondence->ry = (double)sy + v; num_correspondences++; } } - improve_correspondence(src, ref, width, height, src_stride, ref_stride, - correspondences, num_correspondences); + +finished: + aom_free(src_point_info); + aom_free(ref_point_info); return num_correspondences; } bool av1_compute_global_motion_feature_match( TransformationType type, YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *ref, - int bit_depth, MotionModel *motion_models, int num_motion_models, - bool *mem_alloc_failed) { + int bit_depth, int downsample_level, MotionModel *motion_models, + int num_motion_models, bool *mem_alloc_failed) { int num_correspondences; Correspondence *correspondences; ImagePyramid *src_pyramid = src->y_pyramid; @@ -212,19 +263,19 @@ bool av1_compute_global_motion_feature_match( CornerList *ref_corners = ref->corners; // Precompute information we will need about each frame - if (!aom_compute_pyramid(src, bit_depth, src_pyramid)) { + if (aom_compute_pyramid(src, bit_depth, 1, src_pyramid) < 0) { *mem_alloc_failed = true; return false; } - if (!av1_compute_corner_list(src_pyramid, src_corners)) { + if (!av1_compute_corner_list(src, bit_depth, downsample_level, src_corners)) { *mem_alloc_failed = true; return false; } - if (!aom_compute_pyramid(ref, bit_depth, ref_pyramid)) { + if (aom_compute_pyramid(ref, bit_depth, 1, ref_pyramid) < 0) { *mem_alloc_failed = true; return false; } - if (!av1_compute_corner_list(ref_pyramid, ref_corners)) { + if (!av1_compute_corner_list(src, bit_depth, downsample_level, ref_corners)) { *mem_alloc_failed = true; return false; } diff --git a/third_party/aom/aom_dsp/flow_estimation/corner_match.h b/third_party/aom/aom_dsp/flow_estimation/corner_match.h index 4435d2c767..77ebee2ea3 100644 --- a/third_party/aom/aom_dsp/flow_estimation/corner_match.h +++ b/third_party/aom/aom_dsp/flow_estimation/corner_match.h @@ -25,14 +25,20 @@ extern "C" { #endif -#define MATCH_SZ 13 +#define MATCH_SZ 16 #define MATCH_SZ_BY2 ((MATCH_SZ - 1) / 2) #define MATCH_SZ_SQ (MATCH_SZ * MATCH_SZ) +// Minimum threshold for the variance of a patch, in order for it to be +// considered useful for matching. +// This is evaluated against the scaled variance MATCH_SZ_SQ * sigma^2, +// so a setting of 1 * MATCH_SZ_SQ corresponds to an unscaled variance of 1 +#define MIN_FEATURE_VARIANCE (1 * MATCH_SZ_SQ) + bool av1_compute_global_motion_feature_match( TransformationType type, YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *ref, - int bit_depth, MotionModel *motion_models, int num_motion_models, - bool *mem_alloc_failed); + int bit_depth, int downsample_level, MotionModel *motion_models, + int num_motion_models, bool *mem_alloc_failed); #ifdef __cplusplus } diff --git a/third_party/aom/aom_dsp/flow_estimation/disflow.c b/third_party/aom/aom_dsp/flow_estimation/disflow.c index 82b531c729..f511a6eb49 100644 --- a/third_party/aom/aom_dsp/flow_estimation/disflow.c +++ b/third_party/aom/aom_dsp/flow_estimation/disflow.c @@ -603,9 +603,9 @@ static void upscale_flow_component(double *flow, int cur_width, int cur_height, // make sure flow_u and flow_v start at 0 static bool compute_flow_field(const ImagePyramid *src_pyr, - const ImagePyramid *ref_pyr, FlowField *flow) { + const ImagePyramid *ref_pyr, int n_levels, + FlowField *flow) { bool mem_status = true; - assert(src_pyr->n_levels == ref_pyr->n_levels); double *flow_u = flow->u; double *flow_v = flow->v; @@ -613,7 +613,7 @@ static bool compute_flow_field(const ImagePyramid *src_pyr, double *tmpbuf0; double *tmpbuf; - if (src_pyr->n_levels < 2) { + if (n_levels < 2) { // tmpbuf not needed tmpbuf0 = NULL; tmpbuf = NULL; @@ -639,7 +639,7 @@ static bool compute_flow_field(const ImagePyramid *src_pyr, // correspondences by interpolating this flow field, and then refine the // correspondences themselves. This is both faster and gives better output // compared to refining the flow field at level 0 and then interpolating. - for (int level = src_pyr->n_levels - 1; level >= 1; --level) { + for (int level = n_levels - 1; level >= 1; --level) { const PyramidLayer *cur_layer = &src_pyr->layers[level]; const int cur_width = cur_layer->width; const int cur_height = cur_layer->height; @@ -762,29 +762,31 @@ static void free_flow_field(FlowField *flow) { // Following the convention in flow_estimation.h, the flow vectors are computed // at fixed points in `src` and point to the corresponding locations in `ref`, // regardless of the temporal ordering of the frames. -bool av1_compute_global_motion_disflow(TransformationType type, - YV12_BUFFER_CONFIG *src, - YV12_BUFFER_CONFIG *ref, int bit_depth, - MotionModel *motion_models, - int num_motion_models, - bool *mem_alloc_failed) { +bool av1_compute_global_motion_disflow( + TransformationType type, YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *ref, + int bit_depth, int downsample_level, MotionModel *motion_models, + int num_motion_models, bool *mem_alloc_failed) { // Precompute information we will need about each frame ImagePyramid *src_pyramid = src->y_pyramid; CornerList *src_corners = src->corners; ImagePyramid *ref_pyramid = ref->y_pyramid; - if (!aom_compute_pyramid(src, bit_depth, src_pyramid)) { - *mem_alloc_failed = true; - return false; - } - if (!av1_compute_corner_list(src_pyramid, src_corners)) { + + const int src_layers = + aom_compute_pyramid(src, bit_depth, DISFLOW_PYRAMID_LEVELS, src_pyramid); + const int ref_layers = + aom_compute_pyramid(ref, bit_depth, DISFLOW_PYRAMID_LEVELS, ref_pyramid); + + if (src_layers < 0 || ref_layers < 0) { *mem_alloc_failed = true; return false; } - if (!aom_compute_pyramid(ref, bit_depth, ref_pyramid)) { + if (!av1_compute_corner_list(src, bit_depth, downsample_level, src_corners)) { *mem_alloc_failed = true; return false; } + assert(src_layers == ref_layers); + const int src_width = src_pyramid->layers[0].width; const int src_height = src_pyramid->layers[0].height; assert(ref_pyramid->layers[0].width == src_width); @@ -796,7 +798,7 @@ bool av1_compute_global_motion_disflow(TransformationType type, return false; } - if (!compute_flow_field(src_pyramid, ref_pyramid, flow)) { + if (!compute_flow_field(src_pyramid, ref_pyramid, src_layers, flow)) { *mem_alloc_failed = true; free_flow_field(flow); return false; diff --git a/third_party/aom/aom_dsp/flow_estimation/disflow.h b/third_party/aom/aom_dsp/flow_estimation/disflow.h index ef877b638c..ac3680004d 100644 --- a/third_party/aom/aom_dsp/flow_estimation/disflow.h +++ b/third_party/aom/aom_dsp/flow_estimation/disflow.h @@ -15,7 +15,6 @@ #include #include "aom_dsp/flow_estimation/flow_estimation.h" -#include "aom_dsp/rect.h" #include "aom_scale/yv12config.h" #ifdef __cplusplus @@ -92,12 +91,10 @@ typedef struct { int stride; } FlowField; -bool av1_compute_global_motion_disflow(TransformationType type, - YV12_BUFFER_CONFIG *src, - YV12_BUFFER_CONFIG *ref, int bit_depth, - MotionModel *motion_models, - int num_motion_models, - bool *mem_alloc_failed); +bool av1_compute_global_motion_disflow( + TransformationType type, YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *ref, + int bit_depth, int downsample_level, MotionModel *motion_models, + int num_motion_models, bool *mem_alloc_failed); #ifdef __cplusplus } diff --git a/third_party/aom/aom_dsp/flow_estimation/flow_estimation.c b/third_party/aom/aom_dsp/flow_estimation/flow_estimation.c index 0f47f86f55..96624eb863 100644 --- a/third_party/aom/aom_dsp/flow_estimation/flow_estimation.c +++ b/third_party/aom/aom_dsp/flow_estimation/flow_estimation.c @@ -18,14 +18,6 @@ #include "aom_ports/mem.h" #include "aom_scale/yv12config.h" -// For each global motion method, how many pyramid levels should we allocate? -// Note that this is a maximum, and fewer levels will be allocated if the frame -// is not large enough to need all of the specified levels -const int global_motion_pyr_levels[GLOBAL_MOTION_METHODS] = { - 1, // GLOBAL_MOTION_METHOD_FEATURE_MATCH - 16, // GLOBAL_MOTION_METHOD_DISFLOW -}; - // clang-format off const double kIdentityParams[MAX_PARAMDIM] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0 @@ -43,17 +35,17 @@ const double kIdentityParams[MAX_PARAMDIM] = { bool aom_compute_global_motion(TransformationType type, YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *ref, int bit_depth, GlobalMotionMethod gm_method, - MotionModel *motion_models, + int downsample_level, MotionModel *motion_models, int num_motion_models, bool *mem_alloc_failed) { switch (gm_method) { case GLOBAL_MOTION_METHOD_FEATURE_MATCH: return av1_compute_global_motion_feature_match( - type, src, ref, bit_depth, motion_models, num_motion_models, - mem_alloc_failed); + type, src, ref, bit_depth, downsample_level, motion_models, + num_motion_models, mem_alloc_failed); case GLOBAL_MOTION_METHOD_DISFLOW: - return av1_compute_global_motion_disflow(type, src, ref, bit_depth, - motion_models, num_motion_models, - mem_alloc_failed); + return av1_compute_global_motion_disflow( + type, src, ref, bit_depth, downsample_level, motion_models, + num_motion_models, mem_alloc_failed); default: assert(0 && "Unknown global motion estimation type"); } return false; diff --git a/third_party/aom/aom_dsp/flow_estimation/flow_estimation.h b/third_party/aom/aom_dsp/flow_estimation/flow_estimation.h index 2dfae24980..a38b03fc4e 100644 --- a/third_party/aom/aom_dsp/flow_estimation/flow_estimation.h +++ b/third_party/aom/aom_dsp/flow_estimation/flow_estimation.h @@ -61,11 +61,6 @@ typedef struct { double rx, ry; } Correspondence; -// For each global motion method, how many pyramid levels should we allocate? -// Note that this is a maximum, and fewer levels will be allocated if the frame -// is not large enough to need all of the specified levels -extern const int global_motion_pyr_levels[GLOBAL_MOTION_METHODS]; - // Which global motion method should we use in practice? // Disflow is both faster and gives better results than feature matching in // practically all cases, so we use disflow by default @@ -85,7 +80,7 @@ extern const double kIdentityParams[MAX_PARAMDIM]; bool aom_compute_global_motion(TransformationType type, YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *ref, int bit_depth, GlobalMotionMethod gm_method, - MotionModel *motion_models, + int downsample_level, MotionModel *motion_models, int num_motion_models, bool *mem_alloc_failed); #ifdef __cplusplus diff --git a/third_party/aom/aom_dsp/flow_estimation/ransac.c b/third_party/aom/aom_dsp/flow_estimation/ransac.c index b88a07b023..7c7bebdda4 100644 --- a/third_party/aom/aom_dsp/flow_estimation/ransac.c +++ b/third_party/aom/aom_dsp/flow_estimation/ransac.c @@ -29,8 +29,13 @@ #define INLIER_THRESHOLD 1.25 #define INLIER_THRESHOLD_SQUARED (INLIER_THRESHOLD * INLIER_THRESHOLD) + +// Number of initial models to generate #define NUM_TRIALS 20 +// Number of times to refine the best model found +#define NUM_REFINES 5 + // Flag to enable functions for finding TRANSLATION type models. // // These modes are not considered currently due to a spec bug (see comments @@ -39,63 +44,110 @@ // but disabled, for completeness. #define ALLOW_TRANSLATION_MODELS 0 +typedef struct { + int num_inliers; + double sse; // Sum of squared errors of inliers + int *inlier_indices; +} RANSAC_MOTION; + //////////////////////////////////////////////////////////////////////////////// // ransac -typedef bool (*IsDegenerateFunc)(double *p); -typedef bool (*FindTransformationFunc)(int points, const double *points1, - const double *points2, double *params); -typedef void (*ProjectPointsFunc)(const double *mat, const double *points, - double *proj, int n, int stride_points, - int stride_proj); +typedef bool (*FindTransformationFunc)(const Correspondence *points, + const int *indices, int num_indices, + double *params); +typedef void (*ScoreModelFunc)(const double *mat, const Correspondence *points, + int num_points, RANSAC_MOTION *model); // vtable-like structure which stores all of the information needed by RANSAC // for a particular model type typedef struct { - IsDegenerateFunc is_degenerate; FindTransformationFunc find_transformation; - ProjectPointsFunc project_points; + ScoreModelFunc score_model; + + // The minimum number of points which can be passed to find_transformation + // to generate a model. + // + // This should be set as small as possible. This is due to an observation + // from section 4 of "Optimal Ransac" by A. Hast, J. Nysjö and + // A. Marchetti (https://dspace5.zcu.cz/bitstream/11025/6869/1/Hast.pdf): + // using the minimum possible number of points in the initial model maximizes + // the chance that all of the selected points are inliers. + // + // That paper proposes a method which can deal with models which are + // contaminated by outliers, which helps in cases where the inlier fraction + // is low. However, for our purposes, global motion only gives significant + // gains when the inlier fraction is high. + // + // So we do not use the method from this paper, but we do find that + // minimizing the number of points used for initial model fitting helps + // make the best use of the limited number of models we consider. int minpts; } RansacModelInfo; #if ALLOW_TRANSLATION_MODELS -static void project_points_translation(const double *mat, const double *points, - double *proj, int n, int stride_points, - int stride_proj) { - int i; - for (i = 0; i < n; ++i) { - const double x = *(points++), y = *(points++); - *(proj++) = x + mat[0]; - *(proj++) = y + mat[1]; - points += stride_points - 2; - proj += stride_proj - 2; +static void score_translation(const double *mat, const Correspondence *points, + int num_points, RANSAC_MOTION *model) { + model->num_inliers = 0; + model->sse = 0.0; + + for (int i = 0; i < num_points; ++i) { + const double x1 = points[i].x; + const double y1 = points[i].y; + const double x2 = points[i].rx; + const double y2 = points[i].ry; + + const double proj_x = x1 + mat[0]; + const double proj_y = y1 + mat[1]; + + const double dx = proj_x - x2; + const double dy = proj_y - y2; + const double sse = dx * dx + dy * dy; + + if (sse < INLIER_THRESHOLD_SQUARED) { + model->inlier_indices[model->num_inliers++] = i; + model->sse += sse; + } } } #endif // ALLOW_TRANSLATION_MODELS -static void project_points_affine(const double *mat, const double *points, - double *proj, int n, int stride_points, - int stride_proj) { - int i; - for (i = 0; i < n; ++i) { - const double x = *(points++), y = *(points++); - *(proj++) = mat[2] * x + mat[3] * y + mat[0]; - *(proj++) = mat[4] * x + mat[5] * y + mat[1]; - points += stride_points - 2; - proj += stride_proj - 2; +static void score_affine(const double *mat, const Correspondence *points, + int num_points, RANSAC_MOTION *model) { + model->num_inliers = 0; + model->sse = 0.0; + + for (int i = 0; i < num_points; ++i) { + const double x1 = points[i].x; + const double y1 = points[i].y; + const double x2 = points[i].rx; + const double y2 = points[i].ry; + + const double proj_x = mat[2] * x1 + mat[3] * y1 + mat[0]; + const double proj_y = mat[4] * x1 + mat[5] * y1 + mat[1]; + + const double dx = proj_x - x2; + const double dy = proj_y - y2; + const double sse = dx * dx + dy * dy; + + if (sse < INLIER_THRESHOLD_SQUARED) { + model->inlier_indices[model->num_inliers++] = i; + model->sse += sse; + } } } #if ALLOW_TRANSLATION_MODELS -static bool find_translation(int np, const double *pts1, const double *pts2, - double *params) { +static bool find_translation(const Correspondence *points, const int *indices, + int num_indices, double *params) { double sumx = 0; double sumy = 0; - for (int i = 0; i < np; ++i) { - double dx = *(pts2++); - double dy = *(pts2++); - double sx = *(pts1++); - double sy = *(pts1++); + for (int i = 0; i < num_indices; ++i) { + int index = indices[i]; + const double sx = points[index].x; + const double sy = points[index].y; + const double dx = points[index].rx; + const double dy = points[index].ry; sumx += dx - sx; sumy += dy - sy; @@ -111,8 +163,8 @@ static bool find_translation(int np, const double *pts1, const double *pts2, } #endif // ALLOW_TRANSLATION_MODELS -static bool find_rotzoom(int np, const double *pts1, const double *pts2, - double *params) { +static bool find_rotzoom(const Correspondence *points, const int *indices, + int num_indices, double *params) { const int n = 4; // Size of least-squares problem double mat[4 * 4]; // Accumulator for A'A double y[4]; // Accumulator for A'b @@ -120,11 +172,12 @@ static bool find_rotzoom(int np, const double *pts1, const double *pts2, double b; // Single element of b least_squares_init(mat, y, n); - for (int i = 0; i < np; ++i) { - double dx = *(pts2++); - double dy = *(pts2++); - double sx = *(pts1++); - double sy = *(pts1++); + for (int i = 0; i < num_indices; ++i) { + int index = indices[i]; + const double sx = points[index].x; + const double sy = points[index].y; + const double dx = points[index].rx; + const double dy = points[index].ry; a[0] = 1; a[1] = 0; @@ -153,8 +206,8 @@ static bool find_rotzoom(int np, const double *pts1, const double *pts2, return true; } -static bool find_affine(int np, const double *pts1, const double *pts2, - double *params) { +static bool find_affine(const Correspondence *points, const int *indices, + int num_indices, double *params) { // Note: The least squares problem for affine models is 6-dimensional, // but it splits into two independent 3-dimensional subproblems. // Solving these two subproblems separately and recombining at the end @@ -174,11 +227,12 @@ static bool find_affine(int np, const double *pts1, const double *pts2, least_squares_init(mat[0], y[0], n); least_squares_init(mat[1], y[1], n); - for (int i = 0; i < np; ++i) { - double dx = *(pts2++); - double dy = *(pts2++); - double sx = *(pts1++); - double sy = *(pts1++); + for (int i = 0; i < num_indices; ++i) { + int index = indices[i]; + const double sx = points[index].x; + const double sy = points[index].y; + const double dx = points[index].rx; + const double dy = points[index].ry; a[0][0] = 1; a[0][1] = sx; @@ -211,12 +265,6 @@ static bool find_affine(int np, const double *pts1, const double *pts2, return true; } -typedef struct { - int num_inliers; - double sse; // Sum of squared errors of inliers - int *inlier_indices; -} RANSAC_MOTION; - // Return -1 if 'a' is a better motion, 1 if 'b' is better, 0 otherwise. static int compare_motions(const void *arg_a, const void *arg_b) { const RANSAC_MOTION *motion_a = (RANSAC_MOTION *)arg_a; @@ -234,15 +282,6 @@ static bool is_better_motion(const RANSAC_MOTION *motion_a, return compare_motions(motion_a, motion_b) < 0; } -static void copy_points_at_indices(double *dest, const double *src, - const int *indices, int num_points) { - for (int i = 0; i < num_points; ++i) { - const int index = indices[i]; - dest[i * 2] = src[index * 2]; - dest[i * 2 + 1] = src[index * 2 + 1]; - } -} - // Returns true on success, false on error static bool ransac_internal(const Correspondence *matched_points, int npoints, MotionModel *motion_models, int num_desired_motions, @@ -257,10 +296,6 @@ static bool ransac_internal(const Correspondence *matched_points, int npoints, int indices[MAX_MINPTS] = { 0 }; - double *points1, *points2; - double *corners1, *corners2; - double *projected_corners; - // Store information for the num_desired_motions best transformations found // and the worst motion among them, as well as the motion currently under // consideration. @@ -271,18 +306,19 @@ static bool ransac_internal(const Correspondence *matched_points, int npoints, // currently under consideration. double params_this_motion[MAX_PARAMDIM]; + // Initialize output models, as a fallback in case we can't find a model + for (i = 0; i < num_desired_motions; i++) { + memcpy(motion_models[i].params, kIdentityParams, + MAX_PARAMDIM * sizeof(*(motion_models[i].params))); + motion_models[i].num_inliers = 0; + } + if (npoints < minpts * MINPTS_MULTIPLIER || npoints == 0) { return false; } int min_inliers = AOMMAX((int)(MIN_INLIER_PROB * npoints), minpts); - points1 = (double *)aom_malloc(sizeof(*points1) * npoints * 2); - points2 = (double *)aom_malloc(sizeof(*points2) * npoints * 2); - corners1 = (double *)aom_malloc(sizeof(*corners1) * npoints * 2); - corners2 = (double *)aom_malloc(sizeof(*corners2) * npoints * 2); - projected_corners = - (double *)aom_malloc(sizeof(*projected_corners) * npoints * 2); motions = (RANSAC_MOTION *)aom_calloc(num_desired_motions, sizeof(RANSAC_MOTION)); @@ -295,8 +331,7 @@ static bool ransac_internal(const Correspondence *matched_points, int npoints, int *inlier_buffer = (int *)aom_malloc(sizeof(*inlier_buffer) * npoints * (num_desired_motions + 1)); - if (!(points1 && points2 && corners1 && corners2 && projected_corners && - motions && inlier_buffer)) { + if (!(motions && inlier_buffer)) { ret_val = false; *mem_alloc_failed = true; goto finish_ransac; @@ -311,50 +346,22 @@ static bool ransac_internal(const Correspondence *matched_points, int npoints, memset(¤t_motion, 0, sizeof(current_motion)); current_motion.inlier_indices = inlier_buffer + num_desired_motions * npoints; - for (i = 0; i < npoints; ++i) { - corners1[2 * i + 0] = matched_points[i].x; - corners1[2 * i + 1] = matched_points[i].y; - corners2[2 * i + 0] = matched_points[i].rx; - corners2[2 * i + 1] = matched_points[i].ry; - } - for (int trial_count = 0; trial_count < NUM_TRIALS; trial_count++) { lcg_pick(npoints, minpts, indices, &seed); - copy_points_at_indices(points1, corners1, indices, minpts); - copy_points_at_indices(points2, corners2, indices, minpts); - - if (model_info->is_degenerate(points1)) { - continue; - } - - if (!model_info->find_transformation(minpts, points1, points2, + if (!model_info->find_transformation(matched_points, indices, minpts, params_this_motion)) { continue; } - model_info->project_points(params_this_motion, corners1, projected_corners, - npoints, 2, 2); - - current_motion.num_inliers = 0; - double sse = 0.0; - for (i = 0; i < npoints; ++i) { - double dx = projected_corners[i * 2] - corners2[i * 2]; - double dy = projected_corners[i * 2 + 1] - corners2[i * 2 + 1]; - double squared_error = dx * dx + dy * dy; - - if (squared_error < INLIER_THRESHOLD_SQUARED) { - current_motion.inlier_indices[current_motion.num_inliers++] = i; - sse += squared_error; - } - } + model_info->score_model(params_this_motion, matched_points, npoints, + ¤t_motion); if (current_motion.num_inliers < min_inliers) { // Reject models with too few inliers continue; } - current_motion.sse = sse; if (is_better_motion(¤t_motion, worst_kept_motion)) { // This motion is better than the worst currently kept motion. Remember // the inlier points and sse. The parameters for each kept motion @@ -386,86 +393,98 @@ static bool ransac_internal(const Correspondence *matched_points, int npoints, // Sort the motions, best first. qsort(motions, num_desired_motions, sizeof(RANSAC_MOTION), compare_motions); - // Recompute the motions using only the inliers. + // Refine each of the best N models using iterative estimation. + // + // The idea here is loosely based on the iterative method from + // "Locally Optimized RANSAC" by O. Chum, J. Matas and Josef Kittler: + // https://cmp.felk.cvut.cz/ftp/articles/matas/chum-dagm03.pdf + // + // However, we implement a simpler version than their proposal, and simply + // refit the model repeatedly until the number of inliers stops increasing, + // with a cap on the number of iterations to defend against edge cases which + // only improve very slowly. for (i = 0; i < num_desired_motions; ++i) { - int num_inliers = motions[i].num_inliers; - if (num_inliers > 0) { - assert(num_inliers >= minpts); - - copy_points_at_indices(points1, corners1, motions[i].inlier_indices, - num_inliers); - copy_points_at_indices(points2, corners2, motions[i].inlier_indices, - num_inliers); - - if (!model_info->find_transformation(num_inliers, points1, points2, - motion_models[i].params)) { - // In the unlikely event that this model fitting fails, - // we don't have a good fallback. So just clear the output - // model and move on - memcpy(motion_models[i].params, kIdentityParams, - MAX_PARAMDIM * sizeof(*(motion_models[i].params))); - motion_models[i].num_inliers = 0; - continue; + if (motions[i].num_inliers <= 0) { + // Output model has already been initialized to the identity model, + // so just skip setup + continue; + } + + bool bad_model = false; + for (int refine_count = 0; refine_count < NUM_REFINES; refine_count++) { + int num_inliers = motions[i].num_inliers; + assert(num_inliers >= min_inliers); + + if (!model_info->find_transformation(matched_points, + motions[i].inlier_indices, + num_inliers, params_this_motion)) { + // In the unlikely event that this model fitting fails, we don't have a + // good fallback. So leave this model set to the identity model + bad_model = true; + break; } - // Populate inliers array - for (int j = 0; j < num_inliers; j++) { - int index = motions[i].inlier_indices[j]; - const Correspondence *corr = &matched_points[index]; - motion_models[i].inliers[2 * j + 0] = (int)rint(corr->x); - motion_models[i].inliers[2 * j + 1] = (int)rint(corr->y); + // Score the newly generated model + model_info->score_model(params_this_motion, matched_points, npoints, + ¤t_motion); + + // At this point, there are three possibilities: + // 1) If we found more inliers, keep refining. + // 2) If we found the same number of inliers but a lower SSE, we want to + // keep the new model, but further refinement is unlikely to gain much. + // So commit to this new model + // 3) It is possible, but very unlikely, that the new model will have + // fewer inliers. If it does happen, we probably just lost a few + // borderline inliers. So treat the same as case (2). + if (current_motion.num_inliers > motions[i].num_inliers) { + motions[i].num_inliers = current_motion.num_inliers; + motions[i].sse = current_motion.sse; + int *tmp = motions[i].inlier_indices; + motions[i].inlier_indices = current_motion.inlier_indices; + current_motion.inlier_indices = tmp; + } else { + // Refined model is no better, so stop + // This shouldn't be significantly worse than the previous model, + // so it's fine to use the parameters in params_this_motion. + // This saves us from having to cache the previous iteration's params. + break; } - motion_models[i].num_inliers = num_inliers; - } else { - memcpy(motion_models[i].params, kIdentityParams, - MAX_PARAMDIM * sizeof(*(motion_models[i].params))); - motion_models[i].num_inliers = 0; } + + if (bad_model) continue; + + // Fill in output struct + memcpy(motion_models[i].params, params_this_motion, + MAX_PARAMDIM * sizeof(*motion_models[i].params)); + for (int j = 0; j < motions[i].num_inliers; j++) { + int index = motions[i].inlier_indices[j]; + const Correspondence *corr = &matched_points[index]; + motion_models[i].inliers[2 * j + 0] = (int)rint(corr->x); + motion_models[i].inliers[2 * j + 1] = (int)rint(corr->y); + } + motion_models[i].num_inliers = motions[i].num_inliers; } finish_ransac: aom_free(inlier_buffer); aom_free(motions); - aom_free(projected_corners); - aom_free(corners2); - aom_free(corners1); - aom_free(points2); - aom_free(points1); return ret_val; } -static bool is_collinear3(double *p1, double *p2, double *p3) { - static const double collinear_eps = 1e-3; - const double v = - (p2[0] - p1[0]) * (p3[1] - p1[1]) - (p2[1] - p1[1]) * (p3[0] - p1[0]); - return fabs(v) < collinear_eps; -} - -#if ALLOW_TRANSLATION_MODELS -static bool is_degenerate_translation(double *p) { - return (p[0] - p[2]) * (p[0] - p[2]) + (p[1] - p[3]) * (p[1] - p[3]) <= 2; -} -#endif // ALLOW_TRANSLATION_MODELS - -static bool is_degenerate_affine(double *p) { - return is_collinear3(p, p + 2, p + 4); -} - static const RansacModelInfo ransac_model_info[TRANS_TYPES] = { // IDENTITY - { NULL, NULL, NULL, 0 }, + { NULL, NULL, 0 }, // TRANSLATION #if ALLOW_TRANSLATION_MODELS - { is_degenerate_translation, find_translation, project_points_translation, - 3 }, + { find_translation, score_translation, 1 }, #else - { NULL, NULL, NULL, 0 }, + { NULL, NULL, 0 }, #endif // ROTZOOM - { is_degenerate_affine, find_rotzoom, project_points_affine, 3 }, + { find_rotzoom, score_affine, 2 }, // AFFINE - { is_degenerate_affine, find_affine, project_points_affine, 3 }, + { find_affine, score_affine, 3 }, }; // Returns true on success, false on error diff --git a/third_party/aom/aom_dsp/flow_estimation/x86/corner_match_avx2.c b/third_party/aom/aom_dsp/flow_estimation/x86/corner_match_avx2.c index 87c76fa13b..ff69ae75f5 100644 --- a/third_party/aom/aom_dsp/flow_estimation/x86/corner_match_avx2.c +++ b/third_party/aom/aom_dsp/flow_estimation/x86/corner_match_avx2.c @@ -17,64 +17,112 @@ #include "aom_ports/mem.h" #include "aom_dsp/flow_estimation/corner_match.h" -DECLARE_ALIGNED(16, static const uint8_t, - byte_mask[16]) = { 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 0, 0, 0 }; -#if MATCH_SZ != 13 -#error "Need to change byte_mask in corner_match_sse4.c if MATCH_SZ != 13" +DECLARE_ALIGNED(32, static const uint16_t, ones_array[16]) = { 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 }; + +#if MATCH_SZ != 16 +#error "Need to apply pixel mask in corner_match_avx2.c if MATCH_SZ != 16" #endif -/* Compute corr(frame1, frame2) * MATCH_SZ * stddev(frame1), where the -correlation/standard deviation are taken over MATCH_SZ by MATCH_SZ windows -of each image, centered at (x1, y1) and (x2, y2) respectively. +/* Compute mean and standard deviation of pixels in a window of size + MATCH_SZ by MATCH_SZ centered at (x, y). + Store results into *mean and *one_over_stddev + + Note: The output of this function is scaled by MATCH_SZ, as in + *mean = MATCH_SZ * and + *one_over_stddev = 1 / (MATCH_SZ * ) + + Combined with the fact that we return 1/stddev rather than the standard + deviation itself, this allows us to completely avoid divisions in + aom_compute_correlation, which is much hotter than this function is. + + Returns true if this feature point is usable, false otherwise. */ -double av1_compute_cross_correlation_avx2(const unsigned char *frame1, - int stride1, int x1, int y1, - const unsigned char *frame2, - int stride2, int x2, int y2) { - int i, stride1_i = 0, stride2_i = 0; - __m256i temp1, sum_vec, sumsq2_vec, cross_vec, v, v1_1, v2_1; - const __m128i mask = _mm_load_si128((__m128i *)byte_mask); - const __m256i zero = _mm256_setzero_si256(); - __m128i v1, v2; - - sum_vec = zero; - sumsq2_vec = zero; - cross_vec = zero; +bool aom_compute_mean_stddev_avx2(const unsigned char *frame, int stride, int x, + int y, double *mean, + double *one_over_stddev) { + __m256i sum_vec = _mm256_setzero_si256(); + __m256i sumsq_vec = _mm256_setzero_si256(); + + frame += (y - MATCH_SZ_BY2) * stride + (x - MATCH_SZ_BY2); + + for (int i = 0; i < MATCH_SZ; ++i) { + const __m256i v = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)frame)); + + sum_vec = _mm256_add_epi16(sum_vec, v); + sumsq_vec = _mm256_add_epi32(sumsq_vec, _mm256_madd_epi16(v, v)); + + frame += stride; + } + + // Reduce sum_vec and sumsq_vec into single values + // Start by reducing each vector to 8x32-bit values, hadd() to perform 8 + // additions, sum vertically to do 4 more, then the last 2 in scalar code. + const __m256i ones = _mm256_load_si256((__m256i *)ones_array); + const __m256i partial_sum = _mm256_madd_epi16(sum_vec, ones); + const __m256i tmp_8x32 = _mm256_hadd_epi32(partial_sum, sumsq_vec); + const __m128i tmp_4x32 = _mm_add_epi32(_mm256_extracti128_si256(tmp_8x32, 0), + _mm256_extracti128_si256(tmp_8x32, 1)); + const int sum = + _mm_extract_epi32(tmp_4x32, 0) + _mm_extract_epi32(tmp_4x32, 1); + const int sumsq = + _mm_extract_epi32(tmp_4x32, 2) + _mm_extract_epi32(tmp_4x32, 3); + + *mean = (double)sum / MATCH_SZ; + const double variance = sumsq - (*mean) * (*mean); + if (variance < MIN_FEATURE_VARIANCE) { + *one_over_stddev = 0.0; + return false; + } + *one_over_stddev = 1.0 / sqrt(variance); + return true; +} + +/* Compute corr(frame1, frame2) over a window of size MATCH_SZ by MATCH_SZ. + To save on computation, the mean and (1 divided by the) standard deviation + of the window in each frame are precomputed and passed into this function + as arguments. +*/ +double aom_compute_correlation_avx2(const unsigned char *frame1, int stride1, + int x1, int y1, double mean1, + double one_over_stddev1, + const unsigned char *frame2, int stride2, + int x2, int y2, double mean2, + double one_over_stddev2) { + __m256i cross_vec = _mm256_setzero_si256(); frame1 += (y1 - MATCH_SZ_BY2) * stride1 + (x1 - MATCH_SZ_BY2); frame2 += (y2 - MATCH_SZ_BY2) * stride2 + (x2 - MATCH_SZ_BY2); - for (i = 0; i < MATCH_SZ; ++i) { - v1 = _mm_and_si128(_mm_loadu_si128((__m128i *)&frame1[stride1_i]), mask); - v1_1 = _mm256_cvtepu8_epi16(v1); - v2 = _mm_and_si128(_mm_loadu_si128((__m128i *)&frame2[stride2_i]), mask); - v2_1 = _mm256_cvtepu8_epi16(v2); + for (int i = 0; i < MATCH_SZ; ++i) { + const __m256i v1 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)frame1)); + const __m256i v2 = _mm256_cvtepu8_epi16(_mm_loadu_si128((__m128i *)frame2)); - v = _mm256_insertf128_si256(_mm256_castsi128_si256(v1), v2, 1); - sumsq2_vec = _mm256_add_epi32(sumsq2_vec, _mm256_madd_epi16(v2_1, v2_1)); + cross_vec = _mm256_add_epi32(cross_vec, _mm256_madd_epi16(v1, v2)); - sum_vec = _mm256_add_epi16(sum_vec, _mm256_sad_epu8(v, zero)); - cross_vec = _mm256_add_epi32(cross_vec, _mm256_madd_epi16(v1_1, v2_1)); - stride1_i += stride1; - stride2_i += stride2; + frame1 += stride1; + frame2 += stride2; } - __m256i sum_vec1 = _mm256_srli_si256(sum_vec, 8); - sum_vec = _mm256_add_epi32(sum_vec, sum_vec1); - int sum1_acc = _mm_cvtsi128_si32(_mm256_castsi256_si128(sum_vec)); - int sum2_acc = _mm256_extract_epi32(sum_vec, 4); - - __m256i unp_low = _mm256_unpacklo_epi64(sumsq2_vec, cross_vec); - __m256i unp_hig = _mm256_unpackhi_epi64(sumsq2_vec, cross_vec); - temp1 = _mm256_add_epi32(unp_low, unp_hig); - - __m128i low_sumsq = _mm256_castsi256_si128(temp1); - low_sumsq = _mm_add_epi32(low_sumsq, _mm256_extractf128_si256(temp1, 1)); - low_sumsq = _mm_add_epi32(low_sumsq, _mm_srli_epi64(low_sumsq, 32)); - int sumsq2_acc = _mm_cvtsi128_si32(low_sumsq); - int cross_acc = _mm_extract_epi32(low_sumsq, 2); - - int var2 = sumsq2_acc * MATCH_SZ_SQ - sum2_acc * sum2_acc; - int cov = cross_acc * MATCH_SZ_SQ - sum1_acc * sum2_acc; - return cov / sqrt((double)var2); + + // Sum cross_vec into a single value + const __m128i tmp = _mm_add_epi32(_mm256_extracti128_si256(cross_vec, 0), + _mm256_extracti128_si256(cross_vec, 1)); + const int cross = _mm_extract_epi32(tmp, 0) + _mm_extract_epi32(tmp, 1) + + _mm_extract_epi32(tmp, 2) + _mm_extract_epi32(tmp, 3); + + // Note: In theory, the calculations here "should" be + // covariance = cross / N^2 - mean1 * mean2 + // correlation = covariance / (stddev1 * stddev2). + // + // However, because of the scaling in aom_compute_mean_stddev, the + // lines below actually calculate + // covariance * N^2 = cross - (mean1 * N) * (mean2 * N) + // correlation = (covariance * N^2) / ((stddev1 * N) * (stddev2 * N)) + // + // ie. we have removed the need for a division, and still end up with the + // correct unscaled correlation (ie, in the range [-1, +1]) + const double covariance = cross - mean1 * mean2; + const double correlation = covariance * (one_over_stddev1 * one_over_stddev2); + return correlation; } diff --git a/third_party/aom/aom_dsp/flow_estimation/x86/corner_match_sse4.c b/third_party/aom/aom_dsp/flow_estimation/x86/corner_match_sse4.c index b3cb5bc5fd..bff7db6d2f 100644 --- a/third_party/aom/aom_dsp/flow_estimation/x86/corner_match_sse4.c +++ b/third_party/aom/aom_dsp/flow_estimation/x86/corner_match_sse4.c @@ -21,84 +21,125 @@ #include "aom_ports/mem.h" #include "aom_dsp/flow_estimation/corner_match.h" -DECLARE_ALIGNED(16, static const uint8_t, - byte_mask[16]) = { 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 0, 0, 0 }; -#if MATCH_SZ != 13 -#error "Need to change byte_mask in corner_match_sse4.c if MATCH_SZ != 13" +DECLARE_ALIGNED(16, static const uint16_t, ones_array[8]) = { 1, 1, 1, 1, + 1, 1, 1, 1 }; + +#if MATCH_SZ != 16 +#error "Need to apply pixel mask in corner_match_sse4.c if MATCH_SZ != 16" #endif -/* Compute corr(frame1, frame2) * MATCH_SZ * stddev(frame1), where the - correlation/standard deviation are taken over MATCH_SZ by MATCH_SZ windows - of each image, centered at (x1, y1) and (x2, y2) respectively. +/* Compute mean and standard deviation of pixels in a window of size + MATCH_SZ by MATCH_SZ centered at (x, y). + Store results into *mean and *one_over_stddev + + Note: The output of this function is scaled by MATCH_SZ, as in + *mean = MATCH_SZ * and + *one_over_stddev = 1 / (MATCH_SZ * ) + + Combined with the fact that we return 1/stddev rather than the standard + deviation itself, this allows us to completely avoid divisions in + aom_compute_correlation, which is much hotter than this function is. + + Returns true if this feature point is usable, false otherwise. +*/ +bool aom_compute_mean_stddev_sse4_1(const unsigned char *frame, int stride, + int x, int y, double *mean, + double *one_over_stddev) { + // 8 16-bit partial sums of pixels + // Each lane sums at most 2*MATCH_SZ pixels, which can have values up to 255, + // and is therefore at most 2*MATCH_SZ*255, which is > 2^8 but < 2^16. + // Thus this value is safe to store in 16 bits. + __m128i sum_vec = _mm_setzero_si128(); + + // 8 32-bit partial sums of squares + __m128i sumsq_vec_l = _mm_setzero_si128(); + __m128i sumsq_vec_r = _mm_setzero_si128(); + + frame += (y - MATCH_SZ_BY2) * stride + (x - MATCH_SZ_BY2); + + for (int i = 0; i < MATCH_SZ; ++i) { + const __m128i v = _mm_loadu_si128((__m128i *)frame); + const __m128i v_l = _mm_cvtepu8_epi16(v); + const __m128i v_r = _mm_cvtepu8_epi16(_mm_srli_si128(v, 8)); + + sum_vec = _mm_add_epi16(sum_vec, _mm_add_epi16(v_l, v_r)); + sumsq_vec_l = _mm_add_epi32(sumsq_vec_l, _mm_madd_epi16(v_l, v_l)); + sumsq_vec_r = _mm_add_epi32(sumsq_vec_r, _mm_madd_epi16(v_r, v_r)); + + frame += stride; + } + + // Reduce sum_vec and sumsq_vec into single values + // Start by reducing each vector to 4x32-bit values, hadd() to perform four + // additions, then perform the last two additions in scalar code. + const __m128i ones = _mm_load_si128((__m128i *)ones_array); + const __m128i partial_sum = _mm_madd_epi16(sum_vec, ones); + const __m128i partial_sumsq = _mm_add_epi32(sumsq_vec_l, sumsq_vec_r); + const __m128i tmp = _mm_hadd_epi32(partial_sum, partial_sumsq); + const int sum = _mm_extract_epi32(tmp, 0) + _mm_extract_epi32(tmp, 1); + const int sumsq = _mm_extract_epi32(tmp, 2) + _mm_extract_epi32(tmp, 3); + + *mean = (double)sum / MATCH_SZ; + const double variance = sumsq - (*mean) * (*mean); + if (variance < MIN_FEATURE_VARIANCE) { + *one_over_stddev = 0.0; + return false; + } + *one_over_stddev = 1.0 / sqrt(variance); + return true; +} + +/* Compute corr(frame1, frame2) over a window of size MATCH_SZ by MATCH_SZ. + To save on computation, the mean and (1 divided by the) standard deviation + of the window in each frame are precomputed and passed into this function + as arguments. */ -double av1_compute_cross_correlation_sse4_1(const unsigned char *frame1, - int stride1, int x1, int y1, - const unsigned char *frame2, - int stride2, int x2, int y2) { - int i; - // 2 16-bit partial sums in lanes 0, 4 (== 2 32-bit partial sums in lanes 0, - // 2) - __m128i sum1_vec = _mm_setzero_si128(); - __m128i sum2_vec = _mm_setzero_si128(); - // 4 32-bit partial sums of squares - __m128i sumsq2_vec = _mm_setzero_si128(); - __m128i cross_vec = _mm_setzero_si128(); - - const __m128i mask = _mm_load_si128((__m128i *)byte_mask); - const __m128i zero = _mm_setzero_si128(); +double aom_compute_correlation_sse4_1(const unsigned char *frame1, int stride1, + int x1, int y1, double mean1, + double one_over_stddev1, + const unsigned char *frame2, int stride2, + int x2, int y2, double mean2, + double one_over_stddev2) { + // 8 32-bit partial sums of products + __m128i cross_vec_l = _mm_setzero_si128(); + __m128i cross_vec_r = _mm_setzero_si128(); frame1 += (y1 - MATCH_SZ_BY2) * stride1 + (x1 - MATCH_SZ_BY2); frame2 += (y2 - MATCH_SZ_BY2) * stride2 + (x2 - MATCH_SZ_BY2); - for (i = 0; i < MATCH_SZ; ++i) { - const __m128i v1 = - _mm_and_si128(_mm_loadu_si128((__m128i *)&frame1[i * stride1]), mask); - const __m128i v2 = - _mm_and_si128(_mm_loadu_si128((__m128i *)&frame2[i * stride2]), mask); - - // Using the 'sad' intrinsic here is a bit faster than adding - // v1_l + v1_r and v2_l + v2_r, plus it avoids the need for a 16->32 bit - // conversion step later, for a net speedup of ~10% - sum1_vec = _mm_add_epi16(sum1_vec, _mm_sad_epu8(v1, zero)); - sum2_vec = _mm_add_epi16(sum2_vec, _mm_sad_epu8(v2, zero)); + for (int i = 0; i < MATCH_SZ; ++i) { + const __m128i v1 = _mm_loadu_si128((__m128i *)frame1); + const __m128i v2 = _mm_loadu_si128((__m128i *)frame2); const __m128i v1_l = _mm_cvtepu8_epi16(v1); const __m128i v1_r = _mm_cvtepu8_epi16(_mm_srli_si128(v1, 8)); const __m128i v2_l = _mm_cvtepu8_epi16(v2); const __m128i v2_r = _mm_cvtepu8_epi16(_mm_srli_si128(v2, 8)); - sumsq2_vec = _mm_add_epi32( - sumsq2_vec, - _mm_add_epi32(_mm_madd_epi16(v2_l, v2_l), _mm_madd_epi16(v2_r, v2_r))); - cross_vec = _mm_add_epi32( - cross_vec, - _mm_add_epi32(_mm_madd_epi16(v1_l, v2_l), _mm_madd_epi16(v1_r, v2_r))); + cross_vec_l = _mm_add_epi32(cross_vec_l, _mm_madd_epi16(v1_l, v2_l)); + cross_vec_r = _mm_add_epi32(cross_vec_r, _mm_madd_epi16(v1_r, v2_r)); + + frame1 += stride1; + frame2 += stride2; } - // Now we can treat the four registers (sum1_vec, sum2_vec, sumsq2_vec, - // cross_vec) - // as holding 4 32-bit elements each, which we want to sum horizontally. - // We do this by transposing and then summing vertically. - __m128i tmp_0 = _mm_unpacklo_epi32(sum1_vec, sum2_vec); - __m128i tmp_1 = _mm_unpackhi_epi32(sum1_vec, sum2_vec); - __m128i tmp_2 = _mm_unpacklo_epi32(sumsq2_vec, cross_vec); - __m128i tmp_3 = _mm_unpackhi_epi32(sumsq2_vec, cross_vec); - - __m128i tmp_4 = _mm_unpacklo_epi64(tmp_0, tmp_2); - __m128i tmp_5 = _mm_unpackhi_epi64(tmp_0, tmp_2); - __m128i tmp_6 = _mm_unpacklo_epi64(tmp_1, tmp_3); - __m128i tmp_7 = _mm_unpackhi_epi64(tmp_1, tmp_3); - - __m128i res = - _mm_add_epi32(_mm_add_epi32(tmp_4, tmp_5), _mm_add_epi32(tmp_6, tmp_7)); - - int sum1 = _mm_extract_epi32(res, 0); - int sum2 = _mm_extract_epi32(res, 1); - int sumsq2 = _mm_extract_epi32(res, 2); - int cross = _mm_extract_epi32(res, 3); - - int var2 = sumsq2 * MATCH_SZ_SQ - sum2 * sum2; - int cov = cross * MATCH_SZ_SQ - sum1 * sum2; - return cov / sqrt((double)var2); + // Sum cross_vec into a single value + const __m128i tmp = _mm_add_epi32(cross_vec_l, cross_vec_r); + const int cross = _mm_extract_epi32(tmp, 0) + _mm_extract_epi32(tmp, 1) + + _mm_extract_epi32(tmp, 2) + _mm_extract_epi32(tmp, 3); + + // Note: In theory, the calculations here "should" be + // covariance = cross / N^2 - mean1 * mean2 + // correlation = covariance / (stddev1 * stddev2). + // + // However, because of the scaling in aom_compute_mean_stddev, the + // lines below actually calculate + // covariance * N^2 = cross - (mean1 * N) * (mean2 * N) + // correlation = (covariance * N^2) / ((stddev1 * N) * (stddev2 * N)) + // + // ie. we have removed the need for a division, and still end up with the + // correct unscaled correlation (ie, in the range [-1, +1]) + const double covariance = cross - mean1 * mean2; + const double correlation = covariance * (one_over_stddev1 * one_over_stddev2); + return correlation; } diff --git a/third_party/aom/aom_dsp/flow_estimation/x86/disflow_avx2.c b/third_party/aom/aom_dsp/flow_estimation/x86/disflow_avx2.c new file mode 100644 index 0000000000..ad5a1bd7c6 --- /dev/null +++ b/third_party/aom/aom_dsp/flow_estimation/x86/disflow_avx2.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include +#include +#include + +#include "aom_dsp/aom_dsp_common.h" +#include "aom_dsp/flow_estimation/disflow.h" +#include "aom_dsp/x86/synonyms.h" +#include "aom_dsp/x86/synonyms_avx2.h" + +#include "config/aom_dsp_rtcd.h" + +#if DISFLOW_PATCH_SIZE != 8 +#error "Need to change disflow_avx2.c if DISFLOW_PATCH_SIZE != 8" +#endif + +// Compute horizontal and vertical kernels and return them packed into a +// register. The coefficient ordering is: +// h0, h1, v0, v1, h2, h3, v2, v3 +// This is chosen because it takes less work than fully separating the kernels, +// but it is separated enough that we can pick out each coefficient pair in the +// main compute_flow_at_point function +static INLINE __m128i compute_cubic_kernels(double u, double v) { + const __m128d x = _mm_set_pd(v, u); + + const __m128d x2 = _mm_mul_pd(x, x); + const __m128d x3 = _mm_mul_pd(x2, x); + + // Macro to multiply a value v by a constant coefficient c +#define MULC(c, v) _mm_mul_pd(_mm_set1_pd(c), v) + + // Compute floating-point kernel + // Note: To ensure results are bit-identical to the C code, we need to perform + // exactly the same sequence of operations here as in the C code. + __m128d k0 = _mm_sub_pd(_mm_add_pd(MULC(-0.5, x), x2), MULC(0.5, x3)); + __m128d k1 = + _mm_add_pd(_mm_sub_pd(_mm_set1_pd(1.0), MULC(2.5, x2)), MULC(1.5, x3)); + __m128d k2 = + _mm_sub_pd(_mm_add_pd(MULC(0.5, x), MULC(2.0, x2)), MULC(1.5, x3)); + __m128d k3 = _mm_add_pd(MULC(-0.5, x2), MULC(0.5, x3)); +#undef MULC + + // Integerize + __m128d prec = _mm_set1_pd((double)(1 << DISFLOW_INTERP_BITS)); + + k0 = _mm_round_pd(_mm_mul_pd(k0, prec), + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + k1 = _mm_round_pd(_mm_mul_pd(k1, prec), + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + k2 = _mm_round_pd(_mm_mul_pd(k2, prec), + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + k3 = _mm_round_pd(_mm_mul_pd(k3, prec), + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + + const __m128i c0 = _mm_cvtpd_epi32(k0); + const __m128i c1 = _mm_cvtpd_epi32(k1); + const __m128i c2 = _mm_cvtpd_epi32(k2); + const __m128i c3 = _mm_cvtpd_epi32(k3); + + // Rearrange results and convert down to 16 bits, giving the target output + // ordering + const __m128i c01 = _mm_unpacklo_epi32(c0, c1); + const __m128i c23 = _mm_unpacklo_epi32(c2, c3); + return _mm_packs_epi32(c01, c23); +} + +// Compare two regions of width x height pixels, one rooted at position +// (x, y) in src and the other at (x + u, y + v) in ref. +// This function returns the sum of squared pixel differences between +// the two regions. +// +// TODO(rachelbarker): Test speed/quality impact of using bilinear interpolation +// instad of bicubic interpolation +static INLINE void compute_flow_vector(const uint8_t *src, const uint8_t *ref, + int width, int height, int stride, int x, + int y, double u, double v, + const int16_t *dx, const int16_t *dy, + int *b) { + const __m256i zero = _mm256_setzero_si256(); + + // Accumulate 8 32-bit partial sums for each element of b + // These will be flattened at the end. + __m256i b0_acc = _mm256_setzero_si256(); + __m256i b1_acc = _mm256_setzero_si256(); + + // Split offset into integer and fractional parts, and compute cubic + // interpolation kernels + const int u_int = (int)floor(u); + const int v_int = (int)floor(v); + const double u_frac = u - floor(u); + const double v_frac = v - floor(v); + + const __m128i kernels = compute_cubic_kernels(u_frac, v_frac); + + // Storage for intermediate values between the two convolution directions + // In the AVX2 implementation, this needs a dummy row at the end, because + // we generate 2 rows at a time but the total number of rows is odd. + // So we generate one more row than we actually need. + DECLARE_ALIGNED(32, int16_t, + tmp_[DISFLOW_PATCH_SIZE * (DISFLOW_PATCH_SIZE + 4)]); + int16_t *tmp = tmp_ + DISFLOW_PATCH_SIZE; // Offset by one row + + // Clamp coordinates so that all pixels we fetch will remain within the + // allocated border region, but allow them to go far enough out that + // the border pixels' values do not change. + // Since we are calculating an 8x8 block, the bottom-right pixel + // in the block has coordinates (x0 + 7, y0 + 7). Then, the cubic + // interpolation has 4 taps, meaning that the output of pixel + // (x_w, y_w) depends on the pixels in the range + // ([x_w - 1, x_w + 2], [y_w - 1, y_w + 2]). + // + // Thus the most extreme coordinates which will be fetched are + // (x0 - 1, y0 - 1) and (x0 + 9, y0 + 9). + const int x0 = clamp(x + u_int, -9, width); + const int y0 = clamp(y + v_int, -9, height); + + // Horizontal convolution + + // Prepare the kernel vectors + // We split the kernel into two vectors with kernel indices: + // 0, 1, 0, 1, 0, 1, 0, 1, and + // 2, 3, 2, 3, 2, 3, 2, 3 + __m256i h_kernel_01 = _mm256_broadcastd_epi32(kernels); + __m256i h_kernel_23 = _mm256_broadcastd_epi32(_mm_srli_si128(kernels, 8)); + + __m256i round_const_h = _mm256_set1_epi32(1 << (DISFLOW_INTERP_BITS - 6 - 1)); + + for (int i = -1; i < DISFLOW_PATCH_SIZE + 2; i += 2) { + const int y_w = y0 + i; + const uint8_t *ref_row = &ref[y_w * stride + (x0 - 1)]; + int16_t *tmp_row = &tmp[i * DISFLOW_PATCH_SIZE]; + + // Load this row of pixels. + // For an 8x8 patch, we need to load the 8 image pixels + 3 extras, + // for a total of 11 pixels. Here we load 16 pixels, but only use + // the first 11. + __m256i row = + yy_loadu2_128((__m128i *)(ref_row + stride), (__m128i *)ref_row); + + // Expand pixels to int16s + // We must use unpacks here, as we have one row in each 128-bit lane + // and want to handle each of those independently. + // This is in contrast to _mm256_cvtepu8_epi16(), which takes a single + // 128-bit input and widens it to 256 bits. + __m256i px_0to7_i16 = _mm256_unpacklo_epi8(row, zero); + __m256i px_4to10_i16 = + _mm256_unpacklo_epi8(_mm256_srli_si256(row, 4), zero); + + // Compute first four outputs + // input pixels 0, 1, 1, 2, 2, 3, 3, 4 + // * kernel 0, 1, 0, 1, 0, 1, 0, 1 + __m256i px0 = + _mm256_unpacklo_epi16(px_0to7_i16, _mm256_srli_si256(px_0to7_i16, 2)); + // input pixels 2, 3, 3, 4, 4, 5, 5, 6 + // * kernel 2, 3, 2, 3, 2, 3, 2, 3 + __m256i px1 = _mm256_unpacklo_epi16(_mm256_srli_si256(px_0to7_i16, 4), + _mm256_srli_si256(px_0to7_i16, 6)); + // Convolve with kernel and sum 2x2 boxes to form first 4 outputs + __m256i sum0 = _mm256_add_epi32(_mm256_madd_epi16(px0, h_kernel_01), + _mm256_madd_epi16(px1, h_kernel_23)); + + __m256i out0 = _mm256_srai_epi32(_mm256_add_epi32(sum0, round_const_h), + DISFLOW_INTERP_BITS - 6); + + // Compute second four outputs + __m256i px2 = + _mm256_unpacklo_epi16(px_4to10_i16, _mm256_srli_si256(px_4to10_i16, 2)); + __m256i px3 = _mm256_unpacklo_epi16(_mm256_srli_si256(px_4to10_i16, 4), + _mm256_srli_si256(px_4to10_i16, 6)); + __m256i sum1 = _mm256_add_epi32(_mm256_madd_epi16(px2, h_kernel_01), + _mm256_madd_epi16(px3, h_kernel_23)); + + // Round by just enough bits that the result is + // guaranteed to fit into an i16. Then the next stage can use 16 x 16 -> 32 + // bit multiplies, which should be a fair bit faster than 32 x 32 -> 32 + // as it does now + // This means shifting down so we have 6 extra bits, for a maximum value + // of +18360, which can occur if u_frac == 0.5 and the input pixels are + // {0, 255, 255, 0}. + __m256i out1 = _mm256_srai_epi32(_mm256_add_epi32(sum1, round_const_h), + DISFLOW_INTERP_BITS - 6); + + _mm256_storeu_si256((__m256i *)tmp_row, _mm256_packs_epi32(out0, out1)); + } + + // Vertical convolution + const int round_bits = DISFLOW_INTERP_BITS + 6 - DISFLOW_DERIV_SCALE_LOG2; + __m256i round_const_v = _mm256_set1_epi32(1 << (round_bits - 1)); + + __m256i v_kernel_01 = _mm256_broadcastd_epi32(_mm_srli_si128(kernels, 4)); + __m256i v_kernel_23 = _mm256_broadcastd_epi32(_mm_srli_si128(kernels, 12)); + + for (int i = 0; i < DISFLOW_PATCH_SIZE; i += 2) { + int16_t *tmp_row = &tmp[i * DISFLOW_PATCH_SIZE]; + + // Load 5 rows of 8 x 16-bit values, and pack into 4 registers + // holding rows {0, 1}, {1, 2}, {2, 3}, {3, 4} + __m128i row0 = _mm_loadu_si128((__m128i *)(tmp_row - DISFLOW_PATCH_SIZE)); + __m128i row1 = _mm_loadu_si128((__m128i *)tmp_row); + __m128i row2 = _mm_loadu_si128((__m128i *)(tmp_row + DISFLOW_PATCH_SIZE)); + __m128i row3 = + _mm_loadu_si128((__m128i *)(tmp_row + 2 * DISFLOW_PATCH_SIZE)); + __m128i row4 = + _mm_loadu_si128((__m128i *)(tmp_row + 3 * DISFLOW_PATCH_SIZE)); + + __m256i px0 = _mm256_set_m128i(row1, row0); + __m256i px1 = _mm256_set_m128i(row2, row1); + __m256i px2 = _mm256_set_m128i(row3, row2); + __m256i px3 = _mm256_set_m128i(row4, row3); + + // We want to calculate px0 * v_kernel[0] + px1 * v_kernel[1] + ... , + // but each multiply expands its output to 32 bits. So we need to be + // a little clever about how we do this + __m256i sum0 = _mm256_add_epi32( + _mm256_madd_epi16(_mm256_unpacklo_epi16(px0, px1), v_kernel_01), + _mm256_madd_epi16(_mm256_unpacklo_epi16(px2, px3), v_kernel_23)); + __m256i sum1 = _mm256_add_epi32( + _mm256_madd_epi16(_mm256_unpackhi_epi16(px0, px1), v_kernel_01), + _mm256_madd_epi16(_mm256_unpackhi_epi16(px2, px3), v_kernel_23)); + + __m256i sum0_rounded = + _mm256_srai_epi32(_mm256_add_epi32(sum0, round_const_v), round_bits); + __m256i sum1_rounded = + _mm256_srai_epi32(_mm256_add_epi32(sum1, round_const_v), round_bits); + + __m256i warped = _mm256_packs_epi32(sum0_rounded, sum1_rounded); + __m128i src_pixels_u8 = xx_loadu_2x64(&src[(y + i + 1) * stride + x], + &src[(y + i) * stride + x]); + __m256i src_pixels = + _mm256_slli_epi16(_mm256_cvtepu8_epi16(src_pixels_u8), 3); + + // Calculate delta from the target patch + __m256i dt = _mm256_sub_epi16(warped, src_pixels); + + // Load 2x8 elements each of dx and dt, to pair with the 2x8 elements of dt + // that we have just computed. Then compute 2x8 partial sums of dx * dt + // and dy * dt, implicitly sum to give 2x4 partial sums of each, and + // accumulate. + __m256i dx_row = _mm256_loadu_si256((__m256i *)&dx[i * DISFLOW_PATCH_SIZE]); + __m256i dy_row = _mm256_loadu_si256((__m256i *)&dy[i * DISFLOW_PATCH_SIZE]); + b0_acc = _mm256_add_epi32(b0_acc, _mm256_madd_epi16(dx_row, dt)); + b1_acc = _mm256_add_epi32(b1_acc, _mm256_madd_epi16(dy_row, dt)); + } + + // Flatten the two sets of partial sums to find the final value of b + // We need to set b[0] = sum(b0_acc), b[1] = sum(b1_acc). + // We need to do 14 additions in total; a `hadd` instruction can take care + // of eight of them, then a vertical sum can do four more, leaving two + // scalar additions. + __m256i partial_sum_256 = _mm256_hadd_epi32(b0_acc, b1_acc); + __m128i partial_sum = + _mm_add_epi32(_mm256_extracti128_si256(partial_sum_256, 0), + _mm256_extracti128_si256(partial_sum_256, 1)); + b[0] = _mm_extract_epi32(partial_sum, 0) + _mm_extract_epi32(partial_sum, 1); + b[1] = _mm_extract_epi32(partial_sum, 2) + _mm_extract_epi32(partial_sum, 3); +} + +// Compute the x and y gradients of the source patch in a single pass, +// and store into dx and dy respectively. +static INLINE void sobel_filter(const uint8_t *src, int src_stride, int16_t *dx, + int16_t *dy) { + const __m256i zero = _mm256_setzero_si256(); + + // Loop setup: Load the first two rows (of 10 input rows) and apply + // the horizontal parts of the two filters + __m256i row_m1_0 = + yy_loadu2_128((__m128i *)(src - 1), (__m128i *)(src - src_stride - 1)); + __m256i row_m1_0_a = _mm256_unpacklo_epi8(row_m1_0, zero); + __m256i row_m1_0_b = + _mm256_unpacklo_epi8(_mm256_srli_si256(row_m1_0, 1), zero); + __m256i row_m1_0_c = + _mm256_unpacklo_epi8(_mm256_srli_si256(row_m1_0, 2), zero); + + __m256i row_m1_0_hsmooth = + _mm256_add_epi16(_mm256_add_epi16(row_m1_0_a, row_m1_0_c), + _mm256_slli_epi16(row_m1_0_b, 1)); + __m256i row_m1_0_hdiff = _mm256_sub_epi16(row_m1_0_a, row_m1_0_c); + + // Main loop: For each pair of output rows (i, i+1): + // * Load rows (i+1, i+2) and apply both horizontal filters + // * Apply vertical filters and store results + // * Shift rows for next iteration + for (int i = 0; i < DISFLOW_PATCH_SIZE; i += 2) { + // Load rows (i+1, i+2) and apply both horizontal filters + const __m256i row_p1_p2 = + yy_loadu2_128((__m128i *)(src + (i + 2) * src_stride - 1), + (__m128i *)(src + (i + 1) * src_stride - 1)); + const __m256i row_p1_p2_a = _mm256_unpacklo_epi8(row_p1_p2, zero); + const __m256i row_p1_p2_b = + _mm256_unpacklo_epi8(_mm256_srli_si256(row_p1_p2, 1), zero); + const __m256i row_p1_p2_c = + _mm256_unpacklo_epi8(_mm256_srli_si256(row_p1_p2, 2), zero); + + const __m256i row_p1_p2_hsmooth = + _mm256_add_epi16(_mm256_add_epi16(row_p1_p2_a, row_p1_p2_c), + _mm256_slli_epi16(row_p1_p2_b, 1)); + const __m256i row_p1_p2_hdiff = _mm256_sub_epi16(row_p1_p2_a, row_p1_p2_c); + + // Apply vertical filters and store results + // dx = vertical smooth(horizontal diff(input)) + // dy = vertical diff(horizontal smooth(input)) + const __m256i row_0_p1_hdiff = + _mm256_permute2x128_si256(row_m1_0_hdiff, row_p1_p2_hdiff, 0x21); + const __m256i dx_row = + _mm256_add_epi16(_mm256_add_epi16(row_m1_0_hdiff, row_p1_p2_hdiff), + _mm256_slli_epi16(row_0_p1_hdiff, 1)); + const __m256i dy_row = + _mm256_sub_epi16(row_m1_0_hsmooth, row_p1_p2_hsmooth); + + _mm256_storeu_si256((__m256i *)(dx + i * DISFLOW_PATCH_SIZE), dx_row); + _mm256_storeu_si256((__m256i *)(dy + i * DISFLOW_PATCH_SIZE), dy_row); + + // Shift rows for next iteration + // This allows a lot of work to be reused, reducing the number of + // horizontal filtering operations from 2*3*8 = 48 to 2*10 = 20 + row_m1_0_hsmooth = row_p1_p2_hsmooth; + row_m1_0_hdiff = row_p1_p2_hdiff; + } +} + +static INLINE void compute_flow_matrix(const int16_t *dx, int dx_stride, + const int16_t *dy, int dy_stride, + double *M) { + __m256i acc[4] = { 0 }; + + for (int i = 0; i < DISFLOW_PATCH_SIZE; i += 2) { + __m256i dx_row = _mm256_loadu_si256((__m256i *)&dx[i * dx_stride]); + __m256i dy_row = _mm256_loadu_si256((__m256i *)&dy[i * dy_stride]); + + acc[0] = _mm256_add_epi32(acc[0], _mm256_madd_epi16(dx_row, dx_row)); + acc[1] = _mm256_add_epi32(acc[1], _mm256_madd_epi16(dx_row, dy_row)); + // Don't compute acc[2], as it should be equal to acc[1] + acc[3] = _mm256_add_epi32(acc[3], _mm256_madd_epi16(dy_row, dy_row)); + } + + // Condense sums + __m256i partial_sum_0 = _mm256_hadd_epi32(acc[0], acc[1]); + __m256i partial_sum_1 = _mm256_hadd_epi32(acc[1], acc[3]); + __m256i result_256 = _mm256_hadd_epi32(partial_sum_0, partial_sum_1); + __m128i result = _mm_add_epi32(_mm256_extracti128_si256(result_256, 0), + _mm256_extracti128_si256(result_256, 1)); + + // Apply regularization + // We follow the standard regularization method of adding `k * I` before + // inverting. This ensures that the matrix will be invertible. + // + // Setting the regularization strength k to 1 seems to work well here, as + // typical values coming from the other equations are very large (1e5 to + // 1e6, with an upper limit of around 6e7, at the time of writing). + // It also preserves the property that all matrix values are whole numbers, + // which is convenient for integerized SIMD implementation. + result = _mm_add_epi32(result, _mm_set_epi32(1, 0, 0, 1)); + + // Convert results to doubles and store + _mm256_storeu_pd(M, _mm256_cvtepi32_pd(result)); +} + +// Try to invert the matrix M +// Note: Due to the nature of how a least-squares matrix is constructed, all of +// the eigenvalues will be >= 0, and therefore det M >= 0 as well. +// The regularization term `+ k * I` further ensures that det M >= k^2. +// As mentioned in compute_flow_matrix(), here we use k = 1, so det M >= 1. +// So we don't have to worry about non-invertible matrices here. +static INLINE void invert_2x2(const double *M, double *M_inv) { + double det = (M[0] * M[3]) - (M[1] * M[2]); + assert(det >= 1); + const double det_inv = 1 / det; + + M_inv[0] = M[3] * det_inv; + M_inv[1] = -M[1] * det_inv; + M_inv[2] = -M[2] * det_inv; + M_inv[3] = M[0] * det_inv; +} + +void aom_compute_flow_at_point_avx2(const uint8_t *src, const uint8_t *ref, + int x, int y, int width, int height, + int stride, double *u, double *v) { + DECLARE_ALIGNED(32, double, M[4]); + DECLARE_ALIGNED(32, double, M_inv[4]); + DECLARE_ALIGNED(32, int16_t, dx[DISFLOW_PATCH_SIZE * DISFLOW_PATCH_SIZE]); + DECLARE_ALIGNED(32, int16_t, dy[DISFLOW_PATCH_SIZE * DISFLOW_PATCH_SIZE]); + int b[2]; + + // Compute gradients within this patch + const uint8_t *src_patch = &src[y * stride + x]; + sobel_filter(src_patch, stride, dx, dy); + + compute_flow_matrix(dx, DISFLOW_PATCH_SIZE, dy, DISFLOW_PATCH_SIZE, M); + invert_2x2(M, M_inv); + + for (int itr = 0; itr < DISFLOW_MAX_ITR; itr++) { + compute_flow_vector(src, ref, width, height, stride, x, y, *u, *v, dx, dy, + b); + + // Solve flow equations to find a better estimate for the flow vector + // at this point + const double step_u = M_inv[0] * b[0] + M_inv[1] * b[1]; + const double step_v = M_inv[2] * b[0] + M_inv[3] * b[1]; + *u += fclamp(step_u * DISFLOW_STEP_SIZE, -2, 2); + *v += fclamp(step_v * DISFLOW_STEP_SIZE, -2, 2); + + if (fabs(step_u) + fabs(step_v) < DISFLOW_STEP_SIZE_THRESOLD) { + // Stop iteration when we're close to convergence + break; + } + } +} diff --git a/third_party/aom/aom_dsp/flow_estimation/x86/disflow_sse4.c b/third_party/aom/aom_dsp/flow_estimation/x86/disflow_sse4.c index 2c5effd638..e0a4bd040c 100644 --- a/third_party/aom/aom_dsp/flow_estimation/x86/disflow_sse4.c +++ b/third_party/aom/aom_dsp/flow_estimation/x86/disflow_sse4.c @@ -1,13 +1,12 @@ /* - * Copyright (c) 2022, Alliance for Open Media. All rights reserved + * Copyright (c) 2024, Alliance for Open Media. All rights reserved * - * This source code is subject to the terms of the BSD 3-Clause Clear License - * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear - * License was not distributed with this source code in the LICENSE file, you - * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the - * Alliance for Open Media Patent License 1.0 was not distributed with this - * source code in the PATENTS file, you can obtain it at - * aomedia.org/license/patent-license/. + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ #include @@ -20,46 +19,59 @@ #include "config/aom_dsp_rtcd.h" -// Internal cross-check against C code -// If you set this to 1 and compile in debug mode, then the outputs of the two -// convolution stages will be checked against the plain C version of the code, -// and an assertion will be fired if the results differ. -#define CHECK_RESULTS 0 - -// Note: Max sum(+ve coefficients) = 1.125 * scale -static INLINE void get_cubic_kernel_dbl(double x, double kernel[4]) { - // Check that the fractional position is in range. - // - // Note: x is calculated from, e.g., `u_frac = u - floor(u)`. - // Mathematically, this implies that 0 <= x < 1. However, in practice it is - // possible to have x == 1 due to floating point rounding. This is fine, - // and we still interpolate correctly if we allow x = 1. - assert(0 <= x && x <= 1); - - double x2 = x * x; - double x3 = x2 * x; - kernel[0] = -0.5 * x + x2 - 0.5 * x3; - kernel[1] = 1.0 - 2.5 * x2 + 1.5 * x3; - kernel[2] = 0.5 * x + 2.0 * x2 - 1.5 * x3; - kernel[3] = -0.5 * x2 + 0.5 * x3; -} - -static INLINE void get_cubic_kernel_int(double x, int16_t kernel[4]) { - double kernel_dbl[4]; - get_cubic_kernel_dbl(x, kernel_dbl); - - kernel[0] = (int16_t)rint(kernel_dbl[0] * (1 << DISFLOW_INTERP_BITS)); - kernel[1] = (int16_t)rint(kernel_dbl[1] * (1 << DISFLOW_INTERP_BITS)); - kernel[2] = (int16_t)rint(kernel_dbl[2] * (1 << DISFLOW_INTERP_BITS)); - kernel[3] = (int16_t)rint(kernel_dbl[3] * (1 << DISFLOW_INTERP_BITS)); -} - -#if CHECK_RESULTS -static INLINE int get_cubic_value_int(const int *p, const int16_t kernel[4]) { - return kernel[0] * p[0] + kernel[1] * p[1] + kernel[2] * p[2] + - kernel[3] * p[3]; +#if DISFLOW_PATCH_SIZE != 8 +#error "Need to change disflow_sse4.c if DISFLOW_PATCH_SIZE != 8" +#endif + +// Compute horizontal and vertical kernels and return them packed into a +// register. The coefficient ordering is: +// h0, h1, v0, v1, h2, h3, v2, v3 +// This is chosen because it takes less work than fully separating the kernels, +// but it is separated enough that we can pick out each coefficient pair in the +// main compute_flow_at_point function +static INLINE __m128i compute_cubic_kernels(double u, double v) { + const __m128d x = _mm_set_pd(v, u); + + const __m128d x2 = _mm_mul_pd(x, x); + const __m128d x3 = _mm_mul_pd(x2, x); + + // Macro to multiply a value v by a constant coefficient c +#define MULC(c, v) _mm_mul_pd(_mm_set1_pd(c), v) + + // Compute floating-point kernel + // Note: To ensure results are bit-identical to the C code, we need to perform + // exactly the same sequence of operations here as in the C code. + __m128d k0 = _mm_sub_pd(_mm_add_pd(MULC(-0.5, x), x2), MULC(0.5, x3)); + __m128d k1 = + _mm_add_pd(_mm_sub_pd(_mm_set1_pd(1.0), MULC(2.5, x2)), MULC(1.5, x3)); + __m128d k2 = + _mm_sub_pd(_mm_add_pd(MULC(0.5, x), MULC(2.0, x2)), MULC(1.5, x3)); + __m128d k3 = _mm_add_pd(MULC(-0.5, x2), MULC(0.5, x3)); +#undef MULC + + // Integerize + __m128d prec = _mm_set1_pd((double)(1 << DISFLOW_INTERP_BITS)); + + k0 = _mm_round_pd(_mm_mul_pd(k0, prec), + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + k1 = _mm_round_pd(_mm_mul_pd(k1, prec), + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + k2 = _mm_round_pd(_mm_mul_pd(k2, prec), + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + k3 = _mm_round_pd(_mm_mul_pd(k3, prec), + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + + const __m128i c0 = _mm_cvtpd_epi32(k0); + const __m128i c1 = _mm_cvtpd_epi32(k1); + const __m128i c2 = _mm_cvtpd_epi32(k2); + const __m128i c3 = _mm_cvtpd_epi32(k3); + + // Rearrange results and convert down to 16 bits, giving the target output + // ordering + const __m128i c01 = _mm_unpacklo_epi32(c0, c1); + const __m128i c23 = _mm_unpacklo_epi32(c2, c3); + return _mm_packs_epi32(c01, c23); } -#endif // CHECK_RESULTS // Compare two regions of width x height pixels, one rooted at position // (x, y) in src and the other at (x + u, y + v) in ref. @@ -80,10 +92,6 @@ static INLINE void compute_flow_vector(const uint8_t *src, const uint8_t *ref, // These will be flattened at the end. __m128i b0_acc = _mm_setzero_si128(); __m128i b1_acc = _mm_setzero_si128(); -#if CHECK_RESULTS - // Also keep a running sum using the C algorithm, for cross-checking - int c_result[2] = { 0 }; -#endif // CHECK_RESULTS // Split offset into integer and fractional parts, and compute cubic // interpolation kernels @@ -92,13 +100,11 @@ static INLINE void compute_flow_vector(const uint8_t *src, const uint8_t *ref, const double u_frac = u - floor(u); const double v_frac = v - floor(v); - int16_t h_kernel[4]; - int16_t v_kernel[4]; - get_cubic_kernel_int(u_frac, h_kernel); - get_cubic_kernel_int(v_frac, v_kernel); + const __m128i kernels = compute_cubic_kernels(u_frac, v_frac); // Storage for intermediate values between the two convolution directions - int16_t tmp_[DISFLOW_PATCH_SIZE * (DISFLOW_PATCH_SIZE + 3)]; + DECLARE_ALIGNED(16, int16_t, + tmp_[DISFLOW_PATCH_SIZE * (DISFLOW_PATCH_SIZE + 3)]); int16_t *tmp = tmp_ + DISFLOW_PATCH_SIZE; // Offset by one row // Clamp coordinates so that all pixels we fetch will remain within the @@ -121,8 +127,8 @@ static INLINE void compute_flow_vector(const uint8_t *src, const uint8_t *ref, // We split the kernel into two vectors with kernel indices: // 0, 1, 0, 1, 0, 1, 0, 1, and // 2, 3, 2, 3, 2, 3, 2, 3 - __m128i h_kernel_01 = xx_set2_epi16(h_kernel[0], h_kernel[1]); - __m128i h_kernel_23 = xx_set2_epi16(h_kernel[2], h_kernel[3]); + __m128i h_kernel_01 = _mm_set1_epi32(_mm_extract_epi32(kernels, 0)); + __m128i h_kernel_23 = _mm_set1_epi32(_mm_extract_epi32(kernels, 2)); __m128i round_const_h = _mm_set1_epi32(1 << (DISFLOW_INTERP_BITS - 6 - 1)); @@ -141,10 +147,6 @@ static INLINE void compute_flow_vector(const uint8_t *src, const uint8_t *ref, __m128i px_0to7_i16 = _mm_cvtepu8_epi16(row); __m128i px_4to10_i16 = _mm_cvtepu8_epi16(_mm_srli_si128(row, 4)); - // Relevant multiply instruction - // This multiplies pointwise, then sums in pairs. - //_mm_madd_epi16(); - // Compute first four outputs // input pixels 0, 1, 1, 2, 2, 3, 3, 4 // * kernel 0, 1, 0, 1, 0, 1, 0, 1 @@ -180,43 +182,14 @@ static INLINE void compute_flow_vector(const uint8_t *src, const uint8_t *ref, DISFLOW_INTERP_BITS - 6); _mm_storeu_si128((__m128i *)tmp_row, _mm_packs_epi32(out0, out1)); - -#if CHECK_RESULTS && !defined(NDEBUG) - // Cross-check - for (int j = 0; j < DISFLOW_PATCH_SIZE; ++j) { - const int x_w = x0 + j; - int arr[4]; - - arr[0] = (int)ref[y_w * stride + (x_w - 1)]; - arr[1] = (int)ref[y_w * stride + (x_w + 0)]; - arr[2] = (int)ref[y_w * stride + (x_w + 1)]; - arr[3] = (int)ref[y_w * stride + (x_w + 2)]; - - // Apply kernel and round, keeping 6 extra bits of precision. - // - // 6 is the maximum allowable number of extra bits which will avoid - // the intermediate values overflowing an int16_t. The most extreme - // intermediate value occurs when: - // * The input pixels are [0, 255, 255, 0] - // * u_frac = 0.5 - // In this case, the un-scaled output is 255 * 1.125 = 286.875. - // As an integer with 6 fractional bits, that is 18360, which fits - // in an int16_t. But with 7 fractional bits it would be 36720, - // which is too large. - const int c_value = ROUND_POWER_OF_TWO(get_cubic_value_int(arr, h_kernel), - DISFLOW_INTERP_BITS - 6); - (void)c_value; // Suppress warnings - assert(tmp_row[j] == c_value); - } -#endif // CHECK_RESULTS } // Vertical convolution const int round_bits = DISFLOW_INTERP_BITS + 6 - DISFLOW_DERIV_SCALE_LOG2; __m128i round_const_v = _mm_set1_epi32(1 << (round_bits - 1)); - __m128i v_kernel_01 = xx_set2_epi16(v_kernel[0], v_kernel[1]); - __m128i v_kernel_23 = xx_set2_epi16(v_kernel[2], v_kernel[3]); + __m128i v_kernel_01 = _mm_set1_epi32(_mm_extract_epi32(kernels, 1)); + __m128i v_kernel_23 = _mm_set1_epi32(_mm_extract_epi32(kernels, 3)); for (int i = 0; i < DISFLOW_PATCH_SIZE; ++i) { int16_t *tmp_row = &tmp[i * DISFLOW_PATCH_SIZE]; @@ -259,30 +232,6 @@ static INLINE void compute_flow_vector(const uint8_t *src, const uint8_t *ref, __m128i dy_row = _mm_loadu_si128((__m128i *)&dy[i * DISFLOW_PATCH_SIZE]); b0_acc = _mm_add_epi32(b0_acc, _mm_madd_epi16(dx_row, dt)); b1_acc = _mm_add_epi32(b1_acc, _mm_madd_epi16(dy_row, dt)); - -#if CHECK_RESULTS - int16_t dt_arr[8]; - memcpy(dt_arr, &dt, 8 * sizeof(*dt_arr)); - for (int j = 0; j < DISFLOW_PATCH_SIZE; ++j) { - int16_t *p = &tmp[i * DISFLOW_PATCH_SIZE + j]; - int arr[4] = { p[-DISFLOW_PATCH_SIZE], p[0], p[DISFLOW_PATCH_SIZE], - p[2 * DISFLOW_PATCH_SIZE] }; - const int result = get_cubic_value_int(arr, v_kernel); - - // Apply kernel and round. - // This time, we have to round off the 6 extra bits which were kept - // earlier, but we also want to keep DISFLOW_DERIV_SCALE_LOG2 extra bits - // of precision to match the scale of the dx and dy arrays. - const int c_warped = ROUND_POWER_OF_TWO(result, round_bits); - const int c_src_px = src[(x + j) + (y + i) * stride] << 3; - const int c_dt = c_warped - c_src_px; - - assert(dt_arr[j] == c_dt); - - c_result[0] += dx[i * DISFLOW_PATCH_SIZE + j] * c_dt; - c_result[1] += dy[i * DISFLOW_PATCH_SIZE + j] * c_dt; - } -#endif // CHECK_RESULTS } // Flatten the two sets of partial sums to find the final value of b @@ -292,156 +241,66 @@ static INLINE void compute_flow_vector(const uint8_t *src, const uint8_t *ref, __m128i partial_sum = _mm_hadd_epi32(b0_acc, b1_acc); b[0] = _mm_extract_epi32(partial_sum, 0) + _mm_extract_epi32(partial_sum, 1); b[1] = _mm_extract_epi32(partial_sum, 2) + _mm_extract_epi32(partial_sum, 3); - -#if CHECK_RESULTS - assert(b[0] == c_result[0]); - assert(b[1] == c_result[1]); -#endif // CHECK_RESULTS } -static INLINE void sobel_filter_x(const uint8_t *src, int src_stride, - int16_t *dst, int dst_stride) { - int16_t tmp_[DISFLOW_PATCH_SIZE * (DISFLOW_PATCH_SIZE + 2)]; - int16_t *tmp = tmp_ + DISFLOW_PATCH_SIZE; -#if CHECK_RESULTS - const int taps = 3; -#endif // CHECK_RESULTS - - // Horizontal filter - // As the kernel is simply {1, 0, -1}, we implement this as simply - // out[x] = image[x-1] - image[x+1] - // rather than doing a "proper" convolution operation - for (int y = -1; y < DISFLOW_PATCH_SIZE + 1; ++y) { - const uint8_t *src_row = src + y * src_stride; - int16_t *tmp_row = tmp + y * DISFLOW_PATCH_SIZE; - - // Load pixels and expand to 16 bits - __m128i row = _mm_loadu_si128((__m128i *)(src_row - 1)); - __m128i px0 = _mm_cvtepu8_epi16(row); - __m128i px2 = _mm_cvtepu8_epi16(_mm_srli_si128(row, 2)); - - __m128i out = _mm_sub_epi16(px0, px2); - - // Store to intermediate array - _mm_storeu_si128((__m128i *)tmp_row, out); - -#if CHECK_RESULTS - // Cross-check - static const int16_t h_kernel[3] = { 1, 0, -1 }; - for (int x = 0; x < DISFLOW_PATCH_SIZE; ++x) { - int sum = 0; - for (int k = 0; k < taps; ++k) { - sum += h_kernel[k] * src_row[x + k - 1]; - } - (void)sum; - assert(tmp_row[x] == sum); - } -#endif // CHECK_RESULTS - } - - // Vertical filter - // Here the kernel is {1, 2, 1}, which can be implemented - // with simple sums rather than multiplies and adds. - // In order to minimize dependency chains, we evaluate in the order - // (image[y - 1] + image[y + 1]) + (image[y] << 1) - // This way, the first addition and the shift can happen in parallel - for (int y = 0; y < DISFLOW_PATCH_SIZE; ++y) { - const int16_t *tmp_row = tmp + y * DISFLOW_PATCH_SIZE; - int16_t *dst_row = dst + y * dst_stride; - - __m128i px0 = _mm_loadu_si128((__m128i *)(tmp_row - DISFLOW_PATCH_SIZE)); - __m128i px1 = _mm_loadu_si128((__m128i *)tmp_row); - __m128i px2 = _mm_loadu_si128((__m128i *)(tmp_row + DISFLOW_PATCH_SIZE)); - - __m128i out = - _mm_add_epi16(_mm_add_epi16(px0, px2), _mm_slli_epi16(px1, 1)); - - _mm_storeu_si128((__m128i *)dst_row, out); - -#if CHECK_RESULTS - static const int16_t v_kernel[3] = { 1, 2, 1 }; - for (int x = 0; x < DISFLOW_PATCH_SIZE; ++x) { - int sum = 0; - for (int k = 0; k < taps; ++k) { - sum += v_kernel[k] * tmp[(y + k - 1) * DISFLOW_PATCH_SIZE + x]; - } - (void)sum; - assert(dst_row[x] == sum); - } -#endif // CHECK_RESULTS - } -} - -static INLINE void sobel_filter_y(const uint8_t *src, int src_stride, - int16_t *dst, int dst_stride) { - int16_t tmp_[DISFLOW_PATCH_SIZE * (DISFLOW_PATCH_SIZE + 2)]; - int16_t *tmp = tmp_ + DISFLOW_PATCH_SIZE; -#if CHECK_RESULTS - const int taps = 3; -#endif // CHECK_RESULTS - - // Horizontal filter - // Here the kernel is {1, 2, 1}, which can be implemented - // with simple sums rather than multiplies and adds. - // In order to minimize dependency chains, we evaluate in the order - // (image[y - 1] + image[y + 1]) + (image[y] << 1) - // This way, the first addition and the shift can happen in parallel - for (int y = -1; y < DISFLOW_PATCH_SIZE + 1; ++y) { - const uint8_t *src_row = src + y * src_stride; - int16_t *tmp_row = tmp + y * DISFLOW_PATCH_SIZE; - - // Load pixels and expand to 16 bits - __m128i row = _mm_loadu_si128((__m128i *)(src_row - 1)); - __m128i px0 = _mm_cvtepu8_epi16(row); - __m128i px1 = _mm_cvtepu8_epi16(_mm_srli_si128(row, 1)); - __m128i px2 = _mm_cvtepu8_epi16(_mm_srli_si128(row, 2)); - - __m128i out = - _mm_add_epi16(_mm_add_epi16(px0, px2), _mm_slli_epi16(px1, 1)); - - // Store to intermediate array - _mm_storeu_si128((__m128i *)tmp_row, out); - -#if CHECK_RESULTS - // Cross-check - static const int16_t h_kernel[3] = { 1, 2, 1 }; - for (int x = 0; x < DISFLOW_PATCH_SIZE; ++x) { - int sum = 0; - for (int k = 0; k < taps; ++k) { - sum += h_kernel[k] * src_row[x + k - 1]; - } - (void)sum; - assert(tmp_row[x] == sum); - } -#endif // CHECK_RESULTS - } - - // Vertical filter - // As the kernel is simply {1, 0, -1}, we implement this as simply - // out[x] = image[x-1] - image[x+1] - // rather than doing a "proper" convolution operation - for (int y = 0; y < DISFLOW_PATCH_SIZE; ++y) { - const int16_t *tmp_row = tmp + y * DISFLOW_PATCH_SIZE; - int16_t *dst_row = dst + y * dst_stride; - - __m128i px0 = _mm_loadu_si128((__m128i *)(tmp_row - DISFLOW_PATCH_SIZE)); - __m128i px2 = _mm_loadu_si128((__m128i *)(tmp_row + DISFLOW_PATCH_SIZE)); - - __m128i out = _mm_sub_epi16(px0, px2); - - _mm_storeu_si128((__m128i *)dst_row, out); - -#if CHECK_RESULTS - static const int16_t v_kernel[3] = { 1, 0, -1 }; - for (int x = 0; x < DISFLOW_PATCH_SIZE; ++x) { - int sum = 0; - for (int k = 0; k < taps; ++k) { - sum += v_kernel[k] * tmp[(y + k - 1) * DISFLOW_PATCH_SIZE + x]; - } - (void)sum; - assert(dst_row[x] == sum); - } -#endif // CHECK_RESULTS +// Compute the x and y gradients of the source patch in a single pass, +// and store into dx and dy respectively. +static INLINE void sobel_filter(const uint8_t *src, int src_stride, int16_t *dx, + int16_t *dy) { + // Loop setup: Load the first two rows (of 10 input rows) and apply + // the horizontal parts of the two filters + __m128i row_m1 = _mm_loadu_si128((__m128i *)(src - src_stride - 1)); + __m128i row_m1_a = _mm_cvtepu8_epi16(row_m1); + __m128i row_m1_b = _mm_cvtepu8_epi16(_mm_srli_si128(row_m1, 1)); + __m128i row_m1_c = _mm_cvtepu8_epi16(_mm_srli_si128(row_m1, 2)); + + __m128i row_m1_hsmooth = _mm_add_epi16(_mm_add_epi16(row_m1_a, row_m1_c), + _mm_slli_epi16(row_m1_b, 1)); + __m128i row_m1_hdiff = _mm_sub_epi16(row_m1_a, row_m1_c); + + __m128i row = _mm_loadu_si128((__m128i *)(src - 1)); + __m128i row_a = _mm_cvtepu8_epi16(row); + __m128i row_b = _mm_cvtepu8_epi16(_mm_srli_si128(row, 1)); + __m128i row_c = _mm_cvtepu8_epi16(_mm_srli_si128(row, 2)); + + __m128i row_hsmooth = + _mm_add_epi16(_mm_add_epi16(row_a, row_c), _mm_slli_epi16(row_b, 1)); + __m128i row_hdiff = _mm_sub_epi16(row_a, row_c); + + // Main loop: For each of the 8 output rows: + // * Load row i+1 and apply both horizontal filters + // * Apply vertical filters and store results + // * Shift rows for next iteration + for (int i = 0; i < DISFLOW_PATCH_SIZE; i++) { + // Load row i+1 and apply both horizontal filters + const __m128i row_p1 = + _mm_loadu_si128((__m128i *)(src + (i + 1) * src_stride - 1)); + const __m128i row_p1_a = _mm_cvtepu8_epi16(row_p1); + const __m128i row_p1_b = _mm_cvtepu8_epi16(_mm_srli_si128(row_p1, 1)); + const __m128i row_p1_c = _mm_cvtepu8_epi16(_mm_srli_si128(row_p1, 2)); + + const __m128i row_p1_hsmooth = _mm_add_epi16( + _mm_add_epi16(row_p1_a, row_p1_c), _mm_slli_epi16(row_p1_b, 1)); + const __m128i row_p1_hdiff = _mm_sub_epi16(row_p1_a, row_p1_c); + + // Apply vertical filters and store results + // dx = vertical smooth(horizontal diff(input)) + // dy = vertical diff(horizontal smooth(input)) + const __m128i dx_row = + _mm_add_epi16(_mm_add_epi16(row_m1_hdiff, row_p1_hdiff), + _mm_slli_epi16(row_hdiff, 1)); + const __m128i dy_row = _mm_sub_epi16(row_m1_hsmooth, row_p1_hsmooth); + + _mm_storeu_si128((__m128i *)(dx + i * DISFLOW_PATCH_SIZE), dx_row); + _mm_storeu_si128((__m128i *)(dy + i * DISFLOW_PATCH_SIZE), dy_row); + + // Shift rows for next iteration + // This allows a lot of work to be reused, reducing the number of + // horizontal filtering operations from 2*3*8 = 48 to 2*10 = 20 + row_m1_hsmooth = row_hsmooth; + row_m1_hdiff = row_hdiff; + row_hsmooth = row_p1_hsmooth; + row_hdiff = row_p1_hdiff; } } @@ -476,30 +335,6 @@ static INLINE void compute_flow_matrix(const int16_t *dx, int dx_stride, // which is convenient for integerized SIMD implementation. result = _mm_add_epi32(result, _mm_set_epi32(1, 0, 0, 1)); -#if CHECK_RESULTS - int tmp[4] = { 0 }; - - for (int i = 0; i < DISFLOW_PATCH_SIZE; i++) { - for (int j = 0; j < DISFLOW_PATCH_SIZE; j++) { - tmp[0] += dx[i * dx_stride + j] * dx[i * dx_stride + j]; - tmp[1] += dx[i * dx_stride + j] * dy[i * dy_stride + j]; - // Don't compute tmp[2], as it should be equal to tmp[1] - tmp[3] += dy[i * dy_stride + j] * dy[i * dy_stride + j]; - } - } - - // Apply regularization - tmp[0] += 1; - tmp[3] += 1; - - tmp[2] = tmp[1]; - - assert(tmp[0] == _mm_extract_epi32(result, 0)); - assert(tmp[1] == _mm_extract_epi32(result, 1)); - assert(tmp[2] == _mm_extract_epi32(result, 2)); - assert(tmp[3] == _mm_extract_epi32(result, 3)); -#endif // CHECK_RESULTS - // Convert results to doubles and store _mm_storeu_pd(M, _mm_cvtepi32_pd(result)); _mm_storeu_pd(M + 2, _mm_cvtepi32_pd(_mm_srli_si128(result, 8))); @@ -525,16 +360,15 @@ static INLINE void invert_2x2(const double *M, double *M_inv) { void aom_compute_flow_at_point_sse4_1(const uint8_t *src, const uint8_t *ref, int x, int y, int width, int height, int stride, double *u, double *v) { - double M[4]; - double M_inv[4]; + DECLARE_ALIGNED(16, double, M[4]); + DECLARE_ALIGNED(16, double, M_inv[4]); + DECLARE_ALIGNED(16, int16_t, dx[DISFLOW_PATCH_SIZE * DISFLOW_PATCH_SIZE]); + DECLARE_ALIGNED(16, int16_t, dy[DISFLOW_PATCH_SIZE * DISFLOW_PATCH_SIZE]); int b[2]; - int16_t dx[DISFLOW_PATCH_SIZE * DISFLOW_PATCH_SIZE]; - int16_t dy[DISFLOW_PATCH_SIZE * DISFLOW_PATCH_SIZE]; // Compute gradients within this patch const uint8_t *src_patch = &src[y * stride + x]; - sobel_filter_x(src_patch, stride, dx, DISFLOW_PATCH_SIZE); - sobel_filter_y(src_patch, stride, dy, DISFLOW_PATCH_SIZE); + sobel_filter(src_patch, stride, dx, dy); compute_flow_matrix(dx, DISFLOW_PATCH_SIZE, dy, DISFLOW_PATCH_SIZE, M); invert_2x2(M, M_inv); diff --git a/third_party/aom/aom_dsp/mathutils.h b/third_party/aom/aom_dsp/mathutils.h index cbb6cf491f..26635fc4d1 100644 --- a/third_party/aom/aom_dsp/mathutils.h +++ b/third_party/aom/aom_dsp/mathutils.h @@ -17,7 +17,6 @@ #include #include "aom_dsp/aom_dsp_common.h" -#include "aom_mem/aom_mem.h" static const double TINY_NEAR_ZERO = 1.0E-16; diff --git a/third_party/aom/aom_dsp/noise_model.c b/third_party/aom/aom_dsp/noise_model.c index 065ec9a106..947dfd3c7a 100644 --- a/third_party/aom/aom_dsp/noise_model.c +++ b/third_party/aom/aom_dsp/noise_model.c @@ -19,6 +19,8 @@ #include "aom_dsp/noise_model.h" #include "aom_dsp/noise_util.h" #include "aom_mem/aom_mem.h" +#include "aom_ports/mem.h" +#include "aom_scale/yv12config.h" #define kLowPolyNumParams 3 @@ -1555,7 +1557,7 @@ void aom_denoise_and_model_free(struct aom_denoise_and_model_t *ctx) { } static int denoise_and_model_realloc_if_necessary( - struct aom_denoise_and_model_t *ctx, YV12_BUFFER_CONFIG *sd) { + struct aom_denoise_and_model_t *ctx, const YV12_BUFFER_CONFIG *sd) { if (ctx->width == sd->y_width && ctx->height == sd->y_height && ctx->y_stride == sd->y_stride && ctx->uv_stride == sd->uv_stride) return 1; @@ -1624,7 +1626,7 @@ static int denoise_and_model_realloc_if_necessary( // TODO(aomedia:3151): Handle a monochrome image (sd->u_buffer and sd->v_buffer // are null pointers) correctly. int aom_denoise_and_model_run(struct aom_denoise_and_model_t *ctx, - YV12_BUFFER_CONFIG *sd, + const YV12_BUFFER_CONFIG *sd, aom_film_grain_t *film_grain, int apply_denoise) { const int block_size = ctx->block_size; const int use_highbd = (sd->flags & YV12_FLAG_HIGHBITDEPTH) != 0; diff --git a/third_party/aom/aom_dsp/noise_model.h b/third_party/aom/aom_dsp/noise_model.h index 8228aeacfc..5b2d7efe29 100644 --- a/third_party/aom/aom_dsp/noise_model.h +++ b/third_party/aom/aom_dsp/noise_model.h @@ -297,14 +297,14 @@ struct aom_denoise_and_model_t; * aom_denoise_and_model_alloc that holds some * buffers for denoising and the current noise * estimate. - * \param[in,out] buf The raw input buffer to be denoised. + * \param[in,out] sd The raw input buffer to be denoised. * \param[out] grain Output film grain parameters * \param[in] apply_denoise Whether or not to apply the denoising to the * frame that will be encoded */ int aom_denoise_and_model_run(struct aom_denoise_and_model_t *ctx, - YV12_BUFFER_CONFIG *buf, aom_film_grain_t *grain, - int apply_denoise); + const YV12_BUFFER_CONFIG *sd, + aom_film_grain_t *grain, int apply_denoise); /*!\brief Allocates a context that can be used for denoising and noise modeling. * diff --git a/third_party/aom/aom_dsp/pyramid.c b/third_party/aom/aom_dsp/pyramid.c index 324a18baea..5de001dbd5 100644 --- a/third_party/aom/aom_dsp/pyramid.c +++ b/third_party/aom/aom_dsp/pyramid.c @@ -12,7 +12,7 @@ #include "aom_dsp/pyramid.h" #include "aom_mem/aom_mem.h" #include "aom_ports/bitops.h" -#include "aom_util/aom_thread.h" +#include "aom_util/aom_pthread.h" // TODO(rachelbarker): Move needed code from av1/ to aom_dsp/ #include "av1/common/resize.h" @@ -26,18 +26,16 @@ // levels. This is counted in the size checked against the max allocation // limit // * Then calls aom_alloc_pyramid() to actually create the pyramid -// * Pyramid is initially marked as invalid (no data) -// * Whenever pyramid is needed, we check the valid flag. If set, use existing -// data. If not set, compute full pyramid -// * Whenever frame buffer is reused, clear the valid flag +// * Pyramid is initially marked as containing no valid data +// * Each pyramid layer is computed on-demand, the first time it is requested +// * Whenever frame buffer is reused, reset the counter of filled levels. +// This invalidates all of the existing pyramid levels. // * Whenever frame buffer is resized, reallocate pyramid -size_t aom_get_pyramid_alloc_size(int width, int height, int n_levels, - bool image_is_16bit) { - // Limit number of levels on small frames +size_t aom_get_pyramid_alloc_size(int width, int height, bool image_is_16bit) { + // Allocate the maximum possible number of layers for this width and height const int msb = get_msb(AOMMIN(width, height)); - const int max_levels = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1); - n_levels = AOMMIN(n_levels, max_levels); + const int n_levels = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1); size_t alloc_size = 0; alloc_size += sizeof(ImagePyramid); @@ -100,12 +98,10 @@ size_t aom_get_pyramid_alloc_size(int width, int height, int n_levels, return alloc_size; } -ImagePyramid *aom_alloc_pyramid(int width, int height, int n_levels, - bool image_is_16bit) { - // Limit number of levels on small frames +ImagePyramid *aom_alloc_pyramid(int width, int height, bool image_is_16bit) { + // Allocate the maximum possible number of layers for this width and height const int msb = get_msb(AOMMIN(width, height)); - const int max_levels = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1); - n_levels = AOMMIN(n_levels, max_levels); + const int n_levels = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1); ImagePyramid *pyr = aom_calloc(1, sizeof(*pyr)); if (!pyr) { @@ -118,8 +114,8 @@ ImagePyramid *aom_alloc_pyramid(int width, int height, int n_levels, return NULL; } - pyr->valid = false; - pyr->n_levels = n_levels; + pyr->max_levels = n_levels; + pyr->filled_levels = 0; // Compute sizes and offsets for each pyramid level // These are gathered up first, so that we can allocate all pyramid levels @@ -248,46 +244,67 @@ static INLINE void fill_border(uint8_t *img_buf, const int width, } } -// Compute coarse to fine pyramids for a frame +// Compute downsampling pyramid for a frame +// +// This function will ensure that the first `n_levels` levels of the pyramid +// are filled, unless the frame is too small to have this many levels. +// In that case, we will fill all available levels and then stop. +// +// Returns the actual number of levels filled, capped at n_levels, +// or -1 on error. +// // This must only be called while holding frame_pyr->mutex -static INLINE bool fill_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, - ImagePyramid *frame_pyr) { - int n_levels = frame_pyr->n_levels; +static INLINE int fill_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, + int n_levels, ImagePyramid *frame_pyr) { + int already_filled_levels = frame_pyr->filled_levels; + + // This condition should already be enforced by aom_compute_pyramid + assert(n_levels <= frame_pyr->max_levels); + + if (already_filled_levels >= n_levels) { + return n_levels; + } + const int frame_width = frame->y_crop_width; const int frame_height = frame->y_crop_height; const int frame_stride = frame->y_stride; assert((frame_width >> n_levels) >= 0); assert((frame_height >> n_levels) >= 0); - PyramidLayer *first_layer = &frame_pyr->layers[0]; - if (frame->flags & YV12_FLAG_HIGHBITDEPTH) { - // For frames stored in a 16-bit buffer, we need to downconvert to 8 bits - assert(first_layer->width == frame_width); - assert(first_layer->height == frame_height); - - uint16_t *frame_buffer = CONVERT_TO_SHORTPTR(frame->y_buffer); - uint8_t *pyr_buffer = first_layer->buffer; - int pyr_stride = first_layer->stride; - for (int y = 0; y < frame_height; y++) { - uint16_t *frame_row = frame_buffer + y * frame_stride; - uint8_t *pyr_row = pyr_buffer + y * pyr_stride; - for (int x = 0; x < frame_width; x++) { - pyr_row[x] = frame_row[x] >> (bit_depth - 8); + if (already_filled_levels == 0) { + // Fill in largest level from the original image + PyramidLayer *first_layer = &frame_pyr->layers[0]; + if (frame->flags & YV12_FLAG_HIGHBITDEPTH) { + // For frames stored in a 16-bit buffer, we need to downconvert to 8 bits + assert(first_layer->width == frame_width); + assert(first_layer->height == frame_height); + + uint16_t *frame_buffer = CONVERT_TO_SHORTPTR(frame->y_buffer); + uint8_t *pyr_buffer = first_layer->buffer; + int pyr_stride = first_layer->stride; + for (int y = 0; y < frame_height; y++) { + uint16_t *frame_row = frame_buffer + y * frame_stride; + uint8_t *pyr_row = pyr_buffer + y * pyr_stride; + for (int x = 0; x < frame_width; x++) { + pyr_row[x] = frame_row[x] >> (bit_depth - 8); + } } + + fill_border(pyr_buffer, frame_width, frame_height, pyr_stride); + } else { + // For frames stored in an 8-bit buffer, we don't need to copy anything - + // we can just reference the original image buffer + first_layer->buffer = frame->y_buffer; + first_layer->width = frame_width; + first_layer->height = frame_height; + first_layer->stride = frame_stride; } - fill_border(pyr_buffer, frame_width, frame_height, pyr_stride); - } else { - // For frames stored in an 8-bit buffer, we need to configure the first - // pyramid layer to point at the original image buffer - first_layer->buffer = frame->y_buffer; - first_layer->width = frame_width; - first_layer->height = frame_height; - first_layer->stride = frame_stride; + already_filled_levels = 1; } // Fill in the remaining levels through progressive downsampling - for (int level = 1; level < n_levels; ++level) { + for (int level = already_filled_levels; level < n_levels; ++level) { PyramidLayer *prev_layer = &frame_pyr->layers[level - 1]; uint8_t *prev_buffer = prev_layer->buffer; int prev_stride = prev_layer->stride; @@ -314,11 +331,16 @@ static INLINE bool fill_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, // TODO(rachelbarker): Use optimized downsample-by-2 function if (!av1_resize_plane(prev_buffer, this_height << 1, this_width << 1, prev_stride, this_buffer, this_height, this_width, - this_stride)) - return false; + this_stride)) { + // If we can't allocate memory, we'll have to terminate early + frame_pyr->filled_levels = n_levels; + return -1; + } fill_border(this_buffer, this_width, this_height, this_stride); } - return true; + + frame_pyr->filled_levels = n_levels; + return n_levels; } // Fill out a downsampling pyramid for a given frame. @@ -327,63 +349,72 @@ static INLINE bool fill_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, // regardless of the input bit depth. Additional levels are then downscaled // by powers of 2. // -// For small input frames, the number of levels actually constructed -// will be limited so that the smallest image is at least MIN_PYRAMID_SIZE -// pixels along each side. +// This function will ensure that the first `n_levels` levels of the pyramid +// are filled, unless the frame is too small to have this many levels. +// In that case, we will fill all available levels and then stop. +// No matter how small the frame is, at least one level is guaranteed +// to be filled. // -// However, if the input frame has a side of length < MIN_PYRAMID_SIZE, -// we will still construct the top level. -bool aom_compute_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, - ImagePyramid *pyr) { +// Returns the actual number of levels filled, capped at n_levels, +// or -1 on error. +int aom_compute_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, + int n_levels, ImagePyramid *pyr) { assert(pyr); // Per the comments in the ImagePyramid struct, we must take this mutex - // before reading or writing the "valid" flag, and hold it while computing - // the pyramid, to ensure proper behaviour if multiple threads call this - // function simultaneously + // before reading or writing the filled_levels field, and hold it while + // computing any additional pyramid levels, to ensure proper behaviour + // when multithreading is used #if CONFIG_MULTITHREAD pthread_mutex_lock(&pyr->mutex); #endif // CONFIG_MULTITHREAD - if (!pyr->valid) { - pyr->valid = fill_pyramid(frame, bit_depth, pyr); + n_levels = AOMMIN(n_levels, pyr->max_levels); + int result = n_levels; + if (pyr->filled_levels < n_levels) { + // Compute any missing levels that we need + result = fill_pyramid(frame, bit_depth, n_levels, pyr); } - bool valid = pyr->valid; - - // At this point, the pyramid is guaranteed to be valid, and can be safely - // read from without holding the mutex any more + // At this point, as long as result >= 0, the requested number of pyramid + // levels are guaranteed to be valid, and can be safely read from without + // holding the mutex any further + assert(IMPLIES(result >= 0, pyr->filled_levels >= n_levels)); #if CONFIG_MULTITHREAD pthread_mutex_unlock(&pyr->mutex); #endif // CONFIG_MULTITHREAD - return valid; + return result; } #ifndef NDEBUG -// Check if a pyramid has already been computed. +// Check if a pyramid has already been computed to at least n levels // This is mostly a debug helper - as it is necessary to hold pyr->mutex -// while reading the valid flag, we cannot just write: -// assert(pyr->valid); +// while reading the number of already-computed levels, we cannot just write: +// assert(pyr->filled_levels >= n_levels); // This function allows the check to be correctly written as: -// assert(aom_is_pyramid_valid(pyr)); -bool aom_is_pyramid_valid(ImagePyramid *pyr) { +// assert(aom_is_pyramid_valid(pyr, n_levels)); +// +// Note: This deliberately does not restrict n_levels based on the maximum +// number of permitted levels for the frame size. This allows the check to +// catch cases where the caller forgets to handle the case where +// max_levels is less than the requested number of levels +bool aom_is_pyramid_valid(ImagePyramid *pyr, int n_levels) { assert(pyr); // Per the comments in the ImagePyramid struct, we must take this mutex - // before reading or writing the "valid" flag, and hold it while computing - // the pyramid, to ensure proper behaviour if multiple threads call this - // function simultaneously + // before reading or writing the filled_levels field, to ensure proper + // behaviour when multithreading is used #if CONFIG_MULTITHREAD pthread_mutex_lock(&pyr->mutex); #endif // CONFIG_MULTITHREAD - bool valid = pyr->valid; + bool result = (pyr->filled_levels >= n_levels); #if CONFIG_MULTITHREAD pthread_mutex_unlock(&pyr->mutex); #endif // CONFIG_MULTITHREAD - return valid; + return result; } #endif @@ -394,7 +425,7 @@ void aom_invalidate_pyramid(ImagePyramid *pyr) { #if CONFIG_MULTITHREAD pthread_mutex_lock(&pyr->mutex); #endif // CONFIG_MULTITHREAD - pyr->valid = false; + pyr->filled_levels = 0; #if CONFIG_MULTITHREAD pthread_mutex_unlock(&pyr->mutex); #endif // CONFIG_MULTITHREAD diff --git a/third_party/aom/aom_dsp/pyramid.h b/third_party/aom/aom_dsp/pyramid.h index 9442a1ff08..745bb7e525 100644 --- a/third_party/aom/aom_dsp/pyramid.h +++ b/third_party/aom/aom_dsp/pyramid.h @@ -19,7 +19,7 @@ #include "config/aom_config.h" #include "aom_scale/yv12config.h" -#include "aom_util/aom_thread.h" +#include "aom_util/aom_pthread.h" #ifdef __cplusplus extern "C" { @@ -57,23 +57,31 @@ typedef struct image_pyramid { // same time // // Semantics: - // * This mutex must be held whenever reading or writing the `valid` flag + // * This mutex must be held whenever reading or writing the + // `filled_levels` field // // * This mutex must also be held while computing the image pyramid, // to ensure that only one thread may do so at a time. // - // * However, once you have read the valid flag and seen a true value, - // it is safe to drop the mutex and read from the remaining fields. - // This is because, once the image pyramid is computed, its contents + // * However, once you have read the filled_levels field and observed + // a value N, it is safe to drop the mutex and read from the remaining + // fields, including the first N pyramid levels (but no higher). + // Note that filled_levels must be read once and cached in a local variable + // in order for this to be safe - it cannot be re-read without retaking + // the mutex. + // + // This works because, once the image pyramid is computed, its contents // will not be changed until the parent frame buffer is recycled, // which will not happen until there are no more outstanding references // to the frame buffer. pthread_mutex_t mutex; #endif - // Flag indicating whether the pyramid contains valid data - bool valid; - // Number of allocated/filled levels in this pyramid - int n_levels; + // Maximum number of levels for the given frame size + // We always allocate enough memory for this many levels, as the memory + // cost of higher levels of the pyramid is minimal. + int max_levels; + // Number of levels which currently hold valid data + int filled_levels; // Pointer to allocated buffer uint8_t *buffer_alloc; // Data for each level @@ -82,11 +90,9 @@ typedef struct image_pyramid { PyramidLayer *layers; } ImagePyramid; -size_t aom_get_pyramid_alloc_size(int width, int height, int n_levels, - bool image_is_16bit); +size_t aom_get_pyramid_alloc_size(int width, int height, bool image_is_16bit); -ImagePyramid *aom_alloc_pyramid(int width, int height, int n_levels, - bool image_is_16bit); +ImagePyramid *aom_alloc_pyramid(int width, int height, bool image_is_16bit); // Fill out a downsampling pyramid for a given frame. // @@ -94,23 +100,28 @@ ImagePyramid *aom_alloc_pyramid(int width, int height, int n_levels, // regardless of the input bit depth. Additional levels are then downscaled // by powers of 2. // -// For small input frames, the number of levels actually constructed -// will be limited so that the smallest image is at least MIN_PYRAMID_SIZE -// pixels along each side. +// This function will ensure that the first `n_levels` levels of the pyramid +// are filled, unless the frame is too small to have this many levels. +// In that case, we will fill all available levels and then stop. // -// However, if the input frame has a side of length < MIN_PYRAMID_SIZE, -// we will still construct the top level. -bool aom_compute_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, - ImagePyramid *pyr); +// Returns the actual number of levels filled, capped at n_levels, +// or -1 on error. +int aom_compute_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, + int n_levels, ImagePyramid *pyr); #ifndef NDEBUG -// Check if a pyramid has already been computed. +// Check if a pyramid has already been computed to at least n levels // This is mostly a debug helper - as it is necessary to hold pyr->mutex -// while reading the valid flag, we cannot just write: -// assert(pyr->valid); +// while reading the number of already-computed levels, we cannot just write: +// assert(pyr->filled_levels >= n_levels); // This function allows the check to be correctly written as: -// assert(aom_is_pyramid_valid(pyr)); -bool aom_is_pyramid_valid(ImagePyramid *pyr); +// assert(aom_is_pyramid_valid(pyr, n_levels)); +// +// Note: This deliberately does not restrict n_levels based on the maximum +// number of permitted levels for the frame size. This allows the check to +// catch cases where the caller forgets to handle the case where +// max_levels is less than the requested number of levels +bool aom_is_pyramid_valid(ImagePyramid *pyr, int n_levels); #endif // Mark a pyramid as no longer containing valid data. diff --git a/third_party/aom/aom_dsp/rect.h b/third_party/aom/aom_dsp/rect.h deleted file mode 100644 index 11bdaca979..0000000000 --- a/third_party/aom/aom_dsp/rect.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 2 Clause License and - * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License - * was not distributed with this source code in the LICENSE file, you can - * obtain it at www.aomedia.org/license/software. If the Alliance for Open - * Media Patent License 1.0 was not distributed with this source code in the - * PATENTS file, you can obtain it at www.aomedia.org/license/patent. - */ - -#ifndef AOM_AOM_DSP_RECT_H_ -#define AOM_AOM_DSP_RECT_H_ - -#include "config/aom_config.h" - -#include - -// Struct representing a rectangle of pixels. -// The axes are inclusive-exclusive, ie. the point (top, left) is included -// in the rectangle but (bottom, right) is not. -typedef struct { - int left, right, top, bottom; -} PixelRect; - -static INLINE int rect_width(const PixelRect *r) { return r->right - r->left; } - -static INLINE int rect_height(const PixelRect *r) { return r->bottom - r->top; } - -static INLINE bool is_inside_rect(const int x, const int y, - const PixelRect *r) { - return (r->left <= x && x < r->right) && (r->top <= y && y < r->bottom); -} - -#endif // AOM_AOM_DSP_RECT_H_ diff --git a/third_party/aom/aom_dsp/variance.c b/third_party/aom/aom_dsp/variance.c index f02c3077ae..6cdd58492a 100644 --- a/third_party/aom/aom_dsp/variance.c +++ b/third_party/aom/aom_dsp/variance.c @@ -10,7 +10,6 @@ */ #include #include -#include #include "config/aom_config.h" #include "config/aom_dsp_rtcd.h" @@ -70,12 +69,10 @@ uint32_t aom_sse_odd_size(const uint8_t *a, int a_stride, const uint8_t *b, // taps should sum to FILTER_WEIGHT. pixel_step defines whether the filter is // applied horizontally (pixel_step = 1) or vertically (pixel_step = stride). // It defines the offset required to move from one input to the next. -void aom_var_filter_block2d_bil_first_pass_c(const uint8_t *a, uint16_t *b, - unsigned int src_pixels_per_line, - unsigned int pixel_step, - unsigned int output_height, - unsigned int output_width, - const uint8_t *filter) { +static void var_filter_block2d_bil_first_pass_c( + const uint8_t *a, uint16_t *b, unsigned int src_pixels_per_line, + unsigned int pixel_step, unsigned int output_height, + unsigned int output_width, const uint8_t *filter) { unsigned int i, j; for (i = 0; i < output_height; ++i) { @@ -100,12 +97,10 @@ void aom_var_filter_block2d_bil_first_pass_c(const uint8_t *a, uint16_t *b, // filter is applied horizontally (pixel_step = 1) or vertically // (pixel_step = stride). It defines the offset required to move from one input // to the next. Output is 8-bit. -void aom_var_filter_block2d_bil_second_pass_c(const uint16_t *a, uint8_t *b, - unsigned int src_pixels_per_line, - unsigned int pixel_step, - unsigned int output_height, - unsigned int output_width, - const uint8_t *filter) { +static void var_filter_block2d_bil_second_pass_c( + const uint16_t *a, uint8_t *b, unsigned int src_pixels_per_line, + unsigned int pixel_step, unsigned int output_height, + unsigned int output_width, const uint8_t *filter) { unsigned int i, j; for (i = 0; i < output_height; ++i) { @@ -129,19 +124,19 @@ void aom_var_filter_block2d_bil_second_pass_c(const uint16_t *a, uint8_t *b, return *sse - (uint32_t)(((int64_t)sum * sum) / (W * H)); \ } -#define SUBPIX_VAR(W, H) \ - uint32_t aom_sub_pixel_variance##W##x##H##_c( \ - const uint8_t *a, int a_stride, int xoffset, int yoffset, \ - const uint8_t *b, int b_stride, uint32_t *sse) { \ - uint16_t fdata3[(H + 1) * W]; \ - uint8_t temp2[H * W]; \ - \ - aom_var_filter_block2d_bil_first_pass_c(a, fdata3, a_stride, 1, H + 1, W, \ - bilinear_filters_2t[xoffset]); \ - aom_var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ - bilinear_filters_2t[yoffset]); \ - \ - return aom_variance##W##x##H##_c(temp2, W, b, b_stride, sse); \ +#define SUBPIX_VAR(W, H) \ + uint32_t aom_sub_pixel_variance##W##x##H##_c( \ + const uint8_t *a, int a_stride, int xoffset, int yoffset, \ + const uint8_t *b, int b_stride, uint32_t *sse) { \ + uint16_t fdata3[(H + 1) * W]; \ + uint8_t temp2[H * W]; \ + \ + var_filter_block2d_bil_first_pass_c(a, fdata3, a_stride, 1, H + 1, W, \ + bilinear_filters_2t[xoffset]); \ + var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ + bilinear_filters_2t[yoffset]); \ + \ + return aom_variance##W##x##H##_c(temp2, W, b, b_stride, sse); \ } #define SUBPIX_AVG_VAR(W, H) \ @@ -153,10 +148,10 @@ void aom_var_filter_block2d_bil_second_pass_c(const uint16_t *a, uint8_t *b, uint8_t temp2[H * W]; \ DECLARE_ALIGNED(16, uint8_t, temp3[H * W]); \ \ - aom_var_filter_block2d_bil_first_pass_c(a, fdata3, a_stride, 1, H + 1, W, \ - bilinear_filters_2t[xoffset]); \ - aom_var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ - bilinear_filters_2t[yoffset]); \ + var_filter_block2d_bil_first_pass_c(a, fdata3, a_stride, 1, H + 1, W, \ + bilinear_filters_2t[xoffset]); \ + var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ + bilinear_filters_2t[yoffset]); \ \ aom_comp_avg_pred(temp3, second_pred, W, H, temp2, W); \ \ @@ -170,10 +165,10 @@ void aom_var_filter_block2d_bil_second_pass_c(const uint16_t *a, uint8_t *b, uint8_t temp2[H * W]; \ DECLARE_ALIGNED(16, uint8_t, temp3[H * W]); \ \ - aom_var_filter_block2d_bil_first_pass_c(a, fdata3, a_stride, 1, H + 1, W, \ - bilinear_filters_2t[xoffset]); \ - aom_var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ - bilinear_filters_2t[yoffset]); \ + var_filter_block2d_bil_first_pass_c(a, fdata3, a_stride, 1, H + 1, W, \ + bilinear_filters_2t[xoffset]); \ + var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ + bilinear_filters_2t[yoffset]); \ \ aom_dist_wtd_comp_avg_pred(temp3, second_pred, W, H, temp2, W, jcp_param); \ \ @@ -730,24 +725,24 @@ void aom_comp_mask_pred_c(uint8_t *comp_pred, const uint8_t *pred, int width, } } -#define MASK_SUBPIX_VAR(W, H) \ - unsigned int aom_masked_sub_pixel_variance##W##x##H##_c( \ - const uint8_t *src, int src_stride, int xoffset, int yoffset, \ - const uint8_t *ref, int ref_stride, const uint8_t *second_pred, \ - const uint8_t *msk, int msk_stride, int invert_mask, \ - unsigned int *sse) { \ - uint16_t fdata3[(H + 1) * W]; \ - uint8_t temp2[H * W]; \ - DECLARE_ALIGNED(16, uint8_t, temp3[H * W]); \ - \ - aom_var_filter_block2d_bil_first_pass_c(src, fdata3, src_stride, 1, H + 1, \ - W, bilinear_filters_2t[xoffset]); \ - aom_var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ - bilinear_filters_2t[yoffset]); \ - \ - aom_comp_mask_pred_c(temp3, second_pred, W, H, temp2, W, msk, msk_stride, \ - invert_mask); \ - return aom_variance##W##x##H##_c(temp3, W, ref, ref_stride, sse); \ +#define MASK_SUBPIX_VAR(W, H) \ + unsigned int aom_masked_sub_pixel_variance##W##x##H##_c( \ + const uint8_t *src, int src_stride, int xoffset, int yoffset, \ + const uint8_t *ref, int ref_stride, const uint8_t *second_pred, \ + const uint8_t *msk, int msk_stride, int invert_mask, \ + unsigned int *sse) { \ + uint16_t fdata3[(H + 1) * W]; \ + uint8_t temp2[H * W]; \ + DECLARE_ALIGNED(16, uint8_t, temp3[H * W]); \ + \ + var_filter_block2d_bil_first_pass_c(src, fdata3, src_stride, 1, H + 1, W, \ + bilinear_filters_2t[xoffset]); \ + var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ + bilinear_filters_2t[yoffset]); \ + \ + aom_comp_mask_pred_c(temp3, second_pred, W, H, temp2, W, msk, msk_stride, \ + invert_mask); \ + return aom_variance##W##x##H##_c(temp3, W, ref, ref_stride, sse); \ } MASK_SUBPIX_VAR(4, 4) @@ -924,19 +919,19 @@ static INLINE void obmc_variance(const uint8_t *pre, int pre_stride, return *sse - (unsigned int)(((int64_t)sum * sum) / (W * H)); \ } -#define OBMC_SUBPIX_VAR(W, H) \ - unsigned int aom_obmc_sub_pixel_variance##W##x##H##_c( \ - const uint8_t *pre, int pre_stride, int xoffset, int yoffset, \ - const int32_t *wsrc, const int32_t *mask, unsigned int *sse) { \ - uint16_t fdata3[(H + 1) * W]; \ - uint8_t temp2[H * W]; \ - \ - aom_var_filter_block2d_bil_first_pass_c(pre, fdata3, pre_stride, 1, H + 1, \ - W, bilinear_filters_2t[xoffset]); \ - aom_var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ - bilinear_filters_2t[yoffset]); \ - \ - return aom_obmc_variance##W##x##H##_c(temp2, W, wsrc, mask, sse); \ +#define OBMC_SUBPIX_VAR(W, H) \ + unsigned int aom_obmc_sub_pixel_variance##W##x##H##_c( \ + const uint8_t *pre, int pre_stride, int xoffset, int yoffset, \ + const int32_t *wsrc, const int32_t *mask, unsigned int *sse) { \ + uint16_t fdata3[(H + 1) * W]; \ + uint8_t temp2[H * W]; \ + \ + var_filter_block2d_bil_first_pass_c(pre, fdata3, pre_stride, 1, H + 1, W, \ + bilinear_filters_2t[xoffset]); \ + var_filter_block2d_bil_second_pass_c(fdata3, temp2, W, W, H, W, \ + bilinear_filters_2t[yoffset]); \ + \ + return aom_obmc_variance##W##x##H##_c(temp2, W, wsrc, mask, sse); \ } OBMC_VAR(4, 4) diff --git a/third_party/aom/aom_dsp/x86/aom_asm_stubs.c b/third_party/aom/aom_dsp/x86/aom_asm_stubs.c index b08ec2546b..6c7fdd6eb1 100644 --- a/third_party/aom/aom_dsp/x86/aom_asm_stubs.c +++ b/third_party/aom/aom_dsp/x86/aom_asm_stubs.c @@ -15,40 +15,6 @@ #include "aom_dsp/x86/convolve.h" #if HAVE_SSE2 -filter8_1dfunction aom_filter_block1d16_v8_sse2; -filter8_1dfunction aom_filter_block1d16_h8_sse2; -filter8_1dfunction aom_filter_block1d8_v8_sse2; -filter8_1dfunction aom_filter_block1d8_h8_sse2; -filter8_1dfunction aom_filter_block1d4_v8_sse2; -filter8_1dfunction aom_filter_block1d4_h8_sse2; -filter8_1dfunction aom_filter_block1d16_v4_sse2; -filter8_1dfunction aom_filter_block1d16_h4_sse2; - -filter8_1dfunction aom_filter_block1d8_h4_sse2; -filter8_1dfunction aom_filter_block1d8_v4_sse2; -filter8_1dfunction aom_filter_block1d4_h4_sse2; -filter8_1dfunction aom_filter_block1d4_v4_sse2; - -filter8_1dfunction aom_filter_block1d16_v2_sse2; -filter8_1dfunction aom_filter_block1d16_h2_sse2; -filter8_1dfunction aom_filter_block1d8_v2_sse2; -filter8_1dfunction aom_filter_block1d8_h2_sse2; -filter8_1dfunction aom_filter_block1d4_v2_sse2; -filter8_1dfunction aom_filter_block1d4_h2_sse2; - -// void aom_convolve8_horiz_sse2(const uint8_t *src, ptrdiff_t src_stride, -// uint8_t *dst, ptrdiff_t dst_stride, -// const int16_t *filter_x, int x_step_q4, -// const int16_t *filter_y, int y_step_q4, -// int w, int h); -// void aom_convolve8_vert_sse2(const uint8_t *src, ptrdiff_t src_stride, -// uint8_t *dst, ptrdiff_t dst_stride, -// const int16_t *filter_x, int x_step_q4, -// const int16_t *filter_y, int y_step_q4, -// int w, int h); -FUN_CONV_1D(horiz, x_step_q4, filter_x, h, src, , sse2) -FUN_CONV_1D(vert, y_step_q4, filter_y, v, src - src_stride * 3, , sse2) - #if CONFIG_AV1_HIGHBITDEPTH highbd_filter8_1dfunction aom_highbd_filter_block1d16_v8_sse2; highbd_filter8_1dfunction aom_highbd_filter_block1d16_h8_sse2; diff --git a/third_party/aom/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c b/third_party/aom/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c deleted file mode 100644 index 5c36b68727..0000000000 --- a/third_party/aom/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright (c) 2018, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 2 Clause License and - * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License - * was not distributed with this source code in the LICENSE file, you can - * obtain it at www.aomedia.org/license/software. If the Alliance for Open - * Media Patent License 1.0 was not distributed with this source code in the - * PATENTS file, you can obtain it at www.aomedia.org/license/patent. - */ - -#include // SSE2 - -#include "config/aom_dsp_rtcd.h" -#include "aom_dsp/x86/convolve.h" -#include "aom_ports/mem.h" - -void aom_filter_block1d16_h4_sse2(const uint8_t *src_ptr, - ptrdiff_t src_pixels_per_line, - uint8_t *output_ptr, ptrdiff_t output_pitch, - uint32_t output_height, - const int16_t *filter) { - __m128i filtersReg; - __m128i addFilterReg32; - __m128i secondFilters, thirdFilters; - __m128i srcRegFilt32b1_1, srcRegFilt32b1_2, srcRegFilt32b2_1, - srcRegFilt32b2_2; - __m128i srcReg32b1, srcReg32b2; - unsigned int i; - src_ptr -= 3; - addFilterReg32 = _mm_set1_epi16(32); - filtersReg = _mm_loadu_si128((const __m128i *)filter); - filtersReg = _mm_srai_epi16(filtersReg, 1); - - // coeffs 0 1 0 1 2 3 2 3 - const __m128i tmp_0 = _mm_unpacklo_epi32(filtersReg, filtersReg); - // coeffs 4 5 4 5 6 7 6 7 - const __m128i tmp_1 = _mm_unpackhi_epi32(filtersReg, filtersReg); - - secondFilters = _mm_unpackhi_epi64(tmp_0, tmp_0); // coeffs 2 3 2 3 2 3 2 3 - thirdFilters = _mm_unpacklo_epi64(tmp_1, tmp_1); // coeffs 4 5 4 5 4 5 4 5 - - for (i = output_height; i > 0; i -= 1) { - srcReg32b1 = _mm_loadu_si128((const __m128i *)src_ptr); - - __m128i ss_2 = _mm_srli_si128(srcReg32b1, 2); - __m128i ss_4 = _mm_srli_si128(srcReg32b1, 4); - __m128i ss_1_1 = _mm_unpacklo_epi8(ss_2, _mm_setzero_si128()); - __m128i ss_2_1 = _mm_unpacklo_epi8(ss_4, _mm_setzero_si128()); - __m128i d1 = _mm_madd_epi16(ss_1_1, secondFilters); - __m128i d2 = _mm_madd_epi16(ss_2_1, thirdFilters); - srcRegFilt32b1_1 = _mm_add_epi32(d1, d2); - - __m128i ss_1 = _mm_srli_si128(srcReg32b1, 3); - __m128i ss_3 = _mm_srli_si128(srcReg32b1, 5); - __m128i ss_1_2 = _mm_unpacklo_epi8(ss_1, _mm_setzero_si128()); - __m128i ss_2_2 = _mm_unpacklo_epi8(ss_3, _mm_setzero_si128()); - d1 = _mm_madd_epi16(ss_1_2, secondFilters); - d2 = _mm_madd_epi16(ss_2_2, thirdFilters); - srcRegFilt32b1_2 = _mm_add_epi32(d1, d2); - - __m128i res_lo = _mm_unpacklo_epi32(srcRegFilt32b1_1, srcRegFilt32b1_2); - __m128i res_hi = _mm_unpackhi_epi32(srcRegFilt32b1_1, srcRegFilt32b1_2); - srcRegFilt32b1_1 = _mm_packs_epi32(res_lo, res_hi); - - // reading stride of the next 16 bytes - // (part of it was being read by earlier read) - srcReg32b2 = _mm_loadu_si128((const __m128i *)(src_ptr + 8)); - - ss_2 = _mm_srli_si128(srcReg32b2, 2); - ss_4 = _mm_srli_si128(srcReg32b2, 4); - ss_1_1 = _mm_unpacklo_epi8(ss_2, _mm_setzero_si128()); - ss_2_1 = _mm_unpacklo_epi8(ss_4, _mm_setzero_si128()); - d1 = _mm_madd_epi16(ss_1_1, secondFilters); - d2 = _mm_madd_epi16(ss_2_1, thirdFilters); - srcRegFilt32b2_1 = _mm_add_epi32(d1, d2); - - ss_1 = _mm_srli_si128(srcReg32b2, 3); - ss_3 = _mm_srli_si128(srcReg32b2, 5); - ss_1_2 = _mm_unpacklo_epi8(ss_1, _mm_setzero_si128()); - ss_2_2 = _mm_unpacklo_epi8(ss_3, _mm_setzero_si128()); - d1 = _mm_madd_epi16(ss_1_2, secondFilters); - d2 = _mm_madd_epi16(ss_2_2, thirdFilters); - srcRegFilt32b2_2 = _mm_add_epi32(d1, d2); - - res_lo = _mm_unpacklo_epi32(srcRegFilt32b2_1, srcRegFilt32b2_2); - res_hi = _mm_unpackhi_epi32(srcRegFilt32b2_1, srcRegFilt32b2_2); - srcRegFilt32b2_1 = _mm_packs_epi32(res_lo, res_hi); - - // shift by 6 bit each 16 bit - srcRegFilt32b1_1 = _mm_adds_epi16(srcRegFilt32b1_1, addFilterReg32); - srcRegFilt32b2_1 = _mm_adds_epi16(srcRegFilt32b2_1, addFilterReg32); - srcRegFilt32b1_1 = _mm_srai_epi16(srcRegFilt32b1_1, 6); - srcRegFilt32b2_1 = _mm_srai_epi16(srcRegFilt32b2_1, 6); - - // shrink to 8 bit each 16 bits, the first lane contain the first - // convolve result and the second lane contain the second convolve result - srcRegFilt32b1_1 = _mm_packus_epi16(srcRegFilt32b1_1, srcRegFilt32b2_1); - - src_ptr += src_pixels_per_line; - - _mm_store_si128((__m128i *)output_ptr, srcRegFilt32b1_1); - - output_ptr += output_pitch; - } -} - -void aom_filter_block1d16_v4_sse2(const uint8_t *src_ptr, ptrdiff_t src_pitch, - uint8_t *output_ptr, ptrdiff_t out_pitch, - uint32_t output_height, - const int16_t *filter) { - __m128i filtersReg; - __m128i srcReg2, srcReg3, srcReg4, srcReg5, srcReg6; - __m128i srcReg23_lo, srcReg23_hi, srcReg34_lo, srcReg34_hi; - __m128i srcReg45_lo, srcReg45_hi, srcReg56_lo, srcReg56_hi; - __m128i resReg23_lo, resReg34_lo, resReg45_lo, resReg56_lo; - __m128i resReg23_hi, resReg34_hi, resReg45_hi, resReg56_hi; - __m128i resReg23_45_lo, resReg34_56_lo, resReg23_45_hi, resReg34_56_hi; - __m128i resReg23_45, resReg34_56; - __m128i addFilterReg32, secondFilters, thirdFilters; - __m128i tmp_0, tmp_1; - unsigned int i; - ptrdiff_t src_stride, dst_stride; - - addFilterReg32 = _mm_set1_epi16(32); - filtersReg = _mm_loadu_si128((const __m128i *)filter); - filtersReg = _mm_srai_epi16(filtersReg, 1); - - // coeffs 0 1 0 1 2 3 2 3 - const __m128i tmp0 = _mm_unpacklo_epi32(filtersReg, filtersReg); - // coeffs 4 5 4 5 6 7 6 7 - const __m128i tmp1 = _mm_unpackhi_epi32(filtersReg, filtersReg); - - secondFilters = _mm_unpackhi_epi64(tmp0, tmp0); // coeffs 2 3 2 3 2 3 2 3 - thirdFilters = _mm_unpacklo_epi64(tmp1, tmp1); // coeffs 4 5 4 5 4 5 4 5 - - // multiply the size of the source and destination stride by two - src_stride = src_pitch << 1; - dst_stride = out_pitch << 1; - - srcReg2 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 2)); - srcReg3 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 3)); - srcReg23_lo = _mm_unpacklo_epi8(srcReg2, srcReg3); - srcReg23_hi = _mm_unpackhi_epi8(srcReg2, srcReg3); - __m128i resReg23_lo_1 = _mm_unpacklo_epi8(srcReg23_lo, _mm_setzero_si128()); - __m128i resReg23_lo_2 = _mm_unpackhi_epi8(srcReg23_lo, _mm_setzero_si128()); - __m128i resReg23_hi_1 = _mm_unpacklo_epi8(srcReg23_hi, _mm_setzero_si128()); - __m128i resReg23_hi_2 = _mm_unpackhi_epi8(srcReg23_hi, _mm_setzero_si128()); - - srcReg4 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 4)); - srcReg34_lo = _mm_unpacklo_epi8(srcReg3, srcReg4); - srcReg34_hi = _mm_unpackhi_epi8(srcReg3, srcReg4); - __m128i resReg34_lo_1 = _mm_unpacklo_epi8(srcReg34_lo, _mm_setzero_si128()); - __m128i resReg34_lo_2 = _mm_unpackhi_epi8(srcReg34_lo, _mm_setzero_si128()); - __m128i resReg34_hi_1 = _mm_unpacklo_epi8(srcReg34_hi, _mm_setzero_si128()); - __m128i resReg34_hi_2 = _mm_unpackhi_epi8(srcReg34_hi, _mm_setzero_si128()); - - for (i = output_height; i > 1; i -= 2) { - srcReg5 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 5)); - - srcReg45_lo = _mm_unpacklo_epi8(srcReg4, srcReg5); - srcReg45_hi = _mm_unpackhi_epi8(srcReg4, srcReg5); - - srcReg6 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 6)); - - srcReg56_lo = _mm_unpacklo_epi8(srcReg5, srcReg6); - srcReg56_hi = _mm_unpackhi_epi8(srcReg5, srcReg6); - - // multiply 2 adjacent elements with the filter and add the result - - tmp_0 = _mm_madd_epi16(resReg23_lo_1, secondFilters); - tmp_1 = _mm_madd_epi16(resReg23_lo_2, secondFilters); - resReg23_lo = _mm_packs_epi32(tmp_0, tmp_1); - - tmp_0 = _mm_madd_epi16(resReg34_lo_1, secondFilters); - tmp_1 = _mm_madd_epi16(resReg34_lo_2, secondFilters); - resReg34_lo = _mm_packs_epi32(tmp_0, tmp_1); - - __m128i resReg45_lo_1 = _mm_unpacklo_epi8(srcReg45_lo, _mm_setzero_si128()); - __m128i resReg45_lo_2 = _mm_unpackhi_epi8(srcReg45_lo, _mm_setzero_si128()); - tmp_0 = _mm_madd_epi16(resReg45_lo_1, thirdFilters); - tmp_1 = _mm_madd_epi16(resReg45_lo_2, thirdFilters); - resReg45_lo = _mm_packs_epi32(tmp_0, tmp_1); - - __m128i resReg56_lo_1 = _mm_unpacklo_epi8(srcReg56_lo, _mm_setzero_si128()); - __m128i resReg56_lo_2 = _mm_unpackhi_epi8(srcReg56_lo, _mm_setzero_si128()); - tmp_0 = _mm_madd_epi16(resReg56_lo_1, thirdFilters); - tmp_1 = _mm_madd_epi16(resReg56_lo_2, thirdFilters); - resReg56_lo = _mm_packs_epi32(tmp_0, tmp_1); - - // add and saturate the results together - resReg23_45_lo = _mm_adds_epi16(resReg23_lo, resReg45_lo); - resReg34_56_lo = _mm_adds_epi16(resReg34_lo, resReg56_lo); - - // multiply 2 adjacent elements with the filter and add the result - - tmp_0 = _mm_madd_epi16(resReg23_hi_1, secondFilters); - tmp_1 = _mm_madd_epi16(resReg23_hi_2, secondFilters); - resReg23_hi = _mm_packs_epi32(tmp_0, tmp_1); - - tmp_0 = _mm_madd_epi16(resReg34_hi_1, secondFilters); - tmp_1 = _mm_madd_epi16(resReg34_hi_2, secondFilters); - resReg34_hi = _mm_packs_epi32(tmp_0, tmp_1); - - __m128i resReg45_hi_1 = _mm_unpacklo_epi8(srcReg45_hi, _mm_setzero_si128()); - __m128i resReg45_hi_2 = _mm_unpackhi_epi8(srcReg45_hi, _mm_setzero_si128()); - tmp_0 = _mm_madd_epi16(resReg45_hi_1, thirdFilters); - tmp_1 = _mm_madd_epi16(resReg45_hi_2, thirdFilters); - resReg45_hi = _mm_packs_epi32(tmp_0, tmp_1); - - __m128i resReg56_hi_1 = _mm_unpacklo_epi8(srcReg56_hi, _mm_setzero_si128()); - __m128i resReg56_hi_2 = _mm_unpackhi_epi8(srcReg56_hi, _mm_setzero_si128()); - tmp_0 = _mm_madd_epi16(resReg56_hi_1, thirdFilters); - tmp_1 = _mm_madd_epi16(resReg56_hi_2, thirdFilters); - resReg56_hi = _mm_packs_epi32(tmp_0, tmp_1); - - // add and saturate the results together - resReg23_45_hi = _mm_adds_epi16(resReg23_hi, resReg45_hi); - resReg34_56_hi = _mm_adds_epi16(resReg34_hi, resReg56_hi); - - // shift by 6 bit each 16 bit - resReg23_45_lo = _mm_adds_epi16(resReg23_45_lo, addFilterReg32); - resReg34_56_lo = _mm_adds_epi16(resReg34_56_lo, addFilterReg32); - resReg23_45_hi = _mm_adds_epi16(resReg23_45_hi, addFilterReg32); - resReg34_56_hi = _mm_adds_epi16(resReg34_56_hi, addFilterReg32); - resReg23_45_lo = _mm_srai_epi16(resReg23_45_lo, 6); - resReg34_56_lo = _mm_srai_epi16(resReg34_56_lo, 6); - resReg23_45_hi = _mm_srai_epi16(resReg23_45_hi, 6); - resReg34_56_hi = _mm_srai_epi16(resReg34_56_hi, 6); - - // shrink to 8 bit each 16 bits, the first lane contain the first - // convolve result and the second lane contain the second convolve - // result - resReg23_45 = _mm_packus_epi16(resReg23_45_lo, resReg23_45_hi); - resReg34_56 = _mm_packus_epi16(resReg34_56_lo, resReg34_56_hi); - - src_ptr += src_stride; - - _mm_store_si128((__m128i *)output_ptr, (resReg23_45)); - _mm_store_si128((__m128i *)(output_ptr + out_pitch), (resReg34_56)); - - output_ptr += dst_stride; - - // save part of the registers for next strides - resReg23_lo_1 = resReg45_lo_1; - resReg23_lo_2 = resReg45_lo_2; - resReg23_hi_1 = resReg45_hi_1; - resReg23_hi_2 = resReg45_hi_2; - resReg34_lo_1 = resReg56_lo_1; - resReg34_lo_2 = resReg56_lo_2; - resReg34_hi_1 = resReg56_hi_1; - resReg34_hi_2 = resReg56_hi_2; - srcReg4 = srcReg6; - } -} - -void aom_filter_block1d8_h4_sse2(const uint8_t *src_ptr, - ptrdiff_t src_pixels_per_line, - uint8_t *output_ptr, ptrdiff_t output_pitch, - uint32_t output_height, - const int16_t *filter) { - __m128i filtersReg; - __m128i addFilterReg32; - __m128i secondFilters, thirdFilters; - __m128i srcRegFilt32b1_1, srcRegFilt32b1_2; - __m128i srcReg32b1; - unsigned int i; - src_ptr -= 3; - addFilterReg32 = _mm_set1_epi16(32); - filtersReg = _mm_loadu_si128((const __m128i *)filter); - filtersReg = _mm_srai_epi16(filtersReg, 1); - - // coeffs 0 1 0 1 2 3 2 3 - const __m128i tmp_0 = _mm_unpacklo_epi32(filtersReg, filtersReg); - // coeffs 4 5 4 5 6 7 6 7 - const __m128i tmp_1 = _mm_unpackhi_epi32(filtersReg, filtersReg); - - secondFilters = _mm_unpackhi_epi64(tmp_0, tmp_0); // coeffs 2 3 2 3 2 3 2 3 - thirdFilters = _mm_unpacklo_epi64(tmp_1, tmp_1); // coeffs 4 5 4 5 4 5 4 5 - - for (i = output_height; i > 0; i -= 1) { - srcReg32b1 = _mm_loadu_si128((const __m128i *)src_ptr); - - __m128i ss_2 = _mm_srli_si128(srcReg32b1, 2); - __m128i ss_4 = _mm_srli_si128(srcReg32b1, 4); - ss_2 = _mm_unpacklo_epi8(ss_2, _mm_setzero_si128()); - ss_4 = _mm_unpacklo_epi8(ss_4, _mm_setzero_si128()); - __m128i d1 = _mm_madd_epi16(ss_2, secondFilters); - __m128i d2 = _mm_madd_epi16(ss_4, thirdFilters); - srcRegFilt32b1_1 = _mm_add_epi32(d1, d2); - - __m128i ss_3 = _mm_srli_si128(srcReg32b1, 3); - __m128i ss_5 = _mm_srli_si128(srcReg32b1, 5); - ss_3 = _mm_unpacklo_epi8(ss_3, _mm_setzero_si128()); - ss_5 = _mm_unpacklo_epi8(ss_5, _mm_setzero_si128()); - d1 = _mm_madd_epi16(ss_3, secondFilters); - d2 = _mm_madd_epi16(ss_5, thirdFilters); - srcRegFilt32b1_2 = _mm_add_epi32(d1, d2); - - __m128i res_lo = _mm_unpacklo_epi32(srcRegFilt32b1_1, srcRegFilt32b1_2); - __m128i res_hi = _mm_unpackhi_epi32(srcRegFilt32b1_1, srcRegFilt32b1_2); - srcRegFilt32b1_1 = _mm_packs_epi32(res_lo, res_hi); - - // shift by 6 bit each 16 bit - srcRegFilt32b1_1 = _mm_adds_epi16(srcRegFilt32b1_1, addFilterReg32); - srcRegFilt32b1_1 = _mm_srai_epi16(srcRegFilt32b1_1, 6); - - // shrink to 8 bit each 16 bits, the first lane contain the first - // convolve result and the second lane contain the second convolve result - srcRegFilt32b1_1 = _mm_packus_epi16(srcRegFilt32b1_1, _mm_setzero_si128()); - - src_ptr += src_pixels_per_line; - - _mm_storel_epi64((__m128i *)output_ptr, srcRegFilt32b1_1); - - output_ptr += output_pitch; - } -} - -void aom_filter_block1d8_v4_sse2(const uint8_t *src_ptr, ptrdiff_t src_pitch, - uint8_t *output_ptr, ptrdiff_t out_pitch, - uint32_t output_height, - const int16_t *filter) { - __m128i filtersReg; - __m128i srcReg2, srcReg3, srcReg4, srcReg5, srcReg6; - __m128i srcReg23_lo, srcReg34_lo; - __m128i srcReg45_lo, srcReg56_lo; - __m128i resReg23_lo, resReg34_lo, resReg45_lo, resReg56_lo; - __m128i resReg23_45_lo, resReg34_56_lo; - __m128i resReg23_45, resReg34_56; - __m128i addFilterReg32, secondFilters, thirdFilters; - __m128i tmp_0, tmp_1; - unsigned int i; - ptrdiff_t src_stride, dst_stride; - - addFilterReg32 = _mm_set1_epi16(32); - filtersReg = _mm_loadu_si128((const __m128i *)filter); - filtersReg = _mm_srai_epi16(filtersReg, 1); - - // coeffs 0 1 0 1 2 3 2 3 - const __m128i tmp0 = _mm_unpacklo_epi32(filtersReg, filtersReg); - // coeffs 4 5 4 5 6 7 6 7 - const __m128i tmp1 = _mm_unpackhi_epi32(filtersReg, filtersReg); - - secondFilters = _mm_unpackhi_epi64(tmp0, tmp0); // coeffs 2 3 2 3 2 3 2 3 - thirdFilters = _mm_unpacklo_epi64(tmp1, tmp1); // coeffs 4 5 4 5 4 5 4 5 - - // multiply the size of the source and destination stride by two - src_stride = src_pitch << 1; - dst_stride = out_pitch << 1; - - srcReg2 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 2)); - srcReg3 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 3)); - srcReg23_lo = _mm_unpacklo_epi8(srcReg2, srcReg3); - __m128i resReg23_lo_1 = _mm_unpacklo_epi8(srcReg23_lo, _mm_setzero_si128()); - __m128i resReg23_lo_2 = _mm_unpackhi_epi8(srcReg23_lo, _mm_setzero_si128()); - - srcReg4 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 4)); - srcReg34_lo = _mm_unpacklo_epi8(srcReg3, srcReg4); - __m128i resReg34_lo_1 = _mm_unpacklo_epi8(srcReg34_lo, _mm_setzero_si128()); - __m128i resReg34_lo_2 = _mm_unpackhi_epi8(srcReg34_lo, _mm_setzero_si128()); - - for (i = output_height; i > 1; i -= 2) { - srcReg5 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 5)); - srcReg45_lo = _mm_unpacklo_epi8(srcReg4, srcReg5); - - srcReg6 = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 6)); - srcReg56_lo = _mm_unpacklo_epi8(srcReg5, srcReg6); - - // multiply 2 adjacent elements with the filter and add the result - - tmp_0 = _mm_madd_epi16(resReg23_lo_1, secondFilters); - tmp_1 = _mm_madd_epi16(resReg23_lo_2, secondFilters); - resReg23_lo = _mm_packs_epi32(tmp_0, tmp_1); - - tmp_0 = _mm_madd_epi16(resReg34_lo_1, secondFilters); - tmp_1 = _mm_madd_epi16(resReg34_lo_2, secondFilters); - resReg34_lo = _mm_packs_epi32(tmp_0, tmp_1); - - __m128i resReg45_lo_1 = _mm_unpacklo_epi8(srcReg45_lo, _mm_setzero_si128()); - __m128i resReg45_lo_2 = _mm_unpackhi_epi8(srcReg45_lo, _mm_setzero_si128()); - tmp_0 = _mm_madd_epi16(resReg45_lo_1, thirdFilters); - tmp_1 = _mm_madd_epi16(resReg45_lo_2, thirdFilters); - resReg45_lo = _mm_packs_epi32(tmp_0, tmp_1); - - __m128i resReg56_lo_1 = _mm_unpacklo_epi8(srcReg56_lo, _mm_setzero_si128()); - __m128i resReg56_lo_2 = _mm_unpackhi_epi8(srcReg56_lo, _mm_setzero_si128()); - tmp_0 = _mm_madd_epi16(resReg56_lo_1, thirdFilters); - tmp_1 = _mm_madd_epi16(resReg56_lo_2, thirdFilters); - resReg56_lo = _mm_packs_epi32(tmp_0, tmp_1); - - // add and saturate the results together - resReg23_45_lo = _mm_adds_epi16(resReg23_lo, resReg45_lo); - resReg34_56_lo = _mm_adds_epi16(resReg34_lo, resReg56_lo); - - // shift by 6 bit each 16 bit - resReg23_45_lo = _mm_adds_epi16(resReg23_45_lo, addFilterReg32); - resReg34_56_lo = _mm_adds_epi16(resReg34_56_lo, addFilterReg32); - resReg23_45_lo = _mm_srai_epi16(resReg23_45_lo, 6); - resReg34_56_lo = _mm_srai_epi16(resReg34_56_lo, 6); - - // shrink to 8 bit each 16 bits, the first lane contain the first - // convolve result and the second lane contain the second convolve - // result - resReg23_45 = _mm_packus_epi16(resReg23_45_lo, _mm_setzero_si128()); - resReg34_56 = _mm_packus_epi16(resReg34_56_lo, _mm_setzero_si128()); - - src_ptr += src_stride; - - _mm_storel_epi64((__m128i *)output_ptr, (resReg23_45)); - _mm_storel_epi64((__m128i *)(output_ptr + out_pitch), (resReg34_56)); - - output_ptr += dst_stride; - - // save part of the registers for next strides - resReg23_lo_1 = resReg45_lo_1; - resReg23_lo_2 = resReg45_lo_2; - resReg34_lo_1 = resReg56_lo_1; - resReg34_lo_2 = resReg56_lo_2; - srcReg4 = srcReg6; - } -} - -void aom_filter_block1d4_h4_sse2(const uint8_t *src_ptr, - ptrdiff_t src_pixels_per_line, - uint8_t *output_ptr, ptrdiff_t output_pitch, - uint32_t output_height, - const int16_t *filter) { - __m128i filtersReg; - __m128i addFilterReg32; - __m128i secondFilters, thirdFilters; - __m128i srcRegFilt32b1_1; - __m128i srcReg32b1; - unsigned int i; - src_ptr -= 3; - addFilterReg32 = _mm_set1_epi16(32); - filtersReg = _mm_loadu_si128((const __m128i *)filter); - filtersReg = _mm_srai_epi16(filtersReg, 1); - - // coeffs 0 1 0 1 2 3 2 3 - const __m128i tmp_0 = _mm_unpacklo_epi32(filtersReg, filtersReg); - // coeffs 4 5 4 5 6 7 6 7 - const __m128i tmp_1 = _mm_unpackhi_epi32(filtersReg, filtersReg); - - secondFilters = _mm_unpackhi_epi64(tmp_0, tmp_0); // coeffs 2 3 2 3 2 3 2 3 - thirdFilters = _mm_unpacklo_epi64(tmp_1, tmp_1); // coeffs 4 5 4 5 4 5 4 5 - - for (i = output_height; i > 0; i -= 1) { - srcReg32b1 = _mm_loadu_si128((const __m128i *)src_ptr); - - __m128i ss_2 = _mm_srli_si128(srcReg32b1, 2); - __m128i ss_3 = _mm_srli_si128(srcReg32b1, 3); - __m128i ss_4 = _mm_srli_si128(srcReg32b1, 4); - __m128i ss_5 = _mm_srli_si128(srcReg32b1, 5); - - ss_2 = _mm_unpacklo_epi8(ss_2, _mm_setzero_si128()); - ss_3 = _mm_unpacklo_epi8(ss_3, _mm_setzero_si128()); - ss_4 = _mm_unpacklo_epi8(ss_4, _mm_setzero_si128()); - ss_5 = _mm_unpacklo_epi8(ss_5, _mm_setzero_si128()); - - __m128i ss_1_1 = _mm_unpacklo_epi32(ss_2, ss_3); - __m128i ss_1_2 = _mm_unpacklo_epi32(ss_4, ss_5); - - __m128i d1 = _mm_madd_epi16(ss_1_1, secondFilters); - __m128i d2 = _mm_madd_epi16(ss_1_2, thirdFilters); - srcRegFilt32b1_1 = _mm_add_epi32(d1, d2); - - srcRegFilt32b1_1 = _mm_packs_epi32(srcRegFilt32b1_1, _mm_setzero_si128()); - - // shift by 6 bit each 16 bit - srcRegFilt32b1_1 = _mm_adds_epi16(srcRegFilt32b1_1, addFilterReg32); - srcRegFilt32b1_1 = _mm_srai_epi16(srcRegFilt32b1_1, 6); - - // shrink to 8 bit each 16 bits, the first lane contain the first - // convolve result and the second lane contain the second convolve result - srcRegFilt32b1_1 = _mm_packus_epi16(srcRegFilt32b1_1, _mm_setzero_si128()); - - src_ptr += src_pixels_per_line; - - *((int *)(output_ptr)) = _mm_cvtsi128_si32(srcRegFilt32b1_1); - - output_ptr += output_pitch; - } -} - -void aom_filter_block1d4_v4_sse2(const uint8_t *src_ptr, ptrdiff_t src_pitch, - uint8_t *output_ptr, ptrdiff_t out_pitch, - uint32_t output_height, - const int16_t *filter) { - __m128i filtersReg; - __m128i srcReg2, srcReg3, srcReg4, srcReg5, srcReg6; - __m128i srcReg23, srcReg34, srcReg45, srcReg56; - __m128i resReg23_34, resReg45_56; - __m128i resReg23_34_45_56; - __m128i addFilterReg32, secondFilters, thirdFilters; - __m128i tmp_0, tmp_1; - unsigned int i; - ptrdiff_t src_stride, dst_stride; - - addFilterReg32 = _mm_set1_epi16(32); - filtersReg = _mm_loadu_si128((const __m128i *)filter); - filtersReg = _mm_srai_epi16(filtersReg, 1); - - // coeffs 0 1 0 1 2 3 2 3 - const __m128i tmp0 = _mm_unpacklo_epi32(filtersReg, filtersReg); - // coeffs 4 5 4 5 6 7 6 7 - const __m128i tmp1 = _mm_unpackhi_epi32(filtersReg, filtersReg); - - secondFilters = _mm_unpackhi_epi64(tmp0, tmp0); // coeffs 2 3 2 3 2 3 2 3 - thirdFilters = _mm_unpacklo_epi64(tmp1, tmp1); // coeffs 4 5 4 5 4 5 4 5 - - // multiply the size of the source and destination stride by two - src_stride = src_pitch << 1; - dst_stride = out_pitch << 1; - - srcReg2 = _mm_loadl_epi64((const __m128i *)(src_ptr + src_pitch * 2)); - srcReg3 = _mm_loadl_epi64((const __m128i *)(src_ptr + src_pitch * 3)); - srcReg23 = _mm_unpacklo_epi8(srcReg2, srcReg3); - __m128i resReg23 = _mm_unpacklo_epi8(srcReg23, _mm_setzero_si128()); - - srcReg4 = _mm_loadl_epi64((const __m128i *)(src_ptr + src_pitch * 4)); - srcReg34 = _mm_unpacklo_epi8(srcReg3, srcReg4); - __m128i resReg34 = _mm_unpacklo_epi8(srcReg34, _mm_setzero_si128()); - - for (i = output_height; i > 1; i -= 2) { - srcReg5 = _mm_loadl_epi64((const __m128i *)(src_ptr + src_pitch * 5)); - srcReg45 = _mm_unpacklo_epi8(srcReg4, srcReg5); - srcReg6 = _mm_loadl_epi64((const __m128i *)(src_ptr + src_pitch * 6)); - srcReg56 = _mm_unpacklo_epi8(srcReg5, srcReg6); - - // multiply 2 adjacent elements with the filter and add the result - tmp_0 = _mm_madd_epi16(resReg23, secondFilters); - tmp_1 = _mm_madd_epi16(resReg34, secondFilters); - resReg23_34 = _mm_packs_epi32(tmp_0, tmp_1); - - __m128i resReg45 = _mm_unpacklo_epi8(srcReg45, _mm_setzero_si128()); - __m128i resReg56 = _mm_unpacklo_epi8(srcReg56, _mm_setzero_si128()); - - tmp_0 = _mm_madd_epi16(resReg45, thirdFilters); - tmp_1 = _mm_madd_epi16(resReg56, thirdFilters); - resReg45_56 = _mm_packs_epi32(tmp_0, tmp_1); - - // add and saturate the results together - resReg23_34_45_56 = _mm_adds_epi16(resReg23_34, resReg45_56); - - // shift by 6 bit each 16 bit - resReg23_34_45_56 = _mm_adds_epi16(resReg23_34_45_56, addFilterReg32); - resReg23_34_45_56 = _mm_srai_epi16(resReg23_34_45_56, 6); - - // shrink to 8 bit each 16 bits, the first lane contain the first - // convolve result and the second lane contain the second convolve - // result - resReg23_34_45_56 = - _mm_packus_epi16(resReg23_34_45_56, _mm_setzero_si128()); - - src_ptr += src_stride; - - *((int *)(output_ptr)) = _mm_cvtsi128_si32(resReg23_34_45_56); - *((int *)(output_ptr + out_pitch)) = - _mm_cvtsi128_si32(_mm_srli_si128(resReg23_34_45_56, 4)); - - output_ptr += dst_stride; - - // save part of the registers for next strides - resReg23 = resReg45; - resReg34 = resReg56; - srcReg4 = srcReg6; - } -} diff --git a/third_party/aom/aom_dsp/x86/aom_subpixel_8t_sse2.asm b/third_party/aom/aom_dsp/x86/aom_subpixel_8t_sse2.asm deleted file mode 100644 index 640c5b2416..0000000000 --- a/third_party/aom/aom_dsp/x86/aom_subpixel_8t_sse2.asm +++ /dev/null @@ -1,615 +0,0 @@ -; -; Copyright (c) 2016, Alliance for Open Media. All rights reserved -; -; This source code is subject to the terms of the BSD 2 Clause License and -; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License -; was not distributed with this source code in the LICENSE file, you can -; obtain it at www.aomedia.org/license/software. If the Alliance for Open -; Media Patent License 1.0 was not distributed with this source code in the -; PATENTS file, you can obtain it at www.aomedia.org/license/patent. -; - -; - - -%include "aom_ports/x86_abi_support.asm" - -;Note: tap3 and tap4 have to be applied and added after other taps to avoid -;overflow. - -%macro GET_FILTERS_4 0 - mov rdx, arg(5) ;filter ptr - mov rcx, 0x0400040 - - movdqa xmm7, [rdx] ;load filters - pshuflw xmm0, xmm7, 0b ;k0 - pshuflw xmm1, xmm7, 01010101b ;k1 - pshuflw xmm2, xmm7, 10101010b ;k2 - pshuflw xmm3, xmm7, 11111111b ;k3 - psrldq xmm7, 8 - pshuflw xmm4, xmm7, 0b ;k4 - pshuflw xmm5, xmm7, 01010101b ;k5 - pshuflw xmm6, xmm7, 10101010b ;k6 - pshuflw xmm7, xmm7, 11111111b ;k7 - - punpcklqdq xmm0, xmm1 - punpcklqdq xmm2, xmm3 - punpcklqdq xmm5, xmm4 - punpcklqdq xmm6, xmm7 - - movdqa k0k1, xmm0 - movdqa k2k3, xmm2 - movdqa k5k4, xmm5 - movdqa k6k7, xmm6 - - movq xmm6, rcx - pshufd xmm6, xmm6, 0 - movdqa krd, xmm6 - - pxor xmm7, xmm7 - movdqa zero, xmm7 -%endm - -%macro APPLY_FILTER_4 1 - punpckldq xmm0, xmm1 ;two row in one register - punpckldq xmm6, xmm7 - punpckldq xmm2, xmm3 - punpckldq xmm5, xmm4 - - punpcklbw xmm0, zero ;unpack to word - punpcklbw xmm6, zero - punpcklbw xmm2, zero - punpcklbw xmm5, zero - - pmullw xmm0, k0k1 ;multiply the filter factors - pmullw xmm6, k6k7 - pmullw xmm2, k2k3 - pmullw xmm5, k5k4 - - paddsw xmm0, xmm6 ;sum - movdqa xmm1, xmm0 - psrldq xmm1, 8 - paddsw xmm0, xmm1 - paddsw xmm0, xmm2 - psrldq xmm2, 8 - paddsw xmm0, xmm5 - psrldq xmm5, 8 - paddsw xmm0, xmm2 - paddsw xmm0, xmm5 - - paddsw xmm0, krd ;rounding - psraw xmm0, 7 ;shift - packuswb xmm0, xmm0 ;pack to byte - -%if %1 - movd xmm1, [rdi] - pavgb xmm0, xmm1 -%endif - movd [rdi], xmm0 -%endm - -%macro GET_FILTERS 0 - mov rdx, arg(5) ;filter ptr - mov rsi, arg(0) ;src_ptr - mov rdi, arg(2) ;output_ptr - mov rcx, 0x0400040 - - movdqa xmm7, [rdx] ;load filters - pshuflw xmm0, xmm7, 0b ;k0 - pshuflw xmm1, xmm7, 01010101b ;k1 - pshuflw xmm2, xmm7, 10101010b ;k2 - pshuflw xmm3, xmm7, 11111111b ;k3 - pshufhw xmm4, xmm7, 0b ;k4 - pshufhw xmm5, xmm7, 01010101b ;k5 - pshufhw xmm6, xmm7, 10101010b ;k6 - pshufhw xmm7, xmm7, 11111111b ;k7 - - punpcklwd xmm0, xmm0 - punpcklwd xmm1, xmm1 - punpcklwd xmm2, xmm2 - punpcklwd xmm3, xmm3 - punpckhwd xmm4, xmm4 - punpckhwd xmm5, xmm5 - punpckhwd xmm6, xmm6 - punpckhwd xmm7, xmm7 - - movdqa k0, xmm0 ;store filter factors on stack - movdqa k1, xmm1 - movdqa k2, xmm2 - movdqa k3, xmm3 - movdqa k4, xmm4 - movdqa k5, xmm5 - movdqa k6, xmm6 - movdqa k7, xmm7 - - movq xmm6, rcx - pshufd xmm6, xmm6, 0 - movdqa krd, xmm6 ;rounding - - pxor xmm7, xmm7 - movdqa zero, xmm7 -%endm - -%macro LOAD_VERT_8 1 - movq xmm0, [rsi + %1] ;0 - movq xmm1, [rsi + rax + %1] ;1 - movq xmm6, [rsi + rdx * 2 + %1] ;6 - lea rsi, [rsi + rax] - movq xmm7, [rsi + rdx * 2 + %1] ;7 - movq xmm2, [rsi + rax + %1] ;2 - movq xmm3, [rsi + rax * 2 + %1] ;3 - movq xmm4, [rsi + rdx + %1] ;4 - movq xmm5, [rsi + rax * 4 + %1] ;5 -%endm - -%macro APPLY_FILTER_8 2 - punpcklbw xmm0, zero - punpcklbw xmm1, zero - punpcklbw xmm6, zero - punpcklbw xmm7, zero - punpcklbw xmm2, zero - punpcklbw xmm5, zero - punpcklbw xmm3, zero - punpcklbw xmm4, zero - - pmullw xmm0, k0 - pmullw xmm1, k1 - pmullw xmm6, k6 - pmullw xmm7, k7 - pmullw xmm2, k2 - pmullw xmm5, k5 - pmullw xmm3, k3 - pmullw xmm4, k4 - - paddsw xmm0, xmm1 - paddsw xmm0, xmm6 - paddsw xmm0, xmm7 - paddsw xmm0, xmm2 - paddsw xmm0, xmm5 - paddsw xmm0, xmm3 - paddsw xmm0, xmm4 - - paddsw xmm0, krd ;rounding - psraw xmm0, 7 ;shift - packuswb xmm0, xmm0 ;pack back to byte -%if %1 - movq xmm1, [rdi + %2] - pavgb xmm0, xmm1 -%endif - movq [rdi + %2], xmm0 -%endm - -SECTION .text - -;void aom_filter_block1d4_v8_sse2 -;( -; unsigned char *src_ptr, -; unsigned int src_pitch, -; unsigned char *output_ptr, -; unsigned int out_pitch, -; unsigned int output_height, -; short *filter -;) -globalsym(aom_filter_block1d4_v8_sse2) -sym(aom_filter_block1d4_v8_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - push rbx - ; end prolog - - ALIGN_STACK 16, rax - sub rsp, 16 * 6 - %define k0k1 [rsp + 16 * 0] - %define k2k3 [rsp + 16 * 1] - %define k5k4 [rsp + 16 * 2] - %define k6k7 [rsp + 16 * 3] - %define krd [rsp + 16 * 4] - %define zero [rsp + 16 * 5] - - GET_FILTERS_4 - - mov rsi, arg(0) ;src_ptr - mov rdi, arg(2) ;output_ptr - - movsxd rax, DWORD PTR arg(1) ;pixels_per_line - movsxd rbx, DWORD PTR arg(3) ;out_pitch - lea rdx, [rax + rax * 2] - movsxd rcx, DWORD PTR arg(4) ;output_height - -.loop: - movd xmm0, [rsi] ;load src: row 0 - movd xmm1, [rsi + rax] ;1 - movd xmm6, [rsi + rdx * 2] ;6 - lea rsi, [rsi + rax] - movd xmm7, [rsi + rdx * 2] ;7 - movd xmm2, [rsi + rax] ;2 - movd xmm3, [rsi + rax * 2] ;3 - movd xmm4, [rsi + rdx] ;4 - movd xmm5, [rsi + rax * 4] ;5 - - APPLY_FILTER_4 0 - - lea rdi, [rdi + rbx] - dec rcx - jnz .loop - - add rsp, 16 * 6 - pop rsp - pop rbx - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -;void aom_filter_block1d8_v8_sse2 -;( -; unsigned char *src_ptr, -; unsigned int src_pitch, -; unsigned char *output_ptr, -; unsigned int out_pitch, -; unsigned int output_height, -; short *filter -;) -globalsym(aom_filter_block1d8_v8_sse2) -sym(aom_filter_block1d8_v8_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - push rbx - ; end prolog - - ALIGN_STACK 16, rax - sub rsp, 16 * 10 - %define k0 [rsp + 16 * 0] - %define k1 [rsp + 16 * 1] - %define k2 [rsp + 16 * 2] - %define k3 [rsp + 16 * 3] - %define k4 [rsp + 16 * 4] - %define k5 [rsp + 16 * 5] - %define k6 [rsp + 16 * 6] - %define k7 [rsp + 16 * 7] - %define krd [rsp + 16 * 8] - %define zero [rsp + 16 * 9] - - GET_FILTERS - - movsxd rax, DWORD PTR arg(1) ;pixels_per_line - movsxd rbx, DWORD PTR arg(3) ;out_pitch - lea rdx, [rax + rax * 2] - movsxd rcx, DWORD PTR arg(4) ;output_height - -.loop: - LOAD_VERT_8 0 - APPLY_FILTER_8 0, 0 - - lea rdi, [rdi + rbx] - dec rcx - jnz .loop - - add rsp, 16 * 10 - pop rsp - pop rbx - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -;void aom_filter_block1d16_v8_sse2 -;( -; unsigned char *src_ptr, -; unsigned int src_pitch, -; unsigned char *output_ptr, -; unsigned int out_pitch, -; unsigned int output_height, -; short *filter -;) -globalsym(aom_filter_block1d16_v8_sse2) -sym(aom_filter_block1d16_v8_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - push rbx - ; end prolog - - ALIGN_STACK 16, rax - sub rsp, 16 * 10 - %define k0 [rsp + 16 * 0] - %define k1 [rsp + 16 * 1] - %define k2 [rsp + 16 * 2] - %define k3 [rsp + 16 * 3] - %define k4 [rsp + 16 * 4] - %define k5 [rsp + 16 * 5] - %define k6 [rsp + 16 * 6] - %define k7 [rsp + 16 * 7] - %define krd [rsp + 16 * 8] - %define zero [rsp + 16 * 9] - - GET_FILTERS - - movsxd rax, DWORD PTR arg(1) ;pixels_per_line - movsxd rbx, DWORD PTR arg(3) ;out_pitch - lea rdx, [rax + rax * 2] - movsxd rcx, DWORD PTR arg(4) ;output_height - -.loop: - LOAD_VERT_8 0 - APPLY_FILTER_8 0, 0 - sub rsi, rax - - LOAD_VERT_8 8 - APPLY_FILTER_8 0, 8 - add rdi, rbx - - dec rcx - jnz .loop - - add rsp, 16 * 10 - pop rsp - pop rbx - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -;void aom_filter_block1d4_h8_sse2 -;( -; unsigned char *src_ptr, -; unsigned int src_pixels_per_line, -; unsigned char *output_ptr, -; unsigned int output_pitch, -; unsigned int output_height, -; short *filter -;) -globalsym(aom_filter_block1d4_h8_sse2) -sym(aom_filter_block1d4_h8_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - ; end prolog - - ALIGN_STACK 16, rax - sub rsp, 16 * 6 - %define k0k1 [rsp + 16 * 0] - %define k2k3 [rsp + 16 * 1] - %define k5k4 [rsp + 16 * 2] - %define k6k7 [rsp + 16 * 3] - %define krd [rsp + 16 * 4] - %define zero [rsp + 16 * 5] - - GET_FILTERS_4 - - mov rsi, arg(0) ;src_ptr - mov rdi, arg(2) ;output_ptr - - movsxd rax, DWORD PTR arg(1) ;pixels_per_line - movsxd rdx, DWORD PTR arg(3) ;out_pitch - movsxd rcx, DWORD PTR arg(4) ;output_height - -.loop: - movdqu xmm0, [rsi - 3] ;load src - - movdqa xmm1, xmm0 - movdqa xmm6, xmm0 - movdqa xmm7, xmm0 - movdqa xmm2, xmm0 - movdqa xmm3, xmm0 - movdqa xmm5, xmm0 - movdqa xmm4, xmm0 - - psrldq xmm1, 1 - psrldq xmm6, 6 - psrldq xmm7, 7 - psrldq xmm2, 2 - psrldq xmm3, 3 - psrldq xmm5, 5 - psrldq xmm4, 4 - - APPLY_FILTER_4 0 - - lea rsi, [rsi + rax] - lea rdi, [rdi + rdx] - dec rcx - jnz .loop - - add rsp, 16 * 6 - pop rsp - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -;void aom_filter_block1d8_h8_sse2 -;( -; unsigned char *src_ptr, -; unsigned int src_pixels_per_line, -; unsigned char *output_ptr, -; unsigned int output_pitch, -; unsigned int output_height, -; short *filter -;) -globalsym(aom_filter_block1d8_h8_sse2) -sym(aom_filter_block1d8_h8_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - ; end prolog - - ALIGN_STACK 16, rax - sub rsp, 16 * 10 - %define k0 [rsp + 16 * 0] - %define k1 [rsp + 16 * 1] - %define k2 [rsp + 16 * 2] - %define k3 [rsp + 16 * 3] - %define k4 [rsp + 16 * 4] - %define k5 [rsp + 16 * 5] - %define k6 [rsp + 16 * 6] - %define k7 [rsp + 16 * 7] - %define krd [rsp + 16 * 8] - %define zero [rsp + 16 * 9] - - GET_FILTERS - - movsxd rax, DWORD PTR arg(1) ;pixels_per_line - movsxd rdx, DWORD PTR arg(3) ;out_pitch - movsxd rcx, DWORD PTR arg(4) ;output_height - -.loop: - movdqu xmm0, [rsi - 3] ;load src - - movdqa xmm1, xmm0 - movdqa xmm6, xmm0 - movdqa xmm7, xmm0 - movdqa xmm2, xmm0 - movdqa xmm5, xmm0 - movdqa xmm3, xmm0 - movdqa xmm4, xmm0 - - psrldq xmm1, 1 - psrldq xmm6, 6 - psrldq xmm7, 7 - psrldq xmm2, 2 - psrldq xmm5, 5 - psrldq xmm3, 3 - psrldq xmm4, 4 - - APPLY_FILTER_8 0, 0 - - lea rsi, [rsi + rax] - lea rdi, [rdi + rdx] - dec rcx - jnz .loop - - add rsp, 16 * 10 - pop rsp - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -;void aom_filter_block1d16_h8_sse2 -;( -; unsigned char *src_ptr, -; unsigned int src_pixels_per_line, -; unsigned char *output_ptr, -; unsigned int output_pitch, -; unsigned int output_height, -; short *filter -;) -globalsym(aom_filter_block1d16_h8_sse2) -sym(aom_filter_block1d16_h8_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - ; end prolog - - ALIGN_STACK 16, rax - sub rsp, 16 * 10 - %define k0 [rsp + 16 * 0] - %define k1 [rsp + 16 * 1] - %define k2 [rsp + 16 * 2] - %define k3 [rsp + 16 * 3] - %define k4 [rsp + 16 * 4] - %define k5 [rsp + 16 * 5] - %define k6 [rsp + 16 * 6] - %define k7 [rsp + 16 * 7] - %define krd [rsp + 16 * 8] - %define zero [rsp + 16 * 9] - - GET_FILTERS - - movsxd rax, DWORD PTR arg(1) ;pixels_per_line - movsxd rdx, DWORD PTR arg(3) ;out_pitch - movsxd rcx, DWORD PTR arg(4) ;output_height - -.loop: - movdqu xmm0, [rsi - 3] ;load src - - movdqa xmm1, xmm0 - movdqa xmm6, xmm0 - movdqa xmm7, xmm0 - movdqa xmm2, xmm0 - movdqa xmm5, xmm0 - movdqa xmm3, xmm0 - movdqa xmm4, xmm0 - - psrldq xmm1, 1 - psrldq xmm6, 6 - psrldq xmm7, 7 - psrldq xmm2, 2 - psrldq xmm5, 5 - psrldq xmm3, 3 - psrldq xmm4, 4 - - APPLY_FILTER_8 0, 0 - - movdqu xmm0, [rsi + 5] ;load src - - movdqa xmm1, xmm0 - movdqa xmm6, xmm0 - movdqa xmm7, xmm0 - movdqa xmm2, xmm0 - movdqa xmm5, xmm0 - movdqa xmm3, xmm0 - movdqa xmm4, xmm0 - - psrldq xmm1, 1 - psrldq xmm6, 6 - psrldq xmm7, 7 - psrldq xmm2, 2 - psrldq xmm5, 5 - psrldq xmm3, 3 - psrldq xmm4, 4 - - APPLY_FILTER_8 0, 8 - - lea rsi, [rsi + rax] - lea rdi, [rdi + rdx] - dec rcx - jnz .loop - - add rsp, 16 * 10 - pop rsp - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret diff --git a/third_party/aom/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm b/third_party/aom/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm deleted file mode 100644 index 90dd55a4be..0000000000 --- a/third_party/aom/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm +++ /dev/null @@ -1,295 +0,0 @@ -; -; Copyright (c) 2016, Alliance for Open Media. All rights reserved -; -; This source code is subject to the terms of the BSD 2 Clause License and -; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License -; was not distributed with this source code in the LICENSE file, you can -; obtain it at www.aomedia.org/license/software. If the Alliance for Open -; Media Patent License 1.0 was not distributed with this source code in the -; PATENTS file, you can obtain it at www.aomedia.org/license/patent. -; - -; - -%include "aom_ports/x86_abi_support.asm" - -%macro GET_PARAM_4 0 - mov rdx, arg(5) ;filter ptr - mov rsi, arg(0) ;src_ptr - mov rdi, arg(2) ;output_ptr - mov rcx, 0x0400040 - - movdqa xmm3, [rdx] ;load filters - pshuflw xmm4, xmm3, 11111111b ;k3 - psrldq xmm3, 8 - pshuflw xmm3, xmm3, 0b ;k4 - punpcklqdq xmm4, xmm3 ;k3k4 - - movq xmm3, rcx ;rounding - pshufd xmm3, xmm3, 0 - - pxor xmm2, xmm2 - - movsxd rax, DWORD PTR arg(1) ;pixels_per_line - movsxd rdx, DWORD PTR arg(3) ;out_pitch - movsxd rcx, DWORD PTR arg(4) ;output_height -%endm - -%macro APPLY_FILTER_4 1 - - punpckldq xmm0, xmm1 ;two row in one register - punpcklbw xmm0, xmm2 ;unpack to word - pmullw xmm0, xmm4 ;multiply the filter factors - - movdqa xmm1, xmm0 - psrldq xmm1, 8 - paddsw xmm0, xmm1 - - paddsw xmm0, xmm3 ;rounding - psraw xmm0, 7 ;shift - packuswb xmm0, xmm0 ;pack to byte - -%if %1 - movd xmm1, [rdi] - pavgb xmm0, xmm1 -%endif - - movd [rdi], xmm0 - lea rsi, [rsi + rax] - lea rdi, [rdi + rdx] - dec rcx -%endm - -%macro GET_PARAM 0 - mov rdx, arg(5) ;filter ptr - mov rsi, arg(0) ;src_ptr - mov rdi, arg(2) ;output_ptr - mov rcx, 0x0400040 - - movdqa xmm7, [rdx] ;load filters - - pshuflw xmm6, xmm7, 11111111b ;k3 - pshufhw xmm7, xmm7, 0b ;k4 - punpcklwd xmm6, xmm6 - punpckhwd xmm7, xmm7 - - movq xmm4, rcx ;rounding - pshufd xmm4, xmm4, 0 - - pxor xmm5, xmm5 - - movsxd rax, DWORD PTR arg(1) ;pixels_per_line - movsxd rdx, DWORD PTR arg(3) ;out_pitch - movsxd rcx, DWORD PTR arg(4) ;output_height -%endm - -%macro APPLY_FILTER_8 1 - punpcklbw xmm0, xmm5 - punpcklbw xmm1, xmm5 - - pmullw xmm0, xmm6 - pmullw xmm1, xmm7 - paddsw xmm0, xmm1 - paddsw xmm0, xmm4 ;rounding - psraw xmm0, 7 ;shift - packuswb xmm0, xmm0 ;pack back to byte -%if %1 - movq xmm1, [rdi] - pavgb xmm0, xmm1 -%endif - movq [rdi], xmm0 ;store the result - - lea rsi, [rsi + rax] - lea rdi, [rdi + rdx] - dec rcx -%endm - -%macro APPLY_FILTER_16 1 - punpcklbw xmm0, xmm5 - punpcklbw xmm1, xmm5 - punpckhbw xmm2, xmm5 - punpckhbw xmm3, xmm5 - - pmullw xmm0, xmm6 - pmullw xmm1, xmm7 - pmullw xmm2, xmm6 - pmullw xmm3, xmm7 - - paddsw xmm0, xmm1 - paddsw xmm2, xmm3 - - paddsw xmm0, xmm4 ;rounding - paddsw xmm2, xmm4 - psraw xmm0, 7 ;shift - psraw xmm2, 7 - packuswb xmm0, xmm2 ;pack back to byte -%if %1 - movdqu xmm1, [rdi] - pavgb xmm0, xmm1 -%endif - movdqu [rdi], xmm0 ;store the result - - lea rsi, [rsi + rax] - lea rdi, [rdi + rdx] - dec rcx -%endm - -SECTION .text - -globalsym(aom_filter_block1d4_v2_sse2) -sym(aom_filter_block1d4_v2_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - push rsi - push rdi - ; end prolog - - GET_PARAM_4 -.loop: - movd xmm0, [rsi] ;load src - movd xmm1, [rsi + rax] - - APPLY_FILTER_4 0 - jnz .loop - - ; begin epilog - pop rdi - pop rsi - UNSHADOW_ARGS - pop rbp - ret - -globalsym(aom_filter_block1d8_v2_sse2) -sym(aom_filter_block1d8_v2_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - ; end prolog - - GET_PARAM -.loop: - movq xmm0, [rsi] ;0 - movq xmm1, [rsi + rax] ;1 - - APPLY_FILTER_8 0 - jnz .loop - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -globalsym(aom_filter_block1d16_v2_sse2) -sym(aom_filter_block1d16_v2_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - ; end prolog - - GET_PARAM -.loop: - movdqu xmm0, [rsi] ;0 - movdqu xmm1, [rsi + rax] ;1 - movdqa xmm2, xmm0 - movdqa xmm3, xmm1 - - APPLY_FILTER_16 0 - jnz .loop - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -globalsym(aom_filter_block1d4_h2_sse2) -sym(aom_filter_block1d4_h2_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - push rsi - push rdi - ; end prolog - - GET_PARAM_4 -.loop: - movdqu xmm0, [rsi] ;load src - movdqa xmm1, xmm0 - psrldq xmm1, 1 - - APPLY_FILTER_4 0 - jnz .loop - - ; begin epilog - pop rdi - pop rsi - UNSHADOW_ARGS - pop rbp - ret - -globalsym(aom_filter_block1d8_h2_sse2) -sym(aom_filter_block1d8_h2_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - ; end prolog - - GET_PARAM -.loop: - movdqu xmm0, [rsi] ;load src - movdqa xmm1, xmm0 - psrldq xmm1, 1 - - APPLY_FILTER_8 0 - jnz .loop - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -globalsym(aom_filter_block1d16_h2_sse2) -sym(aom_filter_block1d16_h2_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 6 - SAVE_XMM 7 - push rsi - push rdi - ; end prolog - - GET_PARAM -.loop: - movdqu xmm0, [rsi] ;load src - movdqu xmm1, [rsi + 1] - movdqa xmm2, xmm0 - movdqa xmm3, xmm1 - - APPLY_FILTER_16 0 - jnz .loop - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret diff --git a/third_party/aom/aom_dsp/x86/avg_intrin_sse2.c b/third_party/aom/aom_dsp/x86/avg_intrin_sse2.c index 9ab9143eee..0b552b704b 100644 --- a/third_party/aom/aom_dsp/x86/avg_intrin_sse2.c +++ b/third_party/aom/aom_dsp/x86/avg_intrin_sse2.c @@ -133,7 +133,7 @@ unsigned int aom_avg_8x8_sse2(const uint8_t *s, int p) { return (avg + 32) >> 6; } -void calc_avg_8x8_dual_sse2(const uint8_t *s, int p, int *avg) { +static void calc_avg_8x8_dual_sse2(const uint8_t *s, int p, int *avg) { __m128i sum0, sum1, s0, s1, s2, s3, u0; u0 = _mm_setzero_si128(); s0 = _mm_sad_epu8(_mm_loadu_si128((const __m128i *)(s)), u0); diff --git a/third_party/aom/aom_dsp/x86/fwd_txfm_impl_sse2.h b/third_party/aom/aom_dsp/x86/fwd_txfm_impl_sse2.h index 7ee8ba330e..e1db3b950c 100644 --- a/third_party/aom/aom_dsp/x86/fwd_txfm_impl_sse2.h +++ b/third_party/aom/aom_dsp/x86/fwd_txfm_impl_sse2.h @@ -30,6 +30,7 @@ #define SUB_EPI16 _mm_sub_epi16 #endif +#if defined(FDCT4x4_2D_HELPER) static void FDCT4x4_2D_HELPER(const int16_t *input, int stride, __m128i *in0, __m128i *in1) { // Constants @@ -185,7 +186,9 @@ static void FDCT4x4_2D_HELPER(const int16_t *input, int stride, __m128i *in0, } } } +#endif // defined(FDCT4x4_2D_HELPER) +#if defined(FDCT4x4_2D) void FDCT4x4_2D(const int16_t *input, tran_low_t *output, int stride) { // This 2D transform implements 4 vertical 1D transforms followed // by 4 horizontal 1D transforms. The multiplies and adds are as given @@ -205,13 +208,16 @@ void FDCT4x4_2D(const int16_t *input, tran_low_t *output, int stride) { storeu_output(&in0, output + 0 * 4); storeu_output(&in1, output + 2 * 4); } +#endif // defined(FDCT4x4_2D) +#if defined(FDCT4x4_2D_LP) void FDCT4x4_2D_LP(const int16_t *input, int16_t *output, int stride) { __m128i in0, in1; FDCT4x4_2D_HELPER(input, stride, &in0, &in1); _mm_storeu_si128((__m128i *)(output + 0 * 4), in0); _mm_storeu_si128((__m128i *)(output + 2 * 4), in1); } +#endif // defined(FDCT4x4_2D_LP) #if CONFIG_INTERNAL_STATS void FDCT8x8_2D(const int16_t *input, tran_low_t *output, int stride) { diff --git a/third_party/aom/aom_dsp/x86/highbd_variance_avx2.c b/third_party/aom/aom_dsp/x86/highbd_variance_avx2.c index b4ff91d856..21e9e8b282 100644 --- a/third_party/aom/aom_dsp/x86/highbd_variance_avx2.c +++ b/third_party/aom/aom_dsp/x86/highbd_variance_avx2.c @@ -618,9 +618,9 @@ static uint32_t aom_highbd_var_filter_block2d_bil_avx2( return (var > 0) ? var : 0; } -void aom_highbd_calc8x8var_avx2(const uint16_t *src, int src_stride, - const uint16_t *ref, int ref_stride, - uint32_t *sse, int *sum) { +static void highbd_calc8x8var_avx2(const uint16_t *src, int src_stride, + const uint16_t *ref, int ref_stride, + uint32_t *sse, int *sum) { __m256i v_sum_d = _mm256_setzero_si256(); __m256i v_sse_d = _mm256_setzero_si256(); for (int i = 0; i < 8; i += 2) { @@ -653,9 +653,9 @@ void aom_highbd_calc8x8var_avx2(const uint16_t *src, int src_stride, *sse = _mm_extract_epi32(v_d, 1); } -void aom_highbd_calc16x16var_avx2(const uint16_t *src, int src_stride, - const uint16_t *ref, int ref_stride, - uint32_t *sse, int *sum) { +static void highbd_calc16x16var_avx2(const uint16_t *src, int src_stride, + const uint16_t *ref, int ref_stride, + uint32_t *sse, int *sum) { __m256i v_sum_d = _mm256_setzero_si256(); __m256i v_sse_d = _mm256_setzero_si256(); const __m256i one = _mm256_set1_epi16(1); @@ -703,19 +703,19 @@ static void highbd_10_variance_avx2(const uint16_t *src, int src_stride, *sse = (uint32_t)ROUND_POWER_OF_TWO(sse_long, 4); } -#define VAR_FN(w, h, block_size, shift) \ - uint32_t aom_highbd_10_variance##w##x##h##_avx2( \ - const uint8_t *src8, int src_stride, const uint8_t *ref8, \ - int ref_stride, uint32_t *sse) { \ - int sum; \ - int64_t var; \ - uint16_t *src = CONVERT_TO_SHORTPTR(src8); \ - uint16_t *ref = CONVERT_TO_SHORTPTR(ref8); \ - highbd_10_variance_avx2( \ - src, src_stride, ref, ref_stride, w, h, sse, &sum, \ - aom_highbd_calc##block_size##x##block_size##var_avx2, block_size); \ - var = (int64_t)(*sse) - (((int64_t)sum * sum) >> shift); \ - return (var >= 0) ? (uint32_t)var : 0; \ +#define VAR_FN(w, h, block_size, shift) \ + uint32_t aom_highbd_10_variance##w##x##h##_avx2( \ + const uint8_t *src8, int src_stride, const uint8_t *ref8, \ + int ref_stride, uint32_t *sse) { \ + int sum; \ + int64_t var; \ + uint16_t *src = CONVERT_TO_SHORTPTR(src8); \ + uint16_t *ref = CONVERT_TO_SHORTPTR(ref8); \ + highbd_10_variance_avx2(src, src_stride, ref, ref_stride, w, h, sse, &sum, \ + highbd_calc##block_size##x##block_size##var_avx2, \ + block_size); \ + var = (int64_t)(*sse) - (((int64_t)sum * sum) >> shift); \ + return (var >= 0) ? (uint32_t)var : 0; \ } VAR_FN(128, 128, 16, 14) @@ -741,6 +741,17 @@ VAR_FN(8, 32, 8, 8) #undef VAR_FN +unsigned int aom_highbd_10_mse16x16_avx2(const uint8_t *src8, int src_stride, + const uint8_t *ref8, int ref_stride, + unsigned int *sse) { + int sum; + uint16_t *src = CONVERT_TO_SHORTPTR(src8); + uint16_t *ref = CONVERT_TO_SHORTPTR(ref8); + highbd_10_variance_avx2(src, src_stride, ref, ref_stride, 16, 16, sse, &sum, + highbd_calc16x16var_avx2, 16); + return *sse; +} + #define SSE2_HEIGHT(H) \ uint32_t aom_highbd_10_sub_pixel_variance8x##H##_sse2( \ const uint8_t *src8, int src_stride, int x_offset, int y_offset, \ @@ -749,7 +760,7 @@ VAR_FN(8, 32, 8, 8) SSE2_HEIGHT(8) SSE2_HEIGHT(16) -#undef SSE2_Height +#undef SSE2_HEIGHT #define HIGHBD_SUBPIX_VAR(W, H) \ uint32_t aom_highbd_10_sub_pixel_variance##W##x##H##_avx2( \ @@ -782,8 +793,8 @@ HIGHBD_SUBPIX_VAR(8, 8) #undef HIGHBD_SUBPIX_VAR -uint64_t aom_mse_4xh_16bit_highbd_avx2(uint16_t *dst, int dstride, - uint16_t *src, int sstride, int h) { +static uint64_t mse_4xh_16bit_highbd_avx2(uint16_t *dst, int dstride, + uint16_t *src, int sstride, int h) { uint64_t sum = 0; __m128i reg0_4x16, reg1_4x16, reg2_4x16, reg3_4x16; __m256i src0_8x16, src1_8x16, src_16x16; @@ -840,8 +851,8 @@ uint64_t aom_mse_4xh_16bit_highbd_avx2(uint16_t *dst, int dstride, return sum; } -uint64_t aom_mse_8xh_16bit_highbd_avx2(uint16_t *dst, int dstride, - uint16_t *src, int sstride, int h) { +static uint64_t mse_8xh_16bit_highbd_avx2(uint16_t *dst, int dstride, + uint16_t *src, int sstride, int h) { uint64_t sum = 0; __m256i src0_8x16, src1_8x16, src_16x16; __m256i dst0_8x16, dst1_8x16, dst_16x16; @@ -897,8 +908,8 @@ uint64_t aom_mse_wxh_16bit_highbd_avx2(uint16_t *dst, int dstride, assert((w == 8 || w == 4) && (h == 8 || h == 4) && "w=8/4 and h=8/4 must satisfy"); switch (w) { - case 4: return aom_mse_4xh_16bit_highbd_avx2(dst, dstride, src, sstride, h); - case 8: return aom_mse_8xh_16bit_highbd_avx2(dst, dstride, src, sstride, h); + case 4: return mse_4xh_16bit_highbd_avx2(dst, dstride, src, sstride, h); + case 8: return mse_8xh_16bit_highbd_avx2(dst, dstride, src, sstride, h); default: assert(0 && "unsupported width"); return -1; } } diff --git a/third_party/aom/aom_dsp/x86/highbd_variance_sse2.c b/third_party/aom/aom_dsp/x86/highbd_variance_sse2.c index e897aab645..2fc2e1c0dd 100644 --- a/third_party/aom/aom_dsp/x86/highbd_variance_sse2.c +++ b/third_party/aom/aom_dsp/x86/highbd_variance_sse2.c @@ -637,8 +637,8 @@ void aom_highbd_dist_wtd_comp_avg_pred_sse2( } } -uint64_t aom_mse_4xh_16bit_highbd_sse2(uint16_t *dst, int dstride, - uint16_t *src, int sstride, int h) { +static uint64_t mse_4xh_16bit_highbd_sse2(uint16_t *dst, int dstride, + uint16_t *src, int sstride, int h) { uint64_t sum = 0; __m128i reg0_4x16, reg1_4x16; __m128i src_8x16; @@ -682,8 +682,8 @@ uint64_t aom_mse_4xh_16bit_highbd_sse2(uint16_t *dst, int dstride, return sum; } -uint64_t aom_mse_8xh_16bit_highbd_sse2(uint16_t *dst, int dstride, - uint16_t *src, int sstride, int h) { +static uint64_t mse_8xh_16bit_highbd_sse2(uint16_t *dst, int dstride, + uint16_t *src, int sstride, int h) { uint64_t sum = 0; __m128i src_8x16; __m128i dst_8x16; @@ -728,8 +728,8 @@ uint64_t aom_mse_wxh_16bit_highbd_sse2(uint16_t *dst, int dstride, assert((w == 8 || w == 4) && (h == 8 || h == 4) && "w=8/4 and h=8/4 must satisfy"); switch (w) { - case 4: return aom_mse_4xh_16bit_highbd_sse2(dst, dstride, src, sstride, h); - case 8: return aom_mse_8xh_16bit_highbd_sse2(dst, dstride, src, sstride, h); + case 4: return mse_4xh_16bit_highbd_sse2(dst, dstride, src, sstride, h); + case 8: return mse_8xh_16bit_highbd_sse2(dst, dstride, src, sstride, h); default: assert(0 && "unsupported width"); return -1; } } diff --git a/third_party/aom/aom_dsp/x86/intrapred_ssse3.c b/third_party/aom/aom_dsp/x86/intrapred_ssse3.c index fd48260c6f..869f880bda 100644 --- a/third_party/aom/aom_dsp/x86/intrapred_ssse3.c +++ b/third_party/aom/aom_dsp/x86/intrapred_ssse3.c @@ -940,10 +940,10 @@ static AOM_FORCE_INLINE __m128i cvtepu16_epi32(__m128i x) { return _mm_unpacklo_epi16((x), _mm_setzero_si128()); } -void smooth_predictor_wxh(uint8_t *LIBAOM_RESTRICT dst, ptrdiff_t stride, - const uint8_t *LIBAOM_RESTRICT top_row, - const uint8_t *LIBAOM_RESTRICT left_column, int width, - int height) { +static void smooth_predictor_wxh(uint8_t *LIBAOM_RESTRICT dst, ptrdiff_t stride, + const uint8_t *LIBAOM_RESTRICT top_row, + const uint8_t *LIBAOM_RESTRICT left_column, + int width, int height) { const uint8_t *const sm_weights_h = smooth_weights + height - 4; const uint8_t *const sm_weights_w = smooth_weights + width - 4; const __m128i zero = _mm_setzero_si128(); diff --git a/third_party/aom/aom_dsp/x86/masked_sad4d_ssse3.c b/third_party/aom/aom_dsp/x86/masked_sad4d_ssse3.c index 799ce9ef44..d96a9dd23d 100644 --- a/third_party/aom/aom_dsp/x86/masked_sad4d_ssse3.c +++ b/third_party/aom/aom_dsp/x86/masked_sad4d_ssse3.c @@ -103,11 +103,12 @@ static INLINE void masked_sadx4d_ssse3(const uint8_t *src_ptr, int src_stride, pred = _mm_packus_epi16(pred_l, pred_r); \ res##idx = _mm_add_epi32(res##idx, _mm_sad_epu8(pred, src)); -void aom_masked_sad8xhx4d_ssse3(const uint8_t *src_ptr, int src_stride, - const uint8_t *ref_array[4], int a_stride, - const uint8_t *b_ptr, int b_stride, - const uint8_t *m_ptr, int m_stride, int height, - int inv_mask, unsigned sad_array[4]) { +static void masked_sad8xhx4d_ssse3(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_array[4], int a_stride, + const uint8_t *b_ptr, int b_stride, + const uint8_t *m_ptr, int m_stride, + int height, int inv_mask, + unsigned sad_array[4]) { const uint8_t *ref0 = ref_array[0]; const uint8_t *ref1 = ref_array[1]; const uint8_t *ref2 = ref_array[2]; @@ -164,11 +165,12 @@ void aom_masked_sad8xhx4d_ssse3(const uint8_t *src_ptr, int src_stride, pred = _mm_packus_epi16(pred, _mm_setzero_si128()); \ res##idx = _mm_add_epi32(res##idx, _mm_sad_epu8(pred, src)); -void aom_masked_sad4xhx4d_ssse3(const uint8_t *src_ptr, int src_stride, - const uint8_t *ref_array[4], int a_stride, - const uint8_t *b_ptr, int b_stride, - const uint8_t *m_ptr, int m_stride, int height, - int inv_mask, unsigned sad_array[4]) { +static void masked_sad4xhx4d_ssse3(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_array[4], int a_stride, + const uint8_t *b_ptr, int b_stride, + const uint8_t *m_ptr, int m_stride, + int height, int inv_mask, + unsigned sad_array[4]) { const uint8_t *ref0 = ref_array[0]; const uint8_t *ref1 = ref_array[1]; const uint8_t *ref2 = ref_array[2]; @@ -224,22 +226,22 @@ void aom_masked_sad4xhx4d_ssse3(const uint8_t *src_ptr, int src_stride, msk_stride, m, n, inv_mask, sad_array); \ } -#define MASKSAD8XN_SSSE3(n) \ - void aom_masked_sad8x##n##x4d_ssse3( \ - const uint8_t *src, int src_stride, const uint8_t *ref[4], \ - int ref_stride, const uint8_t *second_pred, const uint8_t *msk, \ - int msk_stride, int inv_mask, unsigned sad_array[4]) { \ - aom_masked_sad8xhx4d_ssse3(src, src_stride, ref, ref_stride, second_pred, \ - 8, msk, msk_stride, n, inv_mask, sad_array); \ +#define MASKSAD8XN_SSSE3(n) \ + void aom_masked_sad8x##n##x4d_ssse3( \ + const uint8_t *src, int src_stride, const uint8_t *ref[4], \ + int ref_stride, const uint8_t *second_pred, const uint8_t *msk, \ + int msk_stride, int inv_mask, unsigned sad_array[4]) { \ + masked_sad8xhx4d_ssse3(src, src_stride, ref, ref_stride, second_pred, 8, \ + msk, msk_stride, n, inv_mask, sad_array); \ } -#define MASKSAD4XN_SSSE3(n) \ - void aom_masked_sad4x##n##x4d_ssse3( \ - const uint8_t *src, int src_stride, const uint8_t *ref[4], \ - int ref_stride, const uint8_t *second_pred, const uint8_t *msk, \ - int msk_stride, int inv_mask, unsigned sad_array[4]) { \ - aom_masked_sad4xhx4d_ssse3(src, src_stride, ref, ref_stride, second_pred, \ - 4, msk, msk_stride, n, inv_mask, sad_array); \ +#define MASKSAD4XN_SSSE3(n) \ + void aom_masked_sad4x##n##x4d_ssse3( \ + const uint8_t *src, int src_stride, const uint8_t *ref[4], \ + int ref_stride, const uint8_t *second_pred, const uint8_t *msk, \ + int msk_stride, int inv_mask, unsigned sad_array[4]) { \ + masked_sad4xhx4d_ssse3(src, src_stride, ref, ref_stride, second_pred, 4, \ + msk, msk_stride, n, inv_mask, sad_array); \ } MASKSADMXN_SSSE3(128, 128) diff --git a/third_party/aom/aom_dsp/x86/subpel_variance_sse2.asm b/third_party/aom/aom_dsp/x86/subpel_variance_sse2.asm deleted file mode 100644 index d1d8373456..0000000000 --- a/third_party/aom/aom_dsp/x86/subpel_variance_sse2.asm +++ /dev/null @@ -1,1470 +0,0 @@ -; -; Copyright (c) 2016, Alliance for Open Media. All rights reserved -; -; This source code is subject to the terms of the BSD 2 Clause License and -; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License -; was not distributed with this source code in the LICENSE file, you can -; obtain it at www.aomedia.org/license/software. If the Alliance for Open -; Media Patent License 1.0 was not distributed with this source code in the -; PATENTS file, you can obtain it at www.aomedia.org/license/patent. -; - -; - -%include "third_party/x86inc/x86inc.asm" - -SECTION_RODATA -pw_8: times 8 dw 8 -bilin_filter_m_sse2: times 8 dw 16 - times 8 dw 0 - times 8 dw 14 - times 8 dw 2 - times 8 dw 12 - times 8 dw 4 - times 8 dw 10 - times 8 dw 6 - times 16 dw 8 - times 8 dw 6 - times 8 dw 10 - times 8 dw 4 - times 8 dw 12 - times 8 dw 2 - times 8 dw 14 - -bilin_filter_m_ssse3: times 8 db 16, 0 - times 8 db 14, 2 - times 8 db 12, 4 - times 8 db 10, 6 - times 16 db 8 - times 8 db 6, 10 - times 8 db 4, 12 - times 8 db 2, 14 - -SECTION .text - -; int aom_sub_pixel_varianceNxh(const uint8_t *src, ptrdiff_t src_stride, -; int x_offset, int y_offset, -; const uint8_t *dst, ptrdiff_t dst_stride, -; int height, unsigned int *sse); -; -; This function returns the SE and stores SSE in the given pointer. - -%macro SUM_SSE 6 ; src1, dst1, src2, dst2, sum, sse - psubw %3, %4 - psubw %1, %2 - paddw %5, %3 - pmaddwd %3, %3 - paddw %5, %1 - pmaddwd %1, %1 - paddd %6, %3 - paddd %6, %1 -%endmacro - -%macro STORE_AND_RET 1 -%if %1 > 4 - ; if H=64 and W=16, we have 8 words of each 2(1bit)x64(6bit)x9bit=16bit - ; in m6, i.e. it _exactly_ fits in a signed word per word in the xmm reg. - ; We have to sign-extend it before adding the words within the register - ; and outputing to a dword. - pcmpgtw m5, m6 ; mask for 0 > x - movhlps m3, m7 - punpcklwd m4, m6, m5 - punpckhwd m6, m5 ; sign-extend m6 word->dword - paddd m7, m3 - paddd m6, m4 - pshufd m3, m7, 0x1 - movhlps m4, m6 - paddd m7, m3 - paddd m6, m4 - mov r1, ssem ; r1 = unsigned int *sse - pshufd m4, m6, 0x1 - movd [r1], m7 ; store sse - paddd m6, m4 - movd raxd, m6 ; store sum as return value -%else ; 4xh - pshuflw m4, m6, 0xe - pshuflw m3, m7, 0xe - paddw m6, m4 - paddd m7, m3 - pcmpgtw m5, m6 ; mask for 0 > x - mov r1, ssem ; r1 = unsigned int *sse - punpcklwd m6, m5 ; sign-extend m6 word->dword - movd [r1], m7 ; store sse - pshuflw m4, m6, 0xe - paddd m6, m4 - movd raxd, m6 ; store sum as return value -%endif - RET -%endmacro - -%macro INC_SRC_BY_SRC_STRIDE 0 -%if AOM_ARCH_X86=1 && CONFIG_PIC=1 - add srcq, src_stridemp -%else - add srcq, src_strideq -%endif -%endmacro - -%macro SUBPEL_VARIANCE 1-2 0 ; W -%if cpuflag(ssse3) -%define bilin_filter_m bilin_filter_m_ssse3 -%define filter_idx_shift 4 -%else -%define bilin_filter_m bilin_filter_m_sse2 -%define filter_idx_shift 5 -%endif -; FIXME(rbultje) only bilinear filters use >8 registers, and ssse3 only uses -; 11, not 13, if the registers are ordered correctly. May make a minor speed -; difference on Win64 - -%if AOM_ARCH_X86_64 - %if %2 == 1 ; avg - cglobal sub_pixel_avg_variance%1xh, 9, 10, 13, src, src_stride, \ - x_offset, y_offset, dst, dst_stride, \ - sec, sec_stride, height, sse - %define sec_str sec_strideq - %else - cglobal sub_pixel_variance%1xh, 7, 8, 13, src, src_stride, \ - x_offset, y_offset, dst, dst_stride, \ - height, sse - %endif - %define block_height heightd - %define bilin_filter sseq -%else - %if CONFIG_PIC=1 - %if %2 == 1 ; avg - cglobal sub_pixel_avg_variance%1xh, 7, 7, 13, src, src_stride, \ - x_offset, y_offset, dst, dst_stride, \ - sec, sec_stride, height, sse - %define block_height dword heightm - %define sec_str sec_stridemp - %else - cglobal sub_pixel_variance%1xh, 7, 7, 13, src, src_stride, \ - x_offset, y_offset, dst, dst_stride, \ - height, sse - %define block_height heightd - %endif - - ; reuse argument stack space - %define g_bilin_filterm x_offsetm - %define g_pw_8m y_offsetm - - ;Store bilin_filter and pw_8 location in stack - %if GET_GOT_DEFINED == 1 - GET_GOT eax - add esp, 4 ; restore esp - %endif - - lea ecx, [GLOBAL(bilin_filter_m)] - mov g_bilin_filterm, ecx - - lea ecx, [GLOBAL(pw_8)] - mov g_pw_8m, ecx - - LOAD_IF_USED 0, 1 ; load eax, ecx back - %else - %if %2 == 1 ; avg - cglobal sub_pixel_avg_variance%1xh, 7, 7, 13, src, src_stride, \ - x_offset, y_offset, \ - dst, dst_stride, sec, sec_stride, \ - height, sse - %define block_height dword heightm - %define sec_str sec_stridemp - %else - cglobal sub_pixel_variance%1xh, 7, 7, 13, src, src_stride, \ - x_offset, y_offset, dst, dst_stride, \ - height, sse - %define block_height heightd - %endif - %define bilin_filter bilin_filter_m - %endif -%endif - -%if %1 == 4 - %define movx movd -%else - %define movx movh -%endif - - ASSERT %1 <= 16 ; m6 overflows if w > 16 - pxor m6, m6 ; sum - pxor m7, m7 ; sse - ; FIXME(rbultje) if both filters are bilinear, we don't actually use m5; we - ; could perhaps use it for something more productive then - pxor m5, m5 ; dedicated zero register -%if %1 < 16 - sar block_height, 1 -%if %2 == 1 ; avg - shl sec_str, 1 -%endif -%endif - - ; FIXME(rbultje) replace by jumptable? - test x_offsetd, x_offsetd - jnz .x_nonzero - ; x_offset == 0 - test y_offsetd, y_offsetd - jnz .x_zero_y_nonzero - - ; x_offset == 0 && y_offset == 0 -.x_zero_y_zero_loop: -%if %1 == 16 - movu m0, [srcq] - mova m1, [dstq] -%if %2 == 1 ; avg - pavgb m0, [secq] - punpckhbw m3, m1, m5 - punpcklbw m1, m5 -%endif - punpckhbw m2, m0, m5 - punpcklbw m0, m5 - -%if %2 == 0 ; !avg - punpckhbw m3, m1, m5 - punpcklbw m1, m5 -%endif - SUM_SSE m0, m1, m2, m3, m6, m7 - - add srcq, src_strideq - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] -%if %2 == 1 ; avg -%if %1 > 4 - movhps m0, [srcq+src_strideq] -%else ; 4xh - movx m1, [srcq+src_strideq] - punpckldq m0, m1 -%endif -%else ; !avg - movx m2, [srcq+src_strideq] -%endif - - movx m1, [dstq] - movx m3, [dstq+dst_strideq] - -%if %2 == 1 ; avg -%if %1 > 4 - pavgb m0, [secq] -%else - movh m2, [secq] - pavgb m0, m2 -%endif - punpcklbw m3, m5 - punpcklbw m1, m5 -%if %1 > 4 - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else ; 4xh - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%else ; !avg - punpcklbw m0, m5 - punpcklbw m2, m5 - punpcklbw m3, m5 - punpcklbw m1, m5 -%endif - SUM_SSE m0, m1, m2, m3, m6, m7 - - lea srcq, [srcq+src_strideq*2] - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_zero_y_zero_loop - STORE_AND_RET %1 - -.x_zero_y_nonzero: - cmp y_offsetd, 4 - jne .x_zero_y_nonhalf - - ; x_offset == 0 && y_offset == 0.5 -.x_zero_y_half_loop: -%if %1 == 16 - movu m0, [srcq] - movu m4, [srcq+src_strideq] - mova m1, [dstq] - pavgb m0, m4 - punpckhbw m3, m1, m5 -%if %2 == 1 ; avg - pavgb m0, [secq] -%endif - punpcklbw m1, m5 - punpckhbw m2, m0, m5 - punpcklbw m0, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - - add srcq, src_strideq - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] - movx m2, [srcq+src_strideq] -%if %2 == 1 ; avg -%if %1 > 4 - movhps m2, [srcq+src_strideq*2] -%else ; 4xh - movx m1, [srcq+src_strideq*2] - punpckldq m2, m1 -%endif - movx m1, [dstq] -%if %1 > 4 - movlhps m0, m2 -%else ; 4xh - punpckldq m0, m2 -%endif - movx m3, [dstq+dst_strideq] - pavgb m0, m2 - punpcklbw m1, m5 -%if %1 > 4 - pavgb m0, [secq] - punpcklbw m3, m5 - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else ; 4xh - movh m4, [secq] - pavgb m0, m4 - punpcklbw m3, m5 - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%else ; !avg - movx m4, [srcq+src_strideq*2] - movx m1, [dstq] - pavgb m0, m2 - movx m3, [dstq+dst_strideq] - pavgb m2, m4 - punpcklbw m0, m5 - punpcklbw m2, m5 - punpcklbw m3, m5 - punpcklbw m1, m5 -%endif - SUM_SSE m0, m1, m2, m3, m6, m7 - - lea srcq, [srcq+src_strideq*2] - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_zero_y_half_loop - STORE_AND_RET %1 - -.x_zero_y_nonhalf: - ; x_offset == 0 && y_offset == bilin interpolation -%if AOM_ARCH_X86_64 - lea bilin_filter, [GLOBAL(bilin_filter_m)] -%endif - shl y_offsetd, filter_idx_shift -%if AOM_ARCH_X86_64 && %1 > 4 - mova m8, [bilin_filter+y_offsetq] -%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 - mova m9, [bilin_filter+y_offsetq+16] -%endif - mova m10, [GLOBAL(pw_8)] -%define filter_y_a m8 -%define filter_y_b m9 -%define filter_rnd m10 -%else ; x86-32 or mmx -%if AOM_ARCH_X86=1 && CONFIG_PIC=1 -; x_offset == 0, reuse x_offset reg -%define tempq x_offsetq - add y_offsetq, g_bilin_filterm -%define filter_y_a [y_offsetq] -%define filter_y_b [y_offsetq+16] - mov tempq, g_pw_8m -%define filter_rnd [tempq] -%else - add y_offsetq, bilin_filter -%define filter_y_a [y_offsetq] -%define filter_y_b [y_offsetq+16] -%define filter_rnd [GLOBAL(pw_8)] -%endif -%endif - -.x_zero_y_other_loop: -%if %1 == 16 - movu m0, [srcq] - movu m4, [srcq+src_strideq] - mova m1, [dstq] -%if cpuflag(ssse3) - punpckhbw m2, m0, m4 - punpcklbw m0, m4 - pmaddubsw m2, filter_y_a - pmaddubsw m0, filter_y_a - paddw m2, filter_rnd - paddw m0, filter_rnd -%else - punpckhbw m2, m0, m5 - punpckhbw m3, m4, m5 - punpcklbw m0, m5 - punpcklbw m4, m5 - ; FIXME(rbultje) instead of out=((num-x)*in1+x*in2+rnd)>>log2(num), we can - ; also do out=in1+(((num-x)*(in2-in1)+rnd)>>log2(num)). Total number of - ; instructions is the same (5), but it is 1 mul instead of 2, so might be - ; slightly faster because of pmullw latency. It would also cut our rodata - ; tables in half for this function, and save 1-2 registers on x86-64. - pmullw m2, filter_y_a - pmullw m3, filter_y_b - paddw m2, filter_rnd - pmullw m0, filter_y_a - pmullw m4, filter_y_b - paddw m0, filter_rnd - paddw m2, m3 - paddw m0, m4 -%endif - psraw m2, 4 - psraw m0, 4 -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline - packuswb m0, m2 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%endif - punpckhbw m3, m1, m5 - punpcklbw m1, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - - add srcq, src_strideq - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] - movx m2, [srcq+src_strideq] - movx m4, [srcq+src_strideq*2] - movx m3, [dstq+dst_strideq] -%if cpuflag(ssse3) - movx m1, [dstq] - punpcklbw m0, m2 - punpcklbw m2, m4 - pmaddubsw m0, filter_y_a - pmaddubsw m2, filter_y_a - punpcklbw m3, m5 - paddw m2, filter_rnd - paddw m0, filter_rnd -%else - punpcklbw m0, m5 - punpcklbw m2, m5 - punpcklbw m4, m5 - pmullw m0, filter_y_a - pmullw m1, m2, filter_y_b - punpcklbw m3, m5 - paddw m0, filter_rnd - pmullw m2, filter_y_a - pmullw m4, filter_y_b - paddw m0, m1 - paddw m2, filter_rnd - movx m1, [dstq] - paddw m2, m4 -%endif - psraw m0, 4 - psraw m2, 4 -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline -%if %1 == 4 - movlhps m0, m2 -%endif - packuswb m0, m2 -%if %1 > 4 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else ; 4xh - movh m2, [secq] - pavgb m0, m2 - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%endif - punpcklbw m1, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - - lea srcq, [srcq+src_strideq*2] - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_zero_y_other_loop -%undef filter_y_a -%undef filter_y_b -%undef filter_rnd - STORE_AND_RET %1 - -.x_nonzero: - cmp x_offsetd, 4 - jne .x_nonhalf - ; x_offset == 0.5 - test y_offsetd, y_offsetd - jnz .x_half_y_nonzero - - ; x_offset == 0.5 && y_offset == 0 -.x_half_y_zero_loop: -%if %1 == 16 - movu m0, [srcq] - movu m4, [srcq+1] - mova m1, [dstq] - pavgb m0, m4 - punpckhbw m3, m1, m5 -%if %2 == 1 ; avg - pavgb m0, [secq] -%endif - punpcklbw m1, m5 - punpckhbw m2, m0, m5 - punpcklbw m0, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - - add srcq, src_strideq - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] - movx m4, [srcq+1] -%if %2 == 1 ; avg -%if %1 > 4 - movhps m0, [srcq+src_strideq] - movhps m4, [srcq+src_strideq+1] -%else ; 4xh - movx m1, [srcq+src_strideq] - punpckldq m0, m1 - movx m2, [srcq+src_strideq+1] - punpckldq m4, m2 -%endif - movx m1, [dstq] - movx m3, [dstq+dst_strideq] - pavgb m0, m4 - punpcklbw m3, m5 -%if %1 > 4 - pavgb m0, [secq] - punpcklbw m1, m5 - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else ; 4xh - movh m2, [secq] - pavgb m0, m2 - punpcklbw m1, m5 - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%else ; !avg - movx m2, [srcq+src_strideq] - movx m1, [dstq] - pavgb m0, m4 - movx m4, [srcq+src_strideq+1] - movx m3, [dstq+dst_strideq] - pavgb m2, m4 - punpcklbw m0, m5 - punpcklbw m2, m5 - punpcklbw m3, m5 - punpcklbw m1, m5 -%endif - SUM_SSE m0, m1, m2, m3, m6, m7 - - lea srcq, [srcq+src_strideq*2] - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_half_y_zero_loop - STORE_AND_RET %1 - -.x_half_y_nonzero: - cmp y_offsetd, 4 - jne .x_half_y_nonhalf - - ; x_offset == 0.5 && y_offset == 0.5 -%if %1 == 16 - movu m0, [srcq] - movu m3, [srcq+1] - add srcq, src_strideq - pavgb m0, m3 -.x_half_y_half_loop: - movu m4, [srcq] - movu m3, [srcq+1] - mova m1, [dstq] - pavgb m4, m3 - punpckhbw m3, m1, m5 - pavgb m0, m4 -%if %2 == 1 ; avg - punpcklbw m1, m5 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else - punpckhbw m2, m0, m5 - punpcklbw m0, m5 - punpcklbw m1, m5 -%endif - SUM_SSE m0, m1, m2, m3, m6, m7 - mova m0, m4 - - add srcq, src_strideq - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] - movx m3, [srcq+1] - add srcq, src_strideq - pavgb m0, m3 -.x_half_y_half_loop: - movx m2, [srcq] - movx m3, [srcq+1] -%if %2 == 1 ; avg -%if %1 > 4 - movhps m2, [srcq+src_strideq] - movhps m3, [srcq+src_strideq+1] -%else - movx m1, [srcq+src_strideq] - punpckldq m2, m1 - movx m1, [srcq+src_strideq+1] - punpckldq m3, m1 -%endif - pavgb m2, m3 -%if %1 > 4 - movlhps m0, m2 - movhlps m4, m2 -%else ; 4xh - punpckldq m0, m2 - pshuflw m4, m2, 0xe -%endif - movx m1, [dstq] - pavgb m0, m2 - movx m3, [dstq+dst_strideq] -%if %1 > 4 - pavgb m0, [secq] -%else - movh m2, [secq] - pavgb m0, m2 -%endif - punpcklbw m3, m5 - punpcklbw m1, m5 -%if %1 > 4 - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%else ; !avg - movx m4, [srcq+src_strideq] - movx m1, [srcq+src_strideq+1] - pavgb m2, m3 - pavgb m4, m1 - pavgb m0, m2 - pavgb m2, m4 - movx m1, [dstq] - movx m3, [dstq+dst_strideq] - punpcklbw m0, m5 - punpcklbw m2, m5 - punpcklbw m3, m5 - punpcklbw m1, m5 -%endif - SUM_SSE m0, m1, m2, m3, m6, m7 - mova m0, m4 - - lea srcq, [srcq+src_strideq*2] - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_half_y_half_loop - STORE_AND_RET %1 - -.x_half_y_nonhalf: - ; x_offset == 0.5 && y_offset == bilin interpolation -%if AOM_ARCH_X86_64 - lea bilin_filter, [GLOBAL(bilin_filter_m)] -%endif - shl y_offsetd, filter_idx_shift -%if AOM_ARCH_X86_64 && %1 > 4 - mova m8, [bilin_filter+y_offsetq] -%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 - mova m9, [bilin_filter+y_offsetq+16] -%endif - mova m10, [GLOBAL(pw_8)] -%define filter_y_a m8 -%define filter_y_b m9 -%define filter_rnd m10 -%else ;x86_32 -%if AOM_ARCH_X86=1 && CONFIG_PIC=1 -; x_offset == 0.5. We can reuse x_offset reg -%define tempq x_offsetq - add y_offsetq, g_bilin_filterm -%define filter_y_a [y_offsetq] -%define filter_y_b [y_offsetq+16] - mov tempq, g_pw_8m -%define filter_rnd [tempq] -%else - add y_offsetq, bilin_filter -%define filter_y_a [y_offsetq] -%define filter_y_b [y_offsetq+16] -%define filter_rnd [GLOBAL(pw_8)] -%endif -%endif - -%if %1 == 16 - movu m0, [srcq] - movu m3, [srcq+1] - add srcq, src_strideq - pavgb m0, m3 -.x_half_y_other_loop: - movu m4, [srcq] - movu m2, [srcq+1] - mova m1, [dstq] - pavgb m4, m2 -%if cpuflag(ssse3) - punpckhbw m2, m0, m4 - punpcklbw m0, m4 - pmaddubsw m2, filter_y_a - pmaddubsw m0, filter_y_a - paddw m2, filter_rnd - paddw m0, filter_rnd - psraw m2, 4 -%else - punpckhbw m2, m0, m5 - punpckhbw m3, m4, m5 - pmullw m2, filter_y_a - pmullw m3, filter_y_b - paddw m2, filter_rnd - punpcklbw m0, m5 - paddw m2, m3 - punpcklbw m3, m4, m5 - pmullw m0, filter_y_a - pmullw m3, filter_y_b - paddw m0, filter_rnd - psraw m2, 4 - paddw m0, m3 -%endif - punpckhbw m3, m1, m5 - psraw m0, 4 -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline - packuswb m0, m2 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%endif - punpcklbw m1, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - mova m0, m4 - - add srcq, src_strideq - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] - movx m3, [srcq+1] - add srcq, src_strideq - pavgb m0, m3 -%if notcpuflag(ssse3) - punpcklbw m0, m5 -%endif -.x_half_y_other_loop: - movx m2, [srcq] - movx m1, [srcq+1] - movx m4, [srcq+src_strideq] - movx m3, [srcq+src_strideq+1] - pavgb m2, m1 - pavgb m4, m3 - movx m3, [dstq+dst_strideq] -%if cpuflag(ssse3) - movx m1, [dstq] - punpcklbw m0, m2 - punpcklbw m2, m4 - pmaddubsw m0, filter_y_a - pmaddubsw m2, filter_y_a - punpcklbw m3, m5 - paddw m0, filter_rnd - paddw m2, filter_rnd -%else - punpcklbw m2, m5 - punpcklbw m4, m5 - pmullw m0, filter_y_a - pmullw m1, m2, filter_y_b - punpcklbw m3, m5 - paddw m0, filter_rnd - pmullw m2, filter_y_a - paddw m0, m1 - pmullw m1, m4, filter_y_b - paddw m2, filter_rnd - paddw m2, m1 - movx m1, [dstq] -%endif - psraw m0, 4 - psraw m2, 4 -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline -%if %1 == 4 - movlhps m0, m2 -%endif - packuswb m0, m2 -%if %1 > 4 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else - movh m2, [secq] - pavgb m0, m2 - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%endif - punpcklbw m1, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - mova m0, m4 - - lea srcq, [srcq+src_strideq*2] - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_half_y_other_loop -%undef filter_y_a -%undef filter_y_b -%undef filter_rnd - STORE_AND_RET %1 - -.x_nonhalf: - test y_offsetd, y_offsetd - jnz .x_nonhalf_y_nonzero - - ; x_offset == bilin interpolation && y_offset == 0 -%if AOM_ARCH_X86_64 - lea bilin_filter, [GLOBAL(bilin_filter_m)] -%endif - shl x_offsetd, filter_idx_shift -%if AOM_ARCH_X86_64 && %1 > 4 - mova m8, [bilin_filter+x_offsetq] -%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 - mova m9, [bilin_filter+x_offsetq+16] -%endif - mova m10, [GLOBAL(pw_8)] -%define filter_x_a m8 -%define filter_x_b m9 -%define filter_rnd m10 -%else ; x86-32 -%if AOM_ARCH_X86=1 && CONFIG_PIC=1 -;y_offset == 0. We can reuse y_offset reg. -%define tempq y_offsetq - add x_offsetq, g_bilin_filterm -%define filter_x_a [x_offsetq] -%define filter_x_b [x_offsetq+16] - mov tempq, g_pw_8m -%define filter_rnd [tempq] -%else - add x_offsetq, bilin_filter -%define filter_x_a [x_offsetq] -%define filter_x_b [x_offsetq+16] -%define filter_rnd [GLOBAL(pw_8)] -%endif -%endif - -.x_other_y_zero_loop: -%if %1 == 16 - movu m0, [srcq] - movu m4, [srcq+1] - mova m1, [dstq] -%if cpuflag(ssse3) - punpckhbw m2, m0, m4 - punpcklbw m0, m4 - pmaddubsw m2, filter_x_a - pmaddubsw m0, filter_x_a - paddw m2, filter_rnd - paddw m0, filter_rnd -%else - punpckhbw m2, m0, m5 - punpckhbw m3, m4, m5 - punpcklbw m0, m5 - punpcklbw m4, m5 - pmullw m2, filter_x_a - pmullw m3, filter_x_b - paddw m2, filter_rnd - pmullw m0, filter_x_a - pmullw m4, filter_x_b - paddw m0, filter_rnd - paddw m2, m3 - paddw m0, m4 -%endif - psraw m2, 4 - psraw m0, 4 -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline - packuswb m0, m2 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%endif - punpckhbw m3, m1, m5 - punpcklbw m1, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - - add srcq, src_strideq - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] - movx m1, [srcq+1] - movx m2, [srcq+src_strideq] - movx m4, [srcq+src_strideq+1] - movx m3, [dstq+dst_strideq] -%if cpuflag(ssse3) - punpcklbw m0, m1 - movx m1, [dstq] - punpcklbw m2, m4 - pmaddubsw m0, filter_x_a - pmaddubsw m2, filter_x_a - punpcklbw m3, m5 - paddw m0, filter_rnd - paddw m2, filter_rnd -%else - punpcklbw m0, m5 - punpcklbw m1, m5 - punpcklbw m2, m5 - punpcklbw m4, m5 - pmullw m0, filter_x_a - pmullw m1, filter_x_b - punpcklbw m3, m5 - paddw m0, filter_rnd - pmullw m2, filter_x_a - pmullw m4, filter_x_b - paddw m0, m1 - paddw m2, filter_rnd - movx m1, [dstq] - paddw m2, m4 -%endif - psraw m0, 4 - psraw m2, 4 -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline -%if %1 == 4 - movlhps m0, m2 -%endif - packuswb m0, m2 -%if %1 > 4 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else - movh m2, [secq] - pavgb m0, m2 - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%endif - punpcklbw m1, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - - lea srcq, [srcq+src_strideq*2] - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_other_y_zero_loop -%undef filter_x_a -%undef filter_x_b -%undef filter_rnd - STORE_AND_RET %1 - -.x_nonhalf_y_nonzero: - cmp y_offsetd, 4 - jne .x_nonhalf_y_nonhalf - - ; x_offset == bilin interpolation && y_offset == 0.5 -%if AOM_ARCH_X86_64 - lea bilin_filter, [GLOBAL(bilin_filter_m)] -%endif - shl x_offsetd, filter_idx_shift -%if AOM_ARCH_X86_64 && %1 > 4 - mova m8, [bilin_filter+x_offsetq] -%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 - mova m9, [bilin_filter+x_offsetq+16] -%endif - mova m10, [GLOBAL(pw_8)] -%define filter_x_a m8 -%define filter_x_b m9 -%define filter_rnd m10 -%else ; x86-32 -%if AOM_ARCH_X86=1 && CONFIG_PIC=1 -; y_offset == 0.5. We can reuse y_offset reg. -%define tempq y_offsetq - add x_offsetq, g_bilin_filterm -%define filter_x_a [x_offsetq] -%define filter_x_b [x_offsetq+16] - mov tempq, g_pw_8m -%define filter_rnd [tempq] -%else - add x_offsetq, bilin_filter -%define filter_x_a [x_offsetq] -%define filter_x_b [x_offsetq+16] -%define filter_rnd [GLOBAL(pw_8)] -%endif -%endif - -%if %1 == 16 - movu m0, [srcq] - movu m1, [srcq+1] -%if cpuflag(ssse3) - punpckhbw m2, m0, m1 - punpcklbw m0, m1 - pmaddubsw m2, filter_x_a - pmaddubsw m0, filter_x_a - paddw m2, filter_rnd - paddw m0, filter_rnd -%else - punpckhbw m2, m0, m5 - punpckhbw m3, m1, m5 - punpcklbw m0, m5 - punpcklbw m1, m5 - pmullw m0, filter_x_a - pmullw m1, filter_x_b - paddw m0, filter_rnd - pmullw m2, filter_x_a - pmullw m3, filter_x_b - paddw m2, filter_rnd - paddw m0, m1 - paddw m2, m3 -%endif - psraw m0, 4 - psraw m2, 4 - add srcq, src_strideq - packuswb m0, m2 -.x_other_y_half_loop: - movu m4, [srcq] - movu m3, [srcq+1] -%if cpuflag(ssse3) - mova m1, [dstq] - punpckhbw m2, m4, m3 - punpcklbw m4, m3 - pmaddubsw m2, filter_x_a - pmaddubsw m4, filter_x_a - paddw m2, filter_rnd - paddw m4, filter_rnd - psraw m2, 4 - psraw m4, 4 - packuswb m4, m2 - pavgb m0, m4 - punpckhbw m3, m1, m5 - punpcklbw m1, m5 -%else - punpckhbw m2, m4, m5 - punpckhbw m1, m3, m5 - punpcklbw m4, m5 - punpcklbw m3, m5 - pmullw m4, filter_x_a - pmullw m3, filter_x_b - paddw m4, filter_rnd - pmullw m2, filter_x_a - pmullw m1, filter_x_b - paddw m2, filter_rnd - paddw m4, m3 - paddw m2, m1 - mova m1, [dstq] - psraw m4, 4 - psraw m2, 4 - punpckhbw m3, m1, m5 - ; FIXME(rbultje) the repeated pack/unpack here around m0/m2 is because we - ; have a 1-register shortage to be able to store the backup of the bilin - ; filtered second line as words as cache for the next line. Packing into - ; a byte costs 1 pack and 2 unpacks, but saves a register. - packuswb m4, m2 - punpcklbw m1, m5 - pavgb m0, m4 -%endif -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline - pavgb m0, [secq] -%endif - punpckhbw m2, m0, m5 - punpcklbw m0, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - mova m0, m4 - - add srcq, src_strideq - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] - movx m1, [srcq+1] -%if cpuflag(ssse3) - punpcklbw m0, m1 - pmaddubsw m0, filter_x_a - paddw m0, filter_rnd -%else - punpcklbw m0, m5 - punpcklbw m1, m5 - pmullw m0, filter_x_a - pmullw m1, filter_x_b - paddw m0, filter_rnd - paddw m0, m1 -%endif - add srcq, src_strideq - psraw m0, 4 -.x_other_y_half_loop: - movx m2, [srcq] - movx m1, [srcq+1] - movx m4, [srcq+src_strideq] - movx m3, [srcq+src_strideq+1] -%if cpuflag(ssse3) - punpcklbw m2, m1 - punpcklbw m4, m3 - pmaddubsw m2, filter_x_a - pmaddubsw m4, filter_x_a - movx m1, [dstq] - movx m3, [dstq+dst_strideq] - paddw m2, filter_rnd - paddw m4, filter_rnd -%else - punpcklbw m2, m5 - punpcklbw m1, m5 - punpcklbw m4, m5 - punpcklbw m3, m5 - pmullw m2, filter_x_a - pmullw m1, filter_x_b - paddw m2, filter_rnd - pmullw m4, filter_x_a - pmullw m3, filter_x_b - paddw m4, filter_rnd - paddw m2, m1 - movx m1, [dstq] - paddw m4, m3 - movx m3, [dstq+dst_strideq] -%endif - psraw m2, 4 - psraw m4, 4 - pavgw m0, m2 - pavgw m2, m4 -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline - also consider going to bytes here -%if %1 == 4 - movlhps m0, m2 -%endif - packuswb m0, m2 -%if %1 > 4 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else - movh m2, [secq] - pavgb m0, m2 - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%endif - punpcklbw m3, m5 - punpcklbw m1, m5 - SUM_SSE m0, m1, m2, m3, m6, m7 - mova m0, m4 - - lea srcq, [srcq+src_strideq*2] - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_other_y_half_loop -%undef filter_x_a -%undef filter_x_b -%undef filter_rnd - STORE_AND_RET %1 - -.x_nonhalf_y_nonhalf: -%if AOM_ARCH_X86_64 - lea bilin_filter, [GLOBAL(bilin_filter_m)] -%endif - shl x_offsetd, filter_idx_shift - shl y_offsetd, filter_idx_shift -%if AOM_ARCH_X86_64 && %1 > 4 - mova m8, [bilin_filter+x_offsetq] -%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 - mova m9, [bilin_filter+x_offsetq+16] -%endif - mova m10, [bilin_filter+y_offsetq] -%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 - mova m11, [bilin_filter+y_offsetq+16] -%endif - mova m12, [GLOBAL(pw_8)] -%define filter_x_a m8 -%define filter_x_b m9 -%define filter_y_a m10 -%define filter_y_b m11 -%define filter_rnd m12 -%else ; x86-32 -%if AOM_ARCH_X86=1 && CONFIG_PIC=1 -; In this case, there is NO unused register. Used src_stride register. Later, -; src_stride has to be loaded from stack when it is needed. -%define tempq src_strideq - mov tempq, g_bilin_filterm - add x_offsetq, tempq - add y_offsetq, tempq -%define filter_x_a [x_offsetq] -%define filter_x_b [x_offsetq+16] -%define filter_y_a [y_offsetq] -%define filter_y_b [y_offsetq+16] - - mov tempq, g_pw_8m -%define filter_rnd [tempq] -%else - add x_offsetq, bilin_filter - add y_offsetq, bilin_filter -%define filter_x_a [x_offsetq] -%define filter_x_b [x_offsetq+16] -%define filter_y_a [y_offsetq] -%define filter_y_b [y_offsetq+16] -%define filter_rnd [GLOBAL(pw_8)] -%endif -%endif - - ; x_offset == bilin interpolation && y_offset == bilin interpolation -%if %1 == 16 - movu m0, [srcq] - movu m1, [srcq+1] -%if cpuflag(ssse3) - punpckhbw m2, m0, m1 - punpcklbw m0, m1 - pmaddubsw m2, filter_x_a - pmaddubsw m0, filter_x_a - paddw m2, filter_rnd - paddw m0, filter_rnd -%else - punpckhbw m2, m0, m5 - punpckhbw m3, m1, m5 - punpcklbw m0, m5 - punpcklbw m1, m5 - pmullw m0, filter_x_a - pmullw m1, filter_x_b - paddw m0, filter_rnd - pmullw m2, filter_x_a - pmullw m3, filter_x_b - paddw m2, filter_rnd - paddw m0, m1 - paddw m2, m3 -%endif - psraw m0, 4 - psraw m2, 4 - - INC_SRC_BY_SRC_STRIDE - - packuswb m0, m2 -.x_other_y_other_loop: -%if cpuflag(ssse3) - movu m4, [srcq] - movu m3, [srcq+1] - mova m1, [dstq] - punpckhbw m2, m4, m3 - punpcklbw m4, m3 - pmaddubsw m2, filter_x_a - pmaddubsw m4, filter_x_a - punpckhbw m3, m1, m5 - paddw m2, filter_rnd - paddw m4, filter_rnd - psraw m2, 4 - psraw m4, 4 - packuswb m4, m2 - punpckhbw m2, m0, m4 - punpcklbw m0, m4 - pmaddubsw m2, filter_y_a - pmaddubsw m0, filter_y_a - punpcklbw m1, m5 - paddw m2, filter_rnd - paddw m0, filter_rnd - psraw m2, 4 - psraw m0, 4 -%else - movu m3, [srcq] - movu m4, [srcq+1] - punpckhbw m1, m3, m5 - punpckhbw m2, m4, m5 - punpcklbw m3, m5 - punpcklbw m4, m5 - pmullw m3, filter_x_a - pmullw m4, filter_x_b - paddw m3, filter_rnd - pmullw m1, filter_x_a - pmullw m2, filter_x_b - paddw m1, filter_rnd - paddw m3, m4 - paddw m1, m2 - psraw m3, 4 - psraw m1, 4 - packuswb m4, m3, m1 - punpckhbw m2, m0, m5 - punpcklbw m0, m5 - pmullw m2, filter_y_a - pmullw m1, filter_y_b - paddw m2, filter_rnd - pmullw m0, filter_y_a - pmullw m3, filter_y_b - paddw m2, m1 - mova m1, [dstq] - paddw m0, filter_rnd - psraw m2, 4 - paddw m0, m3 - punpckhbw m3, m1, m5 - psraw m0, 4 - punpcklbw m1, m5 -%endif -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline - packuswb m0, m2 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%endif - SUM_SSE m0, m1, m2, m3, m6, m7 - mova m0, m4 - - INC_SRC_BY_SRC_STRIDE - add dstq, dst_strideq -%else ; %1 < 16 - movx m0, [srcq] - movx m1, [srcq+1] -%if cpuflag(ssse3) - punpcklbw m0, m1 - pmaddubsw m0, filter_x_a - paddw m0, filter_rnd -%else - punpcklbw m0, m5 - punpcklbw m1, m5 - pmullw m0, filter_x_a - pmullw m1, filter_x_b - paddw m0, filter_rnd - paddw m0, m1 -%endif - psraw m0, 4 -%if cpuflag(ssse3) - packuswb m0, m0 -%endif - - INC_SRC_BY_SRC_STRIDE - -.x_other_y_other_loop: - movx m2, [srcq] - movx m1, [srcq+1] - - INC_SRC_BY_SRC_STRIDE - movx m4, [srcq] - movx m3, [srcq+1] - -%if cpuflag(ssse3) - punpcklbw m2, m1 - punpcklbw m4, m3 - pmaddubsw m2, filter_x_a - pmaddubsw m4, filter_x_a - movx m3, [dstq+dst_strideq] - movx m1, [dstq] - paddw m2, filter_rnd - paddw m4, filter_rnd - psraw m2, 4 - psraw m4, 4 - packuswb m2, m2 - packuswb m4, m4 - punpcklbw m0, m2 - punpcklbw m2, m4 - pmaddubsw m0, filter_y_a - pmaddubsw m2, filter_y_a - punpcklbw m3, m5 - paddw m0, filter_rnd - paddw m2, filter_rnd - psraw m0, 4 - psraw m2, 4 - punpcklbw m1, m5 -%else - punpcklbw m2, m5 - punpcklbw m1, m5 - punpcklbw m4, m5 - punpcklbw m3, m5 - pmullw m2, filter_x_a - pmullw m1, filter_x_b - paddw m2, filter_rnd - pmullw m4, filter_x_a - pmullw m3, filter_x_b - paddw m4, filter_rnd - paddw m2, m1 - paddw m4, m3 - psraw m2, 4 - psraw m4, 4 - pmullw m0, filter_y_a - pmullw m3, m2, filter_y_b - paddw m0, filter_rnd - pmullw m2, filter_y_a - pmullw m1, m4, filter_y_b - paddw m2, filter_rnd - paddw m0, m3 - movx m3, [dstq+dst_strideq] - paddw m2, m1 - movx m1, [dstq] - psraw m0, 4 - psraw m2, 4 - punpcklbw m3, m5 - punpcklbw m1, m5 -%endif -%if %2 == 1 ; avg - ; FIXME(rbultje) pipeline -%if %1 == 4 - movlhps m0, m2 -%endif - packuswb m0, m2 -%if %1 > 4 - pavgb m0, [secq] - punpckhbw m2, m0, m5 - punpcklbw m0, m5 -%else - movh m2, [secq] - pavgb m0, m2 - punpcklbw m0, m5 - movhlps m2, m0 -%endif -%endif - SUM_SSE m0, m1, m2, m3, m6, m7 - mova m0, m4 - - INC_SRC_BY_SRC_STRIDE - lea dstq, [dstq+dst_strideq*2] -%endif -%if %2 == 1 ; avg - add secq, sec_str -%endif - dec block_height - jg .x_other_y_other_loop -%undef filter_x_a -%undef filter_x_b -%undef filter_y_a -%undef filter_y_b -%undef filter_rnd -%undef movx - STORE_AND_RET %1 -%endmacro - -; FIXME(rbultje) the non-bilinear versions (i.e. x=0,8&&y=0,8) are identical -; between the ssse3 and non-ssse3 version. It may make sense to merge their -; code in the sense that the ssse3 version would jump to the appropriate -; location in the sse/2 version, rather than duplicating that code in the -; binary. - -INIT_XMM sse2 -SUBPEL_VARIANCE 4 -SUBPEL_VARIANCE 8 -SUBPEL_VARIANCE 16 - -INIT_XMM ssse3 -SUBPEL_VARIANCE 4 -SUBPEL_VARIANCE 8 -SUBPEL_VARIANCE 16 - -INIT_XMM sse2 -SUBPEL_VARIANCE 4, 1 -SUBPEL_VARIANCE 8, 1 -SUBPEL_VARIANCE 16, 1 - -INIT_XMM ssse3 -SUBPEL_VARIANCE 4, 1 -SUBPEL_VARIANCE 8, 1 -SUBPEL_VARIANCE 16, 1 diff --git a/third_party/aom/aom_dsp/x86/subpel_variance_ssse3.asm b/third_party/aom/aom_dsp/x86/subpel_variance_ssse3.asm new file mode 100644 index 0000000000..f424ce01dd --- /dev/null +++ b/third_party/aom/aom_dsp/x86/subpel_variance_ssse3.asm @@ -0,0 +1,1442 @@ +; +; Copyright (c) 2016, Alliance for Open Media. All rights reserved +; +; This source code is subject to the terms of the BSD 2 Clause License and +; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +; was not distributed with this source code in the LICENSE file, you can +; obtain it at www.aomedia.org/license/software. If the Alliance for Open +; Media Patent License 1.0 was not distributed with this source code in the +; PATENTS file, you can obtain it at www.aomedia.org/license/patent. +; + +; + +%include "third_party/x86inc/x86inc.asm" + +SECTION_RODATA +pw_8: times 8 dw 8 + +bilin_filter_m_ssse3: times 8 db 16, 0 + times 8 db 14, 2 + times 8 db 12, 4 + times 8 db 10, 6 + times 16 db 8 + times 8 db 6, 10 + times 8 db 4, 12 + times 8 db 2, 14 + +SECTION .text + +; int aom_sub_pixel_varianceNxh(const uint8_t *src, ptrdiff_t src_stride, +; int x_offset, int y_offset, +; const uint8_t *dst, ptrdiff_t dst_stride, +; int height, unsigned int *sse); +; +; This function returns the SE and stores SSE in the given pointer. + +%macro SUM_SSE 6 ; src1, dst1, src2, dst2, sum, sse + psubw %3, %4 + psubw %1, %2 + paddw %5, %3 + pmaddwd %3, %3 + paddw %5, %1 + pmaddwd %1, %1 + paddd %6, %3 + paddd %6, %1 +%endmacro + +%macro STORE_AND_RET 1 +%if %1 > 4 + ; if H=64 and W=16, we have 8 words of each 2(1bit)x64(6bit)x9bit=16bit + ; in m6, i.e. it _exactly_ fits in a signed word per word in the xmm reg. + ; We have to sign-extend it before adding the words within the register + ; and outputing to a dword. + pcmpgtw m5, m6 ; mask for 0 > x + movhlps m3, m7 + punpcklwd m4, m6, m5 + punpckhwd m6, m5 ; sign-extend m6 word->dword + paddd m7, m3 + paddd m6, m4 + pshufd m3, m7, 0x1 + movhlps m4, m6 + paddd m7, m3 + paddd m6, m4 + mov r1, ssem ; r1 = unsigned int *sse + pshufd m4, m6, 0x1 + movd [r1], m7 ; store sse + paddd m6, m4 + movd raxd, m6 ; store sum as return value +%else ; 4xh + pshuflw m4, m6, 0xe + pshuflw m3, m7, 0xe + paddw m6, m4 + paddd m7, m3 + pcmpgtw m5, m6 ; mask for 0 > x + mov r1, ssem ; r1 = unsigned int *sse + punpcklwd m6, m5 ; sign-extend m6 word->dword + movd [r1], m7 ; store sse + pshuflw m4, m6, 0xe + paddd m6, m4 + movd raxd, m6 ; store sum as return value +%endif + RET +%endmacro + +%macro INC_SRC_BY_SRC_STRIDE 0 +%if AOM_ARCH_X86=1 && CONFIG_PIC=1 + add srcq, src_stridemp +%else + add srcq, src_strideq +%endif +%endmacro + +%macro SUBPEL_VARIANCE 1-2 0 ; W +%if cpuflag(ssse3) +%define bilin_filter_m bilin_filter_m_ssse3 +%define filter_idx_shift 4 +%endif +; FIXME(rbultje) only bilinear filters use >8 registers, and ssse3 only uses +; 11, not 13, if the registers are ordered correctly. May make a minor speed +; difference on Win64 + +%if AOM_ARCH_X86_64 + %if %2 == 1 ; avg + cglobal sub_pixel_avg_variance%1xh, 9, 10, 13, src, src_stride, \ + x_offset, y_offset, dst, dst_stride, \ + sec, sec_stride, height, sse + %define sec_str sec_strideq + %else + cglobal sub_pixel_variance%1xh, 7, 8, 13, src, src_stride, \ + x_offset, y_offset, dst, dst_stride, \ + height, sse + %endif + %define block_height heightd + %define bilin_filter sseq +%else + %if CONFIG_PIC=1 + %if %2 == 1 ; avg + cglobal sub_pixel_avg_variance%1xh, 7, 7, 13, src, src_stride, \ + x_offset, y_offset, dst, dst_stride, \ + sec, sec_stride, height, sse + %define block_height dword heightm + %define sec_str sec_stridemp + %else + cglobal sub_pixel_variance%1xh, 7, 7, 13, src, src_stride, \ + x_offset, y_offset, dst, dst_stride, \ + height, sse + %define block_height heightd + %endif + + ; reuse argument stack space + %define g_bilin_filterm x_offsetm + %define g_pw_8m y_offsetm + + ;Store bilin_filter and pw_8 location in stack + %if GET_GOT_DEFINED == 1 + GET_GOT eax + add esp, 4 ; restore esp + %endif + + lea ecx, [GLOBAL(bilin_filter_m)] + mov g_bilin_filterm, ecx + + lea ecx, [GLOBAL(pw_8)] + mov g_pw_8m, ecx + + LOAD_IF_USED 0, 1 ; load eax, ecx back + %else + %if %2 == 1 ; avg + cglobal sub_pixel_avg_variance%1xh, 7, 7, 13, src, src_stride, \ + x_offset, y_offset, \ + dst, dst_stride, sec, sec_stride, \ + height, sse + %define block_height dword heightm + %define sec_str sec_stridemp + %else + cglobal sub_pixel_variance%1xh, 7, 7, 13, src, src_stride, \ + x_offset, y_offset, dst, dst_stride, \ + height, sse + %define block_height heightd + %endif + %define bilin_filter bilin_filter_m + %endif +%endif + +%if %1 == 4 + %define movx movd +%else + %define movx movh +%endif + + ASSERT %1 <= 16 ; m6 overflows if w > 16 + pxor m6, m6 ; sum + pxor m7, m7 ; sse + ; FIXME(rbultje) if both filters are bilinear, we don't actually use m5; we + ; could perhaps use it for something more productive then + pxor m5, m5 ; dedicated zero register +%if %1 < 16 + sar block_height, 1 +%if %2 == 1 ; avg + shl sec_str, 1 +%endif +%endif + + ; FIXME(rbultje) replace by jumptable? + test x_offsetd, x_offsetd + jnz .x_nonzero + ; x_offset == 0 + test y_offsetd, y_offsetd + jnz .x_zero_y_nonzero + + ; x_offset == 0 && y_offset == 0 +.x_zero_y_zero_loop: +%if %1 == 16 + movu m0, [srcq] + mova m1, [dstq] +%if %2 == 1 ; avg + pavgb m0, [secq] + punpckhbw m3, m1, m5 + punpcklbw m1, m5 +%endif + punpckhbw m2, m0, m5 + punpcklbw m0, m5 + +%if %2 == 0 ; !avg + punpckhbw m3, m1, m5 + punpcklbw m1, m5 +%endif + SUM_SSE m0, m1, m2, m3, m6, m7 + + add srcq, src_strideq + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] +%if %2 == 1 ; avg +%if %1 > 4 + movhps m0, [srcq+src_strideq] +%else ; 4xh + movx m1, [srcq+src_strideq] + punpckldq m0, m1 +%endif +%else ; !avg + movx m2, [srcq+src_strideq] +%endif + + movx m1, [dstq] + movx m3, [dstq+dst_strideq] + +%if %2 == 1 ; avg +%if %1 > 4 + pavgb m0, [secq] +%else + movh m2, [secq] + pavgb m0, m2 +%endif + punpcklbw m3, m5 + punpcklbw m1, m5 +%if %1 > 4 + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else ; 4xh + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%else ; !avg + punpcklbw m0, m5 + punpcklbw m2, m5 + punpcklbw m3, m5 + punpcklbw m1, m5 +%endif + SUM_SSE m0, m1, m2, m3, m6, m7 + + lea srcq, [srcq+src_strideq*2] + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_zero_y_zero_loop + STORE_AND_RET %1 + +.x_zero_y_nonzero: + cmp y_offsetd, 4 + jne .x_zero_y_nonhalf + + ; x_offset == 0 && y_offset == 0.5 +.x_zero_y_half_loop: +%if %1 == 16 + movu m0, [srcq] + movu m4, [srcq+src_strideq] + mova m1, [dstq] + pavgb m0, m4 + punpckhbw m3, m1, m5 +%if %2 == 1 ; avg + pavgb m0, [secq] +%endif + punpcklbw m1, m5 + punpckhbw m2, m0, m5 + punpcklbw m0, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + + add srcq, src_strideq + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] + movx m2, [srcq+src_strideq] +%if %2 == 1 ; avg +%if %1 > 4 + movhps m2, [srcq+src_strideq*2] +%else ; 4xh + movx m1, [srcq+src_strideq*2] + punpckldq m2, m1 +%endif + movx m1, [dstq] +%if %1 > 4 + movlhps m0, m2 +%else ; 4xh + punpckldq m0, m2 +%endif + movx m3, [dstq+dst_strideq] + pavgb m0, m2 + punpcklbw m1, m5 +%if %1 > 4 + pavgb m0, [secq] + punpcklbw m3, m5 + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else ; 4xh + movh m4, [secq] + pavgb m0, m4 + punpcklbw m3, m5 + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%else ; !avg + movx m4, [srcq+src_strideq*2] + movx m1, [dstq] + pavgb m0, m2 + movx m3, [dstq+dst_strideq] + pavgb m2, m4 + punpcklbw m0, m5 + punpcklbw m2, m5 + punpcklbw m3, m5 + punpcklbw m1, m5 +%endif + SUM_SSE m0, m1, m2, m3, m6, m7 + + lea srcq, [srcq+src_strideq*2] + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_zero_y_half_loop + STORE_AND_RET %1 + +.x_zero_y_nonhalf: + ; x_offset == 0 && y_offset == bilin interpolation +%if AOM_ARCH_X86_64 + lea bilin_filter, [GLOBAL(bilin_filter_m)] +%endif + shl y_offsetd, filter_idx_shift +%if AOM_ARCH_X86_64 && %1 > 4 + mova m8, [bilin_filter+y_offsetq] +%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 + mova m9, [bilin_filter+y_offsetq+16] +%endif + mova m10, [GLOBAL(pw_8)] +%define filter_y_a m8 +%define filter_y_b m9 +%define filter_rnd m10 +%else ; x86-32 or mmx +%if AOM_ARCH_X86=1 && CONFIG_PIC=1 +; x_offset == 0, reuse x_offset reg +%define tempq x_offsetq + add y_offsetq, g_bilin_filterm +%define filter_y_a [y_offsetq] +%define filter_y_b [y_offsetq+16] + mov tempq, g_pw_8m +%define filter_rnd [tempq] +%else + add y_offsetq, bilin_filter +%define filter_y_a [y_offsetq] +%define filter_y_b [y_offsetq+16] +%define filter_rnd [GLOBAL(pw_8)] +%endif +%endif + +.x_zero_y_other_loop: +%if %1 == 16 + movu m0, [srcq] + movu m4, [srcq+src_strideq] + mova m1, [dstq] +%if cpuflag(ssse3) + punpckhbw m2, m0, m4 + punpcklbw m0, m4 + pmaddubsw m2, filter_y_a + pmaddubsw m0, filter_y_a + paddw m2, filter_rnd + paddw m0, filter_rnd +%else + punpckhbw m2, m0, m5 + punpckhbw m3, m4, m5 + punpcklbw m0, m5 + punpcklbw m4, m5 + ; FIXME(rbultje) instead of out=((num-x)*in1+x*in2+rnd)>>log2(num), we can + ; also do out=in1+(((num-x)*(in2-in1)+rnd)>>log2(num)). Total number of + ; instructions is the same (5), but it is 1 mul instead of 2, so might be + ; slightly faster because of pmullw latency. It would also cut our rodata + ; tables in half for this function, and save 1-2 registers on x86-64. + pmullw m2, filter_y_a + pmullw m3, filter_y_b + paddw m2, filter_rnd + pmullw m0, filter_y_a + pmullw m4, filter_y_b + paddw m0, filter_rnd + paddw m2, m3 + paddw m0, m4 +%endif + psraw m2, 4 + psraw m0, 4 +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline + packuswb m0, m2 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%endif + punpckhbw m3, m1, m5 + punpcklbw m1, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + + add srcq, src_strideq + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] + movx m2, [srcq+src_strideq] + movx m4, [srcq+src_strideq*2] + movx m3, [dstq+dst_strideq] +%if cpuflag(ssse3) + movx m1, [dstq] + punpcklbw m0, m2 + punpcklbw m2, m4 + pmaddubsw m0, filter_y_a + pmaddubsw m2, filter_y_a + punpcklbw m3, m5 + paddw m2, filter_rnd + paddw m0, filter_rnd +%else + punpcklbw m0, m5 + punpcklbw m2, m5 + punpcklbw m4, m5 + pmullw m0, filter_y_a + pmullw m1, m2, filter_y_b + punpcklbw m3, m5 + paddw m0, filter_rnd + pmullw m2, filter_y_a + pmullw m4, filter_y_b + paddw m0, m1 + paddw m2, filter_rnd + movx m1, [dstq] + paddw m2, m4 +%endif + psraw m0, 4 + psraw m2, 4 +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline +%if %1 == 4 + movlhps m0, m2 +%endif + packuswb m0, m2 +%if %1 > 4 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else ; 4xh + movh m2, [secq] + pavgb m0, m2 + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%endif + punpcklbw m1, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + + lea srcq, [srcq+src_strideq*2] + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_zero_y_other_loop +%undef filter_y_a +%undef filter_y_b +%undef filter_rnd + STORE_AND_RET %1 + +.x_nonzero: + cmp x_offsetd, 4 + jne .x_nonhalf + ; x_offset == 0.5 + test y_offsetd, y_offsetd + jnz .x_half_y_nonzero + + ; x_offset == 0.5 && y_offset == 0 +.x_half_y_zero_loop: +%if %1 == 16 + movu m0, [srcq] + movu m4, [srcq+1] + mova m1, [dstq] + pavgb m0, m4 + punpckhbw m3, m1, m5 +%if %2 == 1 ; avg + pavgb m0, [secq] +%endif + punpcklbw m1, m5 + punpckhbw m2, m0, m5 + punpcklbw m0, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + + add srcq, src_strideq + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] + movx m4, [srcq+1] +%if %2 == 1 ; avg +%if %1 > 4 + movhps m0, [srcq+src_strideq] + movhps m4, [srcq+src_strideq+1] +%else ; 4xh + movx m1, [srcq+src_strideq] + punpckldq m0, m1 + movx m2, [srcq+src_strideq+1] + punpckldq m4, m2 +%endif + movx m1, [dstq] + movx m3, [dstq+dst_strideq] + pavgb m0, m4 + punpcklbw m3, m5 +%if %1 > 4 + pavgb m0, [secq] + punpcklbw m1, m5 + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else ; 4xh + movh m2, [secq] + pavgb m0, m2 + punpcklbw m1, m5 + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%else ; !avg + movx m2, [srcq+src_strideq] + movx m1, [dstq] + pavgb m0, m4 + movx m4, [srcq+src_strideq+1] + movx m3, [dstq+dst_strideq] + pavgb m2, m4 + punpcklbw m0, m5 + punpcklbw m2, m5 + punpcklbw m3, m5 + punpcklbw m1, m5 +%endif + SUM_SSE m0, m1, m2, m3, m6, m7 + + lea srcq, [srcq+src_strideq*2] + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_half_y_zero_loop + STORE_AND_RET %1 + +.x_half_y_nonzero: + cmp y_offsetd, 4 + jne .x_half_y_nonhalf + + ; x_offset == 0.5 && y_offset == 0.5 +%if %1 == 16 + movu m0, [srcq] + movu m3, [srcq+1] + add srcq, src_strideq + pavgb m0, m3 +.x_half_y_half_loop: + movu m4, [srcq] + movu m3, [srcq+1] + mova m1, [dstq] + pavgb m4, m3 + punpckhbw m3, m1, m5 + pavgb m0, m4 +%if %2 == 1 ; avg + punpcklbw m1, m5 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else + punpckhbw m2, m0, m5 + punpcklbw m0, m5 + punpcklbw m1, m5 +%endif + SUM_SSE m0, m1, m2, m3, m6, m7 + mova m0, m4 + + add srcq, src_strideq + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] + movx m3, [srcq+1] + add srcq, src_strideq + pavgb m0, m3 +.x_half_y_half_loop: + movx m2, [srcq] + movx m3, [srcq+1] +%if %2 == 1 ; avg +%if %1 > 4 + movhps m2, [srcq+src_strideq] + movhps m3, [srcq+src_strideq+1] +%else + movx m1, [srcq+src_strideq] + punpckldq m2, m1 + movx m1, [srcq+src_strideq+1] + punpckldq m3, m1 +%endif + pavgb m2, m3 +%if %1 > 4 + movlhps m0, m2 + movhlps m4, m2 +%else ; 4xh + punpckldq m0, m2 + pshuflw m4, m2, 0xe +%endif + movx m1, [dstq] + pavgb m0, m2 + movx m3, [dstq+dst_strideq] +%if %1 > 4 + pavgb m0, [secq] +%else + movh m2, [secq] + pavgb m0, m2 +%endif + punpcklbw m3, m5 + punpcklbw m1, m5 +%if %1 > 4 + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%else ; !avg + movx m4, [srcq+src_strideq] + movx m1, [srcq+src_strideq+1] + pavgb m2, m3 + pavgb m4, m1 + pavgb m0, m2 + pavgb m2, m4 + movx m1, [dstq] + movx m3, [dstq+dst_strideq] + punpcklbw m0, m5 + punpcklbw m2, m5 + punpcklbw m3, m5 + punpcklbw m1, m5 +%endif + SUM_SSE m0, m1, m2, m3, m6, m7 + mova m0, m4 + + lea srcq, [srcq+src_strideq*2] + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_half_y_half_loop + STORE_AND_RET %1 + +.x_half_y_nonhalf: + ; x_offset == 0.5 && y_offset == bilin interpolation +%if AOM_ARCH_X86_64 + lea bilin_filter, [GLOBAL(bilin_filter_m)] +%endif + shl y_offsetd, filter_idx_shift +%if AOM_ARCH_X86_64 && %1 > 4 + mova m8, [bilin_filter+y_offsetq] +%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 + mova m9, [bilin_filter+y_offsetq+16] +%endif + mova m10, [GLOBAL(pw_8)] +%define filter_y_a m8 +%define filter_y_b m9 +%define filter_rnd m10 +%else ;x86_32 +%if AOM_ARCH_X86=1 && CONFIG_PIC=1 +; x_offset == 0.5. We can reuse x_offset reg +%define tempq x_offsetq + add y_offsetq, g_bilin_filterm +%define filter_y_a [y_offsetq] +%define filter_y_b [y_offsetq+16] + mov tempq, g_pw_8m +%define filter_rnd [tempq] +%else + add y_offsetq, bilin_filter +%define filter_y_a [y_offsetq] +%define filter_y_b [y_offsetq+16] +%define filter_rnd [GLOBAL(pw_8)] +%endif +%endif + +%if %1 == 16 + movu m0, [srcq] + movu m3, [srcq+1] + add srcq, src_strideq + pavgb m0, m3 +.x_half_y_other_loop: + movu m4, [srcq] + movu m2, [srcq+1] + mova m1, [dstq] + pavgb m4, m2 +%if cpuflag(ssse3) + punpckhbw m2, m0, m4 + punpcklbw m0, m4 + pmaddubsw m2, filter_y_a + pmaddubsw m0, filter_y_a + paddw m2, filter_rnd + paddw m0, filter_rnd + psraw m2, 4 +%else + punpckhbw m2, m0, m5 + punpckhbw m3, m4, m5 + pmullw m2, filter_y_a + pmullw m3, filter_y_b + paddw m2, filter_rnd + punpcklbw m0, m5 + paddw m2, m3 + punpcklbw m3, m4, m5 + pmullw m0, filter_y_a + pmullw m3, filter_y_b + paddw m0, filter_rnd + psraw m2, 4 + paddw m0, m3 +%endif + punpckhbw m3, m1, m5 + psraw m0, 4 +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline + packuswb m0, m2 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%endif + punpcklbw m1, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + mova m0, m4 + + add srcq, src_strideq + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] + movx m3, [srcq+1] + add srcq, src_strideq + pavgb m0, m3 +%if notcpuflag(ssse3) + punpcklbw m0, m5 +%endif +.x_half_y_other_loop: + movx m2, [srcq] + movx m1, [srcq+1] + movx m4, [srcq+src_strideq] + movx m3, [srcq+src_strideq+1] + pavgb m2, m1 + pavgb m4, m3 + movx m3, [dstq+dst_strideq] +%if cpuflag(ssse3) + movx m1, [dstq] + punpcklbw m0, m2 + punpcklbw m2, m4 + pmaddubsw m0, filter_y_a + pmaddubsw m2, filter_y_a + punpcklbw m3, m5 + paddw m0, filter_rnd + paddw m2, filter_rnd +%else + punpcklbw m2, m5 + punpcklbw m4, m5 + pmullw m0, filter_y_a + pmullw m1, m2, filter_y_b + punpcklbw m3, m5 + paddw m0, filter_rnd + pmullw m2, filter_y_a + paddw m0, m1 + pmullw m1, m4, filter_y_b + paddw m2, filter_rnd + paddw m2, m1 + movx m1, [dstq] +%endif + psraw m0, 4 + psraw m2, 4 +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline +%if %1 == 4 + movlhps m0, m2 +%endif + packuswb m0, m2 +%if %1 > 4 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else + movh m2, [secq] + pavgb m0, m2 + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%endif + punpcklbw m1, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + mova m0, m4 + + lea srcq, [srcq+src_strideq*2] + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_half_y_other_loop +%undef filter_y_a +%undef filter_y_b +%undef filter_rnd + STORE_AND_RET %1 + +.x_nonhalf: + test y_offsetd, y_offsetd + jnz .x_nonhalf_y_nonzero + + ; x_offset == bilin interpolation && y_offset == 0 +%if AOM_ARCH_X86_64 + lea bilin_filter, [GLOBAL(bilin_filter_m)] +%endif + shl x_offsetd, filter_idx_shift +%if AOM_ARCH_X86_64 && %1 > 4 + mova m8, [bilin_filter+x_offsetq] +%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 + mova m9, [bilin_filter+x_offsetq+16] +%endif + mova m10, [GLOBAL(pw_8)] +%define filter_x_a m8 +%define filter_x_b m9 +%define filter_rnd m10 +%else ; x86-32 +%if AOM_ARCH_X86=1 && CONFIG_PIC=1 +;y_offset == 0. We can reuse y_offset reg. +%define tempq y_offsetq + add x_offsetq, g_bilin_filterm +%define filter_x_a [x_offsetq] +%define filter_x_b [x_offsetq+16] + mov tempq, g_pw_8m +%define filter_rnd [tempq] +%else + add x_offsetq, bilin_filter +%define filter_x_a [x_offsetq] +%define filter_x_b [x_offsetq+16] +%define filter_rnd [GLOBAL(pw_8)] +%endif +%endif + +.x_other_y_zero_loop: +%if %1 == 16 + movu m0, [srcq] + movu m4, [srcq+1] + mova m1, [dstq] +%if cpuflag(ssse3) + punpckhbw m2, m0, m4 + punpcklbw m0, m4 + pmaddubsw m2, filter_x_a + pmaddubsw m0, filter_x_a + paddw m2, filter_rnd + paddw m0, filter_rnd +%else + punpckhbw m2, m0, m5 + punpckhbw m3, m4, m5 + punpcklbw m0, m5 + punpcklbw m4, m5 + pmullw m2, filter_x_a + pmullw m3, filter_x_b + paddw m2, filter_rnd + pmullw m0, filter_x_a + pmullw m4, filter_x_b + paddw m0, filter_rnd + paddw m2, m3 + paddw m0, m4 +%endif + psraw m2, 4 + psraw m0, 4 +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline + packuswb m0, m2 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%endif + punpckhbw m3, m1, m5 + punpcklbw m1, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + + add srcq, src_strideq + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] + movx m1, [srcq+1] + movx m2, [srcq+src_strideq] + movx m4, [srcq+src_strideq+1] + movx m3, [dstq+dst_strideq] +%if cpuflag(ssse3) + punpcklbw m0, m1 + movx m1, [dstq] + punpcklbw m2, m4 + pmaddubsw m0, filter_x_a + pmaddubsw m2, filter_x_a + punpcklbw m3, m5 + paddw m0, filter_rnd + paddw m2, filter_rnd +%else + punpcklbw m0, m5 + punpcklbw m1, m5 + punpcklbw m2, m5 + punpcklbw m4, m5 + pmullw m0, filter_x_a + pmullw m1, filter_x_b + punpcklbw m3, m5 + paddw m0, filter_rnd + pmullw m2, filter_x_a + pmullw m4, filter_x_b + paddw m0, m1 + paddw m2, filter_rnd + movx m1, [dstq] + paddw m2, m4 +%endif + psraw m0, 4 + psraw m2, 4 +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline +%if %1 == 4 + movlhps m0, m2 +%endif + packuswb m0, m2 +%if %1 > 4 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else + movh m2, [secq] + pavgb m0, m2 + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%endif + punpcklbw m1, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + + lea srcq, [srcq+src_strideq*2] + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_other_y_zero_loop +%undef filter_x_a +%undef filter_x_b +%undef filter_rnd + STORE_AND_RET %1 + +.x_nonhalf_y_nonzero: + cmp y_offsetd, 4 + jne .x_nonhalf_y_nonhalf + + ; x_offset == bilin interpolation && y_offset == 0.5 +%if AOM_ARCH_X86_64 + lea bilin_filter, [GLOBAL(bilin_filter_m)] +%endif + shl x_offsetd, filter_idx_shift +%if AOM_ARCH_X86_64 && %1 > 4 + mova m8, [bilin_filter+x_offsetq] +%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 + mova m9, [bilin_filter+x_offsetq+16] +%endif + mova m10, [GLOBAL(pw_8)] +%define filter_x_a m8 +%define filter_x_b m9 +%define filter_rnd m10 +%else ; x86-32 +%if AOM_ARCH_X86=1 && CONFIG_PIC=1 +; y_offset == 0.5. We can reuse y_offset reg. +%define tempq y_offsetq + add x_offsetq, g_bilin_filterm +%define filter_x_a [x_offsetq] +%define filter_x_b [x_offsetq+16] + mov tempq, g_pw_8m +%define filter_rnd [tempq] +%else + add x_offsetq, bilin_filter +%define filter_x_a [x_offsetq] +%define filter_x_b [x_offsetq+16] +%define filter_rnd [GLOBAL(pw_8)] +%endif +%endif + +%if %1 == 16 + movu m0, [srcq] + movu m1, [srcq+1] +%if cpuflag(ssse3) + punpckhbw m2, m0, m1 + punpcklbw m0, m1 + pmaddubsw m2, filter_x_a + pmaddubsw m0, filter_x_a + paddw m2, filter_rnd + paddw m0, filter_rnd +%else + punpckhbw m2, m0, m5 + punpckhbw m3, m1, m5 + punpcklbw m0, m5 + punpcklbw m1, m5 + pmullw m0, filter_x_a + pmullw m1, filter_x_b + paddw m0, filter_rnd + pmullw m2, filter_x_a + pmullw m3, filter_x_b + paddw m2, filter_rnd + paddw m0, m1 + paddw m2, m3 +%endif + psraw m0, 4 + psraw m2, 4 + add srcq, src_strideq + packuswb m0, m2 +.x_other_y_half_loop: + movu m4, [srcq] + movu m3, [srcq+1] +%if cpuflag(ssse3) + mova m1, [dstq] + punpckhbw m2, m4, m3 + punpcklbw m4, m3 + pmaddubsw m2, filter_x_a + pmaddubsw m4, filter_x_a + paddw m2, filter_rnd + paddw m4, filter_rnd + psraw m2, 4 + psraw m4, 4 + packuswb m4, m2 + pavgb m0, m4 + punpckhbw m3, m1, m5 + punpcklbw m1, m5 +%else + punpckhbw m2, m4, m5 + punpckhbw m1, m3, m5 + punpcklbw m4, m5 + punpcklbw m3, m5 + pmullw m4, filter_x_a + pmullw m3, filter_x_b + paddw m4, filter_rnd + pmullw m2, filter_x_a + pmullw m1, filter_x_b + paddw m2, filter_rnd + paddw m4, m3 + paddw m2, m1 + mova m1, [dstq] + psraw m4, 4 + psraw m2, 4 + punpckhbw m3, m1, m5 + ; FIXME(rbultje) the repeated pack/unpack here around m0/m2 is because we + ; have a 1-register shortage to be able to store the backup of the bilin + ; filtered second line as words as cache for the next line. Packing into + ; a byte costs 1 pack and 2 unpacks, but saves a register. + packuswb m4, m2 + punpcklbw m1, m5 + pavgb m0, m4 +%endif +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline + pavgb m0, [secq] +%endif + punpckhbw m2, m0, m5 + punpcklbw m0, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + mova m0, m4 + + add srcq, src_strideq + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] + movx m1, [srcq+1] +%if cpuflag(ssse3) + punpcklbw m0, m1 + pmaddubsw m0, filter_x_a + paddw m0, filter_rnd +%else + punpcklbw m0, m5 + punpcklbw m1, m5 + pmullw m0, filter_x_a + pmullw m1, filter_x_b + paddw m0, filter_rnd + paddw m0, m1 +%endif + add srcq, src_strideq + psraw m0, 4 +.x_other_y_half_loop: + movx m2, [srcq] + movx m1, [srcq+1] + movx m4, [srcq+src_strideq] + movx m3, [srcq+src_strideq+1] +%if cpuflag(ssse3) + punpcklbw m2, m1 + punpcklbw m4, m3 + pmaddubsw m2, filter_x_a + pmaddubsw m4, filter_x_a + movx m1, [dstq] + movx m3, [dstq+dst_strideq] + paddw m2, filter_rnd + paddw m4, filter_rnd +%else + punpcklbw m2, m5 + punpcklbw m1, m5 + punpcklbw m4, m5 + punpcklbw m3, m5 + pmullw m2, filter_x_a + pmullw m1, filter_x_b + paddw m2, filter_rnd + pmullw m4, filter_x_a + pmullw m3, filter_x_b + paddw m4, filter_rnd + paddw m2, m1 + movx m1, [dstq] + paddw m4, m3 + movx m3, [dstq+dst_strideq] +%endif + psraw m2, 4 + psraw m4, 4 + pavgw m0, m2 + pavgw m2, m4 +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline - also consider going to bytes here +%if %1 == 4 + movlhps m0, m2 +%endif + packuswb m0, m2 +%if %1 > 4 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else + movh m2, [secq] + pavgb m0, m2 + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%endif + punpcklbw m3, m5 + punpcklbw m1, m5 + SUM_SSE m0, m1, m2, m3, m6, m7 + mova m0, m4 + + lea srcq, [srcq+src_strideq*2] + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_other_y_half_loop +%undef filter_x_a +%undef filter_x_b +%undef filter_rnd + STORE_AND_RET %1 + +.x_nonhalf_y_nonhalf: +%if AOM_ARCH_X86_64 + lea bilin_filter, [GLOBAL(bilin_filter_m)] +%endif + shl x_offsetd, filter_idx_shift + shl y_offsetd, filter_idx_shift +%if AOM_ARCH_X86_64 && %1 > 4 + mova m8, [bilin_filter+x_offsetq] +%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 + mova m9, [bilin_filter+x_offsetq+16] +%endif + mova m10, [bilin_filter+y_offsetq] +%if notcpuflag(ssse3) ; FIXME(rbultje) don't scatter registers on x86-64 + mova m11, [bilin_filter+y_offsetq+16] +%endif + mova m12, [GLOBAL(pw_8)] +%define filter_x_a m8 +%define filter_x_b m9 +%define filter_y_a m10 +%define filter_y_b m11 +%define filter_rnd m12 +%else ; x86-32 +%if AOM_ARCH_X86=1 && CONFIG_PIC=1 +; In this case, there is NO unused register. Used src_stride register. Later, +; src_stride has to be loaded from stack when it is needed. +%define tempq src_strideq + mov tempq, g_bilin_filterm + add x_offsetq, tempq + add y_offsetq, tempq +%define filter_x_a [x_offsetq] +%define filter_x_b [x_offsetq+16] +%define filter_y_a [y_offsetq] +%define filter_y_b [y_offsetq+16] + + mov tempq, g_pw_8m +%define filter_rnd [tempq] +%else + add x_offsetq, bilin_filter + add y_offsetq, bilin_filter +%define filter_x_a [x_offsetq] +%define filter_x_b [x_offsetq+16] +%define filter_y_a [y_offsetq] +%define filter_y_b [y_offsetq+16] +%define filter_rnd [GLOBAL(pw_8)] +%endif +%endif + + ; x_offset == bilin interpolation && y_offset == bilin interpolation +%if %1 == 16 + movu m0, [srcq] + movu m1, [srcq+1] +%if cpuflag(ssse3) + punpckhbw m2, m0, m1 + punpcklbw m0, m1 + pmaddubsw m2, filter_x_a + pmaddubsw m0, filter_x_a + paddw m2, filter_rnd + paddw m0, filter_rnd +%else + punpckhbw m2, m0, m5 + punpckhbw m3, m1, m5 + punpcklbw m0, m5 + punpcklbw m1, m5 + pmullw m0, filter_x_a + pmullw m1, filter_x_b + paddw m0, filter_rnd + pmullw m2, filter_x_a + pmullw m3, filter_x_b + paddw m2, filter_rnd + paddw m0, m1 + paddw m2, m3 +%endif + psraw m0, 4 + psraw m2, 4 + + INC_SRC_BY_SRC_STRIDE + + packuswb m0, m2 +.x_other_y_other_loop: +%if cpuflag(ssse3) + movu m4, [srcq] + movu m3, [srcq+1] + mova m1, [dstq] + punpckhbw m2, m4, m3 + punpcklbw m4, m3 + pmaddubsw m2, filter_x_a + pmaddubsw m4, filter_x_a + punpckhbw m3, m1, m5 + paddw m2, filter_rnd + paddw m4, filter_rnd + psraw m2, 4 + psraw m4, 4 + packuswb m4, m2 + punpckhbw m2, m0, m4 + punpcklbw m0, m4 + pmaddubsw m2, filter_y_a + pmaddubsw m0, filter_y_a + punpcklbw m1, m5 + paddw m2, filter_rnd + paddw m0, filter_rnd + psraw m2, 4 + psraw m0, 4 +%else + movu m3, [srcq] + movu m4, [srcq+1] + punpckhbw m1, m3, m5 + punpckhbw m2, m4, m5 + punpcklbw m3, m5 + punpcklbw m4, m5 + pmullw m3, filter_x_a + pmullw m4, filter_x_b + paddw m3, filter_rnd + pmullw m1, filter_x_a + pmullw m2, filter_x_b + paddw m1, filter_rnd + paddw m3, m4 + paddw m1, m2 + psraw m3, 4 + psraw m1, 4 + packuswb m4, m3, m1 + punpckhbw m2, m0, m5 + punpcklbw m0, m5 + pmullw m2, filter_y_a + pmullw m1, filter_y_b + paddw m2, filter_rnd + pmullw m0, filter_y_a + pmullw m3, filter_y_b + paddw m2, m1 + mova m1, [dstq] + paddw m0, filter_rnd + psraw m2, 4 + paddw m0, m3 + punpckhbw m3, m1, m5 + psraw m0, 4 + punpcklbw m1, m5 +%endif +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline + packuswb m0, m2 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%endif + SUM_SSE m0, m1, m2, m3, m6, m7 + mova m0, m4 + + INC_SRC_BY_SRC_STRIDE + add dstq, dst_strideq +%else ; %1 < 16 + movx m0, [srcq] + movx m1, [srcq+1] +%if cpuflag(ssse3) + punpcklbw m0, m1 + pmaddubsw m0, filter_x_a + paddw m0, filter_rnd +%else + punpcklbw m0, m5 + punpcklbw m1, m5 + pmullw m0, filter_x_a + pmullw m1, filter_x_b + paddw m0, filter_rnd + paddw m0, m1 +%endif + psraw m0, 4 +%if cpuflag(ssse3) + packuswb m0, m0 +%endif + + INC_SRC_BY_SRC_STRIDE + +.x_other_y_other_loop: + movx m2, [srcq] + movx m1, [srcq+1] + + INC_SRC_BY_SRC_STRIDE + movx m4, [srcq] + movx m3, [srcq+1] + +%if cpuflag(ssse3) + punpcklbw m2, m1 + punpcklbw m4, m3 + pmaddubsw m2, filter_x_a + pmaddubsw m4, filter_x_a + movx m3, [dstq+dst_strideq] + movx m1, [dstq] + paddw m2, filter_rnd + paddw m4, filter_rnd + psraw m2, 4 + psraw m4, 4 + packuswb m2, m2 + packuswb m4, m4 + punpcklbw m0, m2 + punpcklbw m2, m4 + pmaddubsw m0, filter_y_a + pmaddubsw m2, filter_y_a + punpcklbw m3, m5 + paddw m0, filter_rnd + paddw m2, filter_rnd + psraw m0, 4 + psraw m2, 4 + punpcklbw m1, m5 +%else + punpcklbw m2, m5 + punpcklbw m1, m5 + punpcklbw m4, m5 + punpcklbw m3, m5 + pmullw m2, filter_x_a + pmullw m1, filter_x_b + paddw m2, filter_rnd + pmullw m4, filter_x_a + pmullw m3, filter_x_b + paddw m4, filter_rnd + paddw m2, m1 + paddw m4, m3 + psraw m2, 4 + psraw m4, 4 + pmullw m0, filter_y_a + pmullw m3, m2, filter_y_b + paddw m0, filter_rnd + pmullw m2, filter_y_a + pmullw m1, m4, filter_y_b + paddw m2, filter_rnd + paddw m0, m3 + movx m3, [dstq+dst_strideq] + paddw m2, m1 + movx m1, [dstq] + psraw m0, 4 + psraw m2, 4 + punpcklbw m3, m5 + punpcklbw m1, m5 +%endif +%if %2 == 1 ; avg + ; FIXME(rbultje) pipeline +%if %1 == 4 + movlhps m0, m2 +%endif + packuswb m0, m2 +%if %1 > 4 + pavgb m0, [secq] + punpckhbw m2, m0, m5 + punpcklbw m0, m5 +%else + movh m2, [secq] + pavgb m0, m2 + punpcklbw m0, m5 + movhlps m2, m0 +%endif +%endif + SUM_SSE m0, m1, m2, m3, m6, m7 + mova m0, m4 + + INC_SRC_BY_SRC_STRIDE + lea dstq, [dstq+dst_strideq*2] +%endif +%if %2 == 1 ; avg + add secq, sec_str +%endif + dec block_height + jg .x_other_y_other_loop +%undef filter_x_a +%undef filter_x_b +%undef filter_y_a +%undef filter_y_b +%undef filter_rnd +%undef movx + STORE_AND_RET %1 +%endmacro + +; FIXME(rbultje) the non-bilinear versions (i.e. x=0,8&&y=0,8) are identical +; between the ssse3 and non-ssse3 version. It may make sense to merge their +; code in the sense that the ssse3 version would jump to the appropriate +; location in the sse/2 version, rather than duplicating that code in the +; binary. + +INIT_XMM ssse3 +SUBPEL_VARIANCE 4 +SUBPEL_VARIANCE 8 +SUBPEL_VARIANCE 16 + +INIT_XMM ssse3 +SUBPEL_VARIANCE 4, 1 +SUBPEL_VARIANCE 8, 1 +SUBPEL_VARIANCE 16, 1 diff --git a/third_party/aom/aom_dsp/x86/synonyms.h b/third_party/aom/aom_dsp/x86/synonyms.h index 6744ec51d0..74318de2e5 100644 --- a/third_party/aom/aom_dsp/x86/synonyms.h +++ b/third_party/aom/aom_dsp/x86/synonyms.h @@ -46,6 +46,25 @@ static INLINE __m128i xx_loadu_128(const void *a) { return _mm_loadu_si128((const __m128i *)a); } + +// _mm_loadu_si64 has been introduced in GCC 9, reimplement the function +// manually on older compilers. +#if !defined(__clang__) && __GNUC_MAJOR__ < 9 +static INLINE __m128i xx_loadu_2x64(const void *hi, const void *lo) { + __m64 hi_, lo_; + memcpy(&hi_, hi, sizeof(hi_)); + memcpy(&lo_, lo, sizeof(lo_)); + return _mm_set_epi64(hi_, lo_); +} +#else +// Load 64 bits from each of hi and low, and pack into an SSE register +// Since directly loading as `int64_t`s and using _mm_set_epi64 may violate +// the strict aliasing rule, this takes a different approach +static INLINE __m128i xx_loadu_2x64(const void *hi, const void *lo) { + return _mm_unpacklo_epi64(_mm_loadu_si64(lo), _mm_loadu_si64(hi)); +} +#endif + static INLINE void xx_storel_32(void *const a, const __m128i v) { const int val = _mm_cvtsi128_si32(v); memcpy(a, &val, sizeof(val)); diff --git a/third_party/aom/aom_dsp/x86/synonyms_avx2.h b/third_party/aom/aom_dsp/x86/synonyms_avx2.h index b729e5f410..7548d4d4f4 100644 --- a/third_party/aom/aom_dsp/x86/synonyms_avx2.h +++ b/third_party/aom/aom_dsp/x86/synonyms_avx2.h @@ -43,6 +43,16 @@ static INLINE void yy_storeu_256(void *const a, const __m256i v) { _mm256_storeu_si256((__m256i *)a, v); } +// Fill an AVX register using an interleaved pair of values, ie. set the +// 16 channels to {a, b} repeated 8 times, using the same channel ordering +// as when a register is stored to / loaded from memory. +// +// This is useful for rearranging filter kernels for use with the _mm_madd_epi16 +// instruction +static INLINE __m256i yy_set2_epi16(int16_t a, int16_t b) { + return _mm256_setr_epi16(a, b, a, b, a, b, a, b, a, b, a, b, a, b, a, b); +} + // The _mm256_set1_epi64x() intrinsic is undefined for some Visual Studio // compilers. The following function is equivalent to _mm256_set1_epi64x() // acting on a 32-bit integer. @@ -61,11 +71,26 @@ static INLINE __m256i yy_set_m128i(__m128i hi, __m128i lo) { return _mm256_insertf128_si256(_mm256_castsi128_si256(lo), hi, 1); } +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + +// _mm256_loadu2_m128i has been introduced in GCC 10.1 +#if !defined(__clang__) && GCC_VERSION < 101000 +static INLINE __m256i yy_loadu2_128(const void *hi, const void *lo) { + __m128i mhi = _mm_loadu_si128((const __m128i *)(hi)); + __m128i mlo = _mm_loadu_si128((const __m128i *)(lo)); + return _mm256_set_m128i(mhi, mlo); +} +#else static INLINE __m256i yy_loadu2_128(const void *hi, const void *lo) { __m128i mhi = _mm_loadu_si128((const __m128i *)(hi)); __m128i mlo = _mm_loadu_si128((const __m128i *)(lo)); return yy_set_m128i(mhi, mlo); } +#endif + +#undef GCC_VERSION static INLINE void yy_storeu2_128(void *hi, void *lo, const __m256i a) { _mm_storeu_si128((__m128i *)hi, _mm256_extracti128_si256(a, 1)); diff --git a/third_party/aom/aom_dsp/x86/variance_avx2.c b/third_party/aom/aom_dsp/x86/variance_avx2.c index 046d6f10f8..0f872fc392 100644 --- a/third_party/aom/aom_dsp/x86/variance_avx2.c +++ b/third_party/aom/aom_dsp/x86/variance_avx2.c @@ -518,8 +518,8 @@ void aom_highbd_comp_mask_pred_avx2(uint8_t *comp_pred8, const uint8_t *pred8, } } -uint64_t aom_mse_4xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, - int sstride, int h) { +static uint64_t mse_4xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, + int sstride, int h) { uint64_t sum = 0; __m128i dst0_4x8, dst1_4x8, dst2_4x8, dst3_4x8, dst_16x8; __m128i src0_4x16, src1_4x16, src2_4x16, src3_4x16; @@ -575,8 +575,9 @@ uint64_t aom_mse_4xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, // In src buffer, each 4x4 block in a 32x32 filter block is stored sequentially. // Hence src_blk_stride is same as block width. Whereas dst buffer is a frame // buffer, thus dstride is a frame level stride. -uint64_t aom_mse_4xh_quad_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, - int src_blk_stride, int h) { +static uint64_t mse_4xh_quad_16bit_avx2(uint8_t *dst, int dstride, + uint16_t *src, int src_blk_stride, + int h) { uint64_t sum = 0; __m128i dst0_16x8, dst1_16x8, dst2_16x8, dst3_16x8; __m256i dst0_16x16, dst1_16x16, dst2_16x16, dst3_16x16; @@ -665,8 +666,8 @@ uint64_t aom_mse_4xh_quad_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, return sum; } -uint64_t aom_mse_8xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, - int sstride, int h) { +static uint64_t mse_8xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, + int sstride, int h) { uint64_t sum = 0; __m128i dst0_8x8, dst1_8x8, dst3_16x8; __m256i src0_8x16, src1_8x16, src_16x16, dst_16x16; @@ -715,8 +716,9 @@ uint64_t aom_mse_8xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, // In src buffer, each 8x8 block in a 64x64 filter block is stored sequentially. // Hence src_blk_stride is same as block width. Whereas dst buffer is a frame // buffer, thus dstride is a frame level stride. -uint64_t aom_mse_8xh_dual_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, - int src_blk_stride, int h) { +static uint64_t mse_8xh_dual_16bit_avx2(uint8_t *dst, int dstride, + uint16_t *src, int src_blk_stride, + int h) { uint64_t sum = 0; __m128i dst0_16x8, dst1_16x8; __m256i dst0_16x16, dst1_16x16; @@ -780,8 +782,8 @@ uint64_t aom_mse_wxh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, assert((w == 8 || w == 4) && (h == 8 || h == 4) && "w=8/4 and h=8/4 must be satisfied"); switch (w) { - case 4: return aom_mse_4xh_16bit_avx2(dst, dstride, src, sstride, h); - case 8: return aom_mse_8xh_16bit_avx2(dst, dstride, src, sstride, h); + case 4: return mse_4xh_16bit_avx2(dst, dstride, src, sstride, h); + case 8: return mse_8xh_16bit_avx2(dst, dstride, src, sstride, h); default: assert(0 && "unsupported width"); return -1; } } @@ -795,8 +797,8 @@ uint64_t aom_mse_16xh_16bit_avx2(uint8_t *dst, int dstride, uint16_t *src, assert((w == 8 || w == 4) && (h == 8 || h == 4) && "w=8/4 and h=8/4 must be satisfied"); switch (w) { - case 4: return aom_mse_4xh_quad_16bit_avx2(dst, dstride, src, w * h, h); - case 8: return aom_mse_8xh_dual_16bit_avx2(dst, dstride, src, w * h, h); + case 4: return mse_4xh_quad_16bit_avx2(dst, dstride, src, w * h, h); + case 8: return mse_8xh_dual_16bit_avx2(dst, dstride, src, w * h, h); default: assert(0 && "unsupported width"); return -1; } } diff --git a/third_party/aom/aom_dsp/x86/variance_impl_avx2.c b/third_party/aom/aom_dsp/x86/variance_impl_avx2.c index 9e9e70ea01..57a1cee781 100644 --- a/third_party/aom/aom_dsp/x86/variance_impl_avx2.c +++ b/third_party/aom/aom_dsp/x86/variance_impl_avx2.c @@ -648,7 +648,7 @@ MAKE_SUB_PIXEL_VAR_16XH(4, 2) #endif #define MAKE_SUB_PIXEL_AVG_VAR_32XH(height, log2height) \ - int aom_sub_pixel_avg_variance32x##height##_imp_avx2( \ + static int sub_pixel_avg_variance32x##height##_imp_avx2( \ const uint8_t *src, int src_stride, int x_offset, int y_offset, \ const uint8_t *dst, int dst_stride, const uint8_t *sec, int sec_stride, \ unsigned int *sse) { \ @@ -876,7 +876,7 @@ MAKE_SUB_PIXEL_VAR_16XH(4, 2) const uint8_t *src, int src_stride, int x_offset, int y_offset, \ const uint8_t *dst, int dst_stride, unsigned int *sse, \ const uint8_t *sec_ptr) { \ - const int sum = aom_sub_pixel_avg_variance32x##height##_imp_avx2( \ + const int sum = sub_pixel_avg_variance32x##height##_imp_avx2( \ src, src_stride, x_offset, y_offset, dst, dst_stride, sec_ptr, 32, \ sse); \ return *sse - (unsigned int)(((int64_t)sum * sum) >> (5 + log2height)); \ @@ -899,7 +899,7 @@ MAKE_SUB_PIXEL_AVG_VAR_32XH(16, 4) const uint8_t *sec_ptr = sec; \ for (int j = 0; j < (h / hf); ++j) { \ unsigned int sse2; \ - const int se2 = aom_sub_pixel_avg_variance##wf##x##hf##_imp_avx2( \ + const int se2 = sub_pixel_avg_variance##wf##x##hf##_imp_avx2( \ src_ptr, src_stride, x_offset, y_offset, dst_ptr, dst_stride, \ sec_ptr, w, &sse2); \ dst_ptr += hf * dst_stride; \ diff --git a/third_party/aom/aom_dsp/x86/variance_sse2.c b/third_party/aom/aom_dsp/x86/variance_sse2.c index faec9cf73d..81b30072a5 100644 --- a/third_party/aom/aom_dsp/x86/variance_sse2.c +++ b/third_party/aom/aom_dsp/x86/variance_sse2.c @@ -415,7 +415,6 @@ unsigned int aom_mse16x16_sse2(const uint8_t *src, int src_stride, DECL(8, opt); \ DECL(16, opt) -DECLS(sse2); DECLS(ssse3); #undef DECLS #undef DECL @@ -492,7 +491,6 @@ DECLS(ssse3); FN(4, 4, 4, 2, 2, opt, (int32_t), (int32_t)) #endif -FNS(sse2) FNS(ssse3) #undef FNS @@ -510,7 +508,6 @@ FNS(ssse3) DECL(8, opt); \ DECL(16, opt) -DECLS(sse2); DECLS(ssse3); #undef DECL #undef DECLS @@ -591,7 +588,6 @@ DECLS(ssse3); FN(4, 4, 4, 2, 2, opt, (uint32_t), (int32_t)) #endif -FNS(sse2) FNS(ssse3) #undef FNS @@ -710,8 +706,8 @@ void aom_highbd_comp_mask_pred_sse2(uint8_t *comp_pred8, const uint8_t *pred8, } } -uint64_t aom_mse_4xh_16bit_sse2(uint8_t *dst, int dstride, uint16_t *src, - int sstride, int h) { +static uint64_t mse_4xh_16bit_sse2(uint8_t *dst, int dstride, uint16_t *src, + int sstride, int h) { uint64_t sum = 0; __m128i dst0_8x8, dst1_8x8, dst_16x8; __m128i src0_16x4, src1_16x4, src_16x8; @@ -744,8 +740,8 @@ uint64_t aom_mse_4xh_16bit_sse2(uint8_t *dst, int dstride, uint16_t *src, return sum; } -uint64_t aom_mse_8xh_16bit_sse2(uint8_t *dst, int dstride, uint16_t *src, - int sstride, int h) { +static uint64_t mse_8xh_16bit_sse2(uint8_t *dst, int dstride, uint16_t *src, + int sstride, int h) { uint64_t sum = 0; __m128i dst_8x8, dst_16x8; __m128i src_16x8; @@ -781,8 +777,8 @@ uint64_t aom_mse_wxh_16bit_sse2(uint8_t *dst, int dstride, uint16_t *src, assert((w == 8 || w == 4) && (h == 8 || h == 4) && "w=8/4 and h=8/4 must satisfy"); switch (w) { - case 4: return aom_mse_4xh_16bit_sse2(dst, dstride, src, sstride, h); - case 8: return aom_mse_8xh_16bit_sse2(dst, dstride, src, sstride, h); + case 4: return mse_4xh_16bit_sse2(dst, dstride, src, sstride, h); + case 8: return mse_8xh_16bit_sse2(dst, dstride, src, sstride, h); default: assert(0 && "unsupported width"); return -1; } } diff --git a/third_party/aom/aom_ports/aarch64_cpudetect.c b/third_party/aom/aom_ports/aarch64_cpudetect.c index 43d5a149c8..159e5b1008 100644 --- a/third_party/aom/aom_ports/aarch64_cpudetect.c +++ b/third_party/aom/aom_ports/aarch64_cpudetect.c @@ -9,8 +9,12 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include "config/aom_config.h" + #include "arm_cpudetect.h" +#include "aom_ports/arm.h" + #if defined(__APPLE__) #include #endif @@ -104,12 +108,18 @@ static int arm_get_cpu_caps(void) { #define AOM_AARCH64_HWCAP_CRC32 (1 << 7) #define AOM_AARCH64_HWCAP_ASIMDDP (1 << 20) #define AOM_AARCH64_HWCAP_SVE (1 << 22) +#define AOM_AARCH64_HWCAP2_SVE2 (1 << 1) #define AOM_AARCH64_HWCAP2_I8MM (1 << 13) static int arm_get_cpu_caps(void) { int flags = 0; +#if HAVE_ARM_CRC32 || HAVE_NEON_DOTPROD || HAVE_SVE unsigned long hwcap = getauxval(AT_HWCAP); +#endif +#if HAVE_NEON_I8MM || HAVE_SVE2 unsigned long hwcap2 = getauxval(AT_HWCAP2); +#endif + #if HAVE_NEON flags |= HAS_NEON; // Neon is mandatory in Armv8.0-A. #endif // HAVE_NEON @@ -125,6 +135,9 @@ static int arm_get_cpu_caps(void) { #if HAVE_SVE if (hwcap & AOM_AARCH64_HWCAP_SVE) flags |= HAS_SVE; #endif // HAVE_SVE +#if HAVE_SVE2 + if (hwcap2 & AOM_AARCH64_HWCAP2_SVE2) flags |= HAS_SVE2; +#endif // HAVE_SVE2 return flags; } @@ -184,5 +197,8 @@ int aom_arm_cpu_caps(void) { if (!(flags & HAS_NEON_DOTPROD)) flags &= ~HAS_SVE; if (!(flags & HAS_NEON_I8MM)) flags &= ~HAS_SVE; + // Restrict flags: SVE2 assumes that FEAT_SVE is available. + if (!(flags & HAS_SVE)) flags &= ~HAS_SVE2; + return flags; } diff --git a/third_party/aom/aom_ports/arm.h b/third_party/aom/aom_ports/arm.h index 853741d19a..a57510895b 100644 --- a/third_party/aom/aom_ports/arm.h +++ b/third_party/aom/aom_ports/arm.h @@ -29,6 +29,8 @@ extern "C" { #define HAS_NEON_I8MM (1 << 3) // Armv8.2-A optional SVE instructions, mandatory from Armv9.0-A. #define HAS_SVE (1 << 4) +// Armv9.0-A SVE2 instructions. +#define HAS_SVE2 (1 << 5) int aom_arm_cpu_caps(void); diff --git a/third_party/aom/aom_ports/mem.h b/third_party/aom/aom_ports/mem.h index a70ce825b1..77180068ae 100644 --- a/third_party/aom/aom_ports/mem.h +++ b/third_party/aom/aom_ports/mem.h @@ -24,7 +24,13 @@ #define DECLARE_ALIGNED(n, typ, val) typ val #endif -#if HAVE_NEON && defined(_MSC_VER) +#if defined(__has_builtin) +#define AOM_HAS_BUILTIN(x) __has_builtin(x) +#else +#define AOM_HAS_BUILTIN(x) 0 +#endif + +#if !AOM_HAS_BUILTIN(__builtin_prefetch) && !defined(__GNUC__) #define __builtin_prefetch(x) #endif diff --git a/third_party/aom/aom_scale/aom_scale_rtcd.pl b/third_party/aom/aom_scale/aom_scale_rtcd.pl index ae0a85687f..0d545c2f3c 100644 --- a/third_party/aom/aom_scale/aom_scale_rtcd.pl +++ b/third_party/aom/aom_scale/aom_scale_rtcd.pl @@ -10,6 +10,8 @@ ## sub aom_scale_forward_decls() { print < + struct yv12_buffer_config; EOF } @@ -26,17 +28,17 @@ if (aom_config("CONFIG_SPATIAL_RESAMPLING") eq "yes") { add_proto qw/void aom_vertical_band_2_1_scale_i/, "unsigned char *source, int src_pitch, unsigned char *dest, int dest_pitch, unsigned int dest_width"; } -add_proto qw/int aom_yv12_realloc_with_new_border/, "struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_pyramid_levels, int num_planes"; +add_proto qw/int aom_yv12_realloc_with_new_border/, "struct yv12_buffer_config *ybf, int new_border, int byte_alignment, bool alloc_pyramid, int num_planes"; add_proto qw/void aom_yv12_extend_frame_borders/, "struct yv12_buffer_config *ybf, const int num_planes"; add_proto qw/void aom_yv12_copy_frame/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc, const int num_planes"; -add_proto qw/void aom_yv12_copy_y/, "const struct yv12_buffer_config *src_ybc, struct yv12_buffer_config *dst_ybc"; +add_proto qw/void aom_yv12_copy_y/, "const struct yv12_buffer_config *src_ybc, struct yv12_buffer_config *dst_ybc, int use_crop"; -add_proto qw/void aom_yv12_copy_u/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc"; +add_proto qw/void aom_yv12_copy_u/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc, int use_crop"; -add_proto qw/void aom_yv12_copy_v/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc"; +add_proto qw/void aom_yv12_copy_v/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc, int use_crop"; add_proto qw/void aom_yv12_partial_copy_y/, "const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2"; add_proto qw/void aom_yv12_partial_coloc_copy_y/, "const struct yv12_buffer_config *src_ybc, struct yv12_buffer_config *dst_ybc, int hstart, int hend, int vstart, int vend"; @@ -47,7 +49,7 @@ add_proto qw/void aom_yv12_partial_coloc_copy_v/, "const struct yv12_buffer_conf add_proto qw/void aom_extend_frame_borders_plane_row/, "const struct yv12_buffer_config *ybf, int plane, int v_start, int v_end"; -add_proto qw/void aom_extend_frame_borders/, "struct yv12_buffer_config *ybf, const int num_planes"; +add_proto qw/void aom_extend_frame_borders/, "struct yv12_buffer_config *ybf, int num_planes"; add_proto qw/void aom_extend_frame_inner_borders/, "struct yv12_buffer_config *ybf, const int num_planes"; diff --git a/third_party/aom/aom_scale/generic/yv12config.c b/third_party/aom/aom_scale/generic/yv12config.c index 94b400b9e0..ed35bb1acb 100644 --- a/third_party/aom/aom_scale/generic/yv12config.c +++ b/third_party/aom/aom_scale/generic/yv12config.c @@ -11,9 +11,12 @@ #include +#include "config/aom_config.h" + +#include "aom/aom_image.h" #include "aom/internal/aom_image_internal.h" -#include "aom_dsp/pyramid.h" #include "aom_dsp/flow_estimation/corner_detect.h" +#include "aom_dsp/pyramid.h" #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" #include "aom_scale/yv12config.h" @@ -60,7 +63,7 @@ static int realloc_frame_buffer_aligned( const uint64_t uvplane_size, const int aligned_width, const int aligned_height, const int uv_width, const int uv_height, const int uv_stride, const int uv_border_w, const int uv_border_h, - int num_pyramid_levels, int alloc_y_plane_only) { + bool alloc_pyramid, int alloc_y_plane_only) { if (ybf) { const int aom_byte_align = (byte_alignment == 0) ? 1 : byte_alignment; const uint64_t frame_size = @@ -71,8 +74,8 @@ static int realloc_frame_buffer_aligned( #if CONFIG_REALTIME_ONLY || !CONFIG_AV1_ENCODER // We should only need an 8-bit version of the source frame if we are // encoding in non-realtime mode - (void)num_pyramid_levels; - assert(num_pyramid_levels == 0); + (void)alloc_pyramid; + assert(!alloc_pyramid); #endif // CONFIG_REALTIME_ONLY || !CONFIG_AV1_ENCODER #if defined AOM_MAX_ALLOCABLE_MEMORY @@ -80,9 +83,8 @@ static int realloc_frame_buffer_aligned( uint64_t alloc_size = frame_size; #if CONFIG_AV1_ENCODER && !CONFIG_REALTIME_ONLY // The size of ybf->y_pyramid - if (num_pyramid_levels > 0) { - alloc_size += aom_get_pyramid_alloc_size( - width, height, num_pyramid_levels, use_highbitdepth); + if (alloc_pyramid) { + alloc_size += aom_get_pyramid_alloc_size(width, height, use_highbitdepth); alloc_size += av1_get_corner_list_size(); } #endif // CONFIG_AV1_ENCODER && !CONFIG_REALTIME_ONLY @@ -190,9 +192,8 @@ static int realloc_frame_buffer_aligned( av1_free_corner_list(ybf->corners); ybf->corners = NULL; } - if (num_pyramid_levels > 0) { - ybf->y_pyramid = aom_alloc_pyramid(width, height, num_pyramid_levels, - use_highbitdepth); + if (alloc_pyramid) { + ybf->y_pyramid = aom_alloc_pyramid(width, height, use_highbitdepth); if (!ybf->y_pyramid) return AOM_CODEC_MEM_ERROR; ybf->corners = av1_alloc_corner_list(); if (!ybf->corners) return AOM_CODEC_MEM_ERROR; @@ -237,7 +238,7 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int border, int byte_alignment, aom_codec_frame_buffer_t *fb, aom_get_frame_buffer_cb_fn_t cb, void *cb_priv, - int num_pyramid_levels, int alloc_y_plane_only) { + bool alloc_pyramid, int alloc_y_plane_only) { #if CONFIG_SIZE_LIMIT if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) return AOM_CODEC_MEM_ERROR; @@ -264,21 +265,20 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, ybf, width, height, ss_x, ss_y, use_highbitdepth, border, byte_alignment, fb, cb, cb_priv, y_stride, yplane_size, uvplane_size, aligned_width, aligned_height, uv_width, uv_height, uv_stride, - uv_border_w, uv_border_h, num_pyramid_levels, alloc_y_plane_only); + uv_border_w, uv_border_h, alloc_pyramid, alloc_y_plane_only); } return AOM_CODEC_MEM_ERROR; } int aom_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int ss_x, int ss_y, int use_highbitdepth, int border, - int byte_alignment, int num_pyramid_levels, + int byte_alignment, bool alloc_pyramid, int alloc_y_plane_only) { if (ybf) { aom_free_frame_buffer(ybf); - return aom_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, - use_highbitdepth, border, byte_alignment, - NULL, NULL, NULL, num_pyramid_levels, - alloc_y_plane_only); + return aom_realloc_frame_buffer( + ybf, width, height, ss_x, ss_y, use_highbitdepth, border, + byte_alignment, NULL, NULL, NULL, alloc_pyramid, alloc_y_plane_only); } return AOM_CODEC_MEM_ERROR; } diff --git a/third_party/aom/aom_scale/generic/yv12extend.c b/third_party/aom/aom_scale/generic/yv12extend.c index 5546112d40..384b72c21e 100644 --- a/third_party/aom/aom_scale/generic/yv12extend.c +++ b/third_party/aom/aom_scale/generic/yv12extend.c @@ -302,8 +302,10 @@ void aom_yv12_copy_frame_c(const YV12_BUFFER_CONFIG *src_bc, } void aom_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc, - YV12_BUFFER_CONFIG *dst_ybc) { + YV12_BUFFER_CONFIG *dst_ybc, int use_crop) { int row; + int width = use_crop ? src_ybc->y_crop_width : src_ybc->y_width; + int height = use_crop ? src_ybc->y_crop_height : src_ybc->y_height; const uint8_t *src = src_ybc->y_buffer; uint8_t *dst = dst_ybc->y_buffer; @@ -311,8 +313,8 @@ void aom_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc, if (src_ybc->flags & YV12_FLAG_HIGHBITDEPTH) { const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst); - for (row = 0; row < src_ybc->y_height; ++row) { - memcpy(dst16, src16, src_ybc->y_width * sizeof(uint16_t)); + for (row = 0; row < height; ++row) { + memcpy(dst16, src16, width * sizeof(uint16_t)); src16 += src_ybc->y_stride; dst16 += dst_ybc->y_stride; } @@ -320,56 +322,60 @@ void aom_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc, } #endif - for (row = 0; row < src_ybc->y_height; ++row) { - memcpy(dst, src, src_ybc->y_width); + for (row = 0; row < height; ++row) { + memcpy(dst, src, width); src += src_ybc->y_stride; dst += dst_ybc->y_stride; } } void aom_yv12_copy_u_c(const YV12_BUFFER_CONFIG *src_bc, - YV12_BUFFER_CONFIG *dst_bc) { + YV12_BUFFER_CONFIG *dst_bc, int use_crop) { int row; + int width = use_crop ? src_bc->uv_crop_width : src_bc->uv_width; + int height = use_crop ? src_bc->uv_crop_height : src_bc->uv_height; const uint8_t *src = src_bc->u_buffer; uint8_t *dst = dst_bc->u_buffer; #if CONFIG_AV1_HIGHBITDEPTH if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) { const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst); - for (row = 0; row < src_bc->uv_height; ++row) { - memcpy(dst16, src16, src_bc->uv_width * sizeof(uint16_t)); + for (row = 0; row < height; ++row) { + memcpy(dst16, src16, width * sizeof(uint16_t)); src16 += src_bc->uv_stride; dst16 += dst_bc->uv_stride; } return; } #endif - for (row = 0; row < src_bc->uv_height; ++row) { - memcpy(dst, src, src_bc->uv_width); + for (row = 0; row < height; ++row) { + memcpy(dst, src, width); src += src_bc->uv_stride; dst += dst_bc->uv_stride; } } void aom_yv12_copy_v_c(const YV12_BUFFER_CONFIG *src_bc, - YV12_BUFFER_CONFIG *dst_bc) { + YV12_BUFFER_CONFIG *dst_bc, int use_crop) { int row; + int width = use_crop ? src_bc->uv_crop_width : src_bc->uv_width; + int height = use_crop ? src_bc->uv_crop_height : src_bc->uv_height; const uint8_t *src = src_bc->v_buffer; uint8_t *dst = dst_bc->v_buffer; #if CONFIG_AV1_HIGHBITDEPTH if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) { const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst); - for (row = 0; row < src_bc->uv_height; ++row) { - memcpy(dst16, src16, src_bc->uv_width * sizeof(uint16_t)); + for (row = 0; row < height; ++row) { + memcpy(dst16, src16, width * sizeof(uint16_t)); src16 += src_bc->uv_stride; dst16 += dst_bc->uv_stride; } return; } #endif - for (row = 0; row < src_bc->uv_height; ++row) { - memcpy(dst, src, src_bc->uv_width); + for (row = 0; row < height; ++row) { + memcpy(dst, src, width); src += src_bc->uv_stride; dst += dst_bc->uv_stride; } @@ -491,8 +497,8 @@ void aom_yv12_partial_coloc_copy_v_c(const YV12_BUFFER_CONFIG *src_bc, } int aom_yv12_realloc_with_new_border_c(YV12_BUFFER_CONFIG *ybf, int new_border, - int byte_alignment, - int num_pyramid_levels, int num_planes) { + int byte_alignment, bool alloc_pyramid, + int num_planes) { if (ybf) { if (new_border == ybf->border) return 0; YV12_BUFFER_CONFIG new_buf; @@ -500,7 +506,7 @@ int aom_yv12_realloc_with_new_border_c(YV12_BUFFER_CONFIG *ybf, int new_border, const int error = aom_alloc_frame_buffer( &new_buf, ybf->y_crop_width, ybf->y_crop_height, ybf->subsampling_x, ybf->subsampling_y, ybf->flags & YV12_FLAG_HIGHBITDEPTH, new_border, - byte_alignment, num_pyramid_levels, 0); + byte_alignment, alloc_pyramid, 0); if (error) return error; // Copy image buffer aom_yv12_copy_frame(ybf, &new_buf, num_planes); diff --git a/third_party/aom/aom_scale/yv12config.h b/third_party/aom/aom_scale/yv12config.h index f192a3032e..bc05de2102 100644 --- a/third_party/aom/aom_scale/yv12config.h +++ b/third_party/aom/aom_scale/yv12config.h @@ -16,6 +16,8 @@ extern "C" { #endif +#include + #include "config/aom_config.h" #include "aom/aom_codec.h" @@ -45,18 +47,29 @@ typedef struct yv12_buffer_config { /*!\cond */ union { struct { + // The aligned frame width of luma. + // It is aligned to a multiple of 8: + // y_width = (y_crop_width + 7) & ~7 int y_width; + // The aligned frame width of chroma. + // uv_width = y_width >> subsampling_x int uv_width; }; int widths[2]; }; union { struct { + // The aligned frame height of luma. + // It is aligned to a multiple of 8: + // y_height = (y_crop_height + 7) & ~7 int y_height; + // The aligned frame height of chroma. + // uv_height = y_height >> subsampling_y int uv_height; }; int heights[2]; }; + // The frame size en/decoded by AV1 union { struct { int y_crop_width; @@ -139,7 +152,7 @@ typedef struct yv12_buffer_config { // available return values. int aom_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int ss_x, int ss_y, int use_highbitdepth, int border, - int byte_alignment, int num_pyramid_levels, + int byte_alignment, bool alloc_pyramid, int alloc_y_plane_only); // Updates the yv12 buffer config with the frame buffer. |byte_alignment| must @@ -149,15 +162,11 @@ int aom_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, // to decode the current frame. If cb is NULL, libaom will allocate memory // internally to decode the current frame. // -// If num_pyramid_levels > 0, then an image pyramid will be allocated with -// the specified number of levels. -// -// Any buffer which may become a source or ref frame buffer in the encoder -// must have num_pyramid_levels = cpi->image_pyramid_levels. This will cause -// an image pyramid to be allocated if one is needed. -// -// Any other buffers (in particular, any buffers inside the decoder) -// must have cpi->image_pyramid_levels = 0, as a pyramid is unneeded there. +// If alloc_pyramid is true, then an image pyramid will be allocated +// for use in global motion estimation. This is only needed if this frame +// buffer will be used to store a source frame or a reference frame in +// the encoder. Any other framebuffers (eg, intermediates for filtering, +// or any buffer in the decoder) can set alloc_pyramid = false. // // Returns 0 on success. Returns < 0 on failure. int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, @@ -165,7 +174,7 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int border, int byte_alignment, aom_codec_frame_buffer_t *fb, aom_get_frame_buffer_cb_fn_t cb, void *cb_priv, - int num_pyramid_levels, int alloc_y_plane_only); + bool alloc_pyramid, int alloc_y_plane_only); int aom_free_frame_buffer(YV12_BUFFER_CONFIG *ybf); diff --git a/third_party/aom/aom_util/aom_pthread.h b/third_party/aom/aom_util/aom_pthread.h new file mode 100644 index 0000000000..99deeb292a --- /dev/null +++ b/third_party/aom/aom_util/aom_pthread.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ +// +// pthread.h wrapper + +#ifndef AOM_AOM_UTIL_AOM_PTHREAD_H_ +#define AOM_AOM_UTIL_AOM_PTHREAD_H_ + +#include "config/aom_config.h" + +#if CONFIG_MULTITHREAD + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) && !HAVE_PTHREAD_H +// Prevent leaking max/min macros. +#undef NOMINMAX +#define NOMINMAX +#undef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#include // NOLINT +#include // NOLINT +#include // NOLINT +typedef HANDLE pthread_t; +typedef int pthread_attr_t; +typedef CRITICAL_SECTION pthread_mutex_t; + +#include + +#if _WIN32_WINNT < 0x0600 +#error _WIN32_WINNT must target Windows Vista / Server 2008 or newer. +#endif +typedef CONDITION_VARIABLE pthread_cond_t; + +#ifndef WINAPI_FAMILY_PARTITION +#define WINAPI_PARTITION_DESKTOP 1 +#define WINAPI_FAMILY_PARTITION(x) x +#endif + +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define USE_CREATE_THREAD +#endif + +//------------------------------------------------------------------------------ +// simplistic pthread emulation layer + +// _beginthreadex requires __stdcall +#if defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +#define THREADFN __attribute__((force_align_arg_pointer)) unsigned int __stdcall +#else +#define THREADFN unsigned int __stdcall +#endif +#define THREAD_EXIT_SUCCESS 0 + +static INLINE int pthread_attr_init(pthread_attr_t *attr) { + (void)attr; + return 0; +} + +static INLINE int pthread_attr_destroy(pthread_attr_t *attr) { + (void)attr; + return 0; +} + +static INLINE int pthread_create(pthread_t *const thread, + const pthread_attr_t *attr, + unsigned int(__stdcall *start)(void *), + void *arg) { + (void)attr; +#ifdef USE_CREATE_THREAD + *thread = CreateThread(NULL, /* lpThreadAttributes */ + 0, /* dwStackSize */ + start, arg, 0, /* dwStackSize */ + NULL); /* lpThreadId */ +#else + *thread = (pthread_t)_beginthreadex(NULL, /* void *security */ + 0, /* unsigned stack_size */ + start, arg, 0, /* unsigned initflag */ + NULL); /* unsigned *thrdaddr */ +#endif + if (*thread == NULL) return 1; + SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL); + return 0; +} + +static INLINE int pthread_join(pthread_t thread, void **value_ptr) { + (void)value_ptr; + return (WaitForSingleObjectEx(thread, INFINITE, FALSE /*bAlertable*/) != + WAIT_OBJECT_0 || + CloseHandle(thread) == 0); +} + +// Mutex +static INLINE int pthread_mutex_init(pthread_mutex_t *const mutex, + void *mutexattr) { + (void)mutexattr; + InitializeCriticalSectionEx(mutex, 0 /*dwSpinCount*/, 0 /*Flags*/); + return 0; +} + +static INLINE int pthread_mutex_trylock(pthread_mutex_t *const mutex) { + return TryEnterCriticalSection(mutex) ? 0 : EBUSY; +} + +static INLINE int pthread_mutex_lock(pthread_mutex_t *const mutex) { + EnterCriticalSection(mutex); + return 0; +} + +static INLINE int pthread_mutex_unlock(pthread_mutex_t *const mutex) { + LeaveCriticalSection(mutex); + return 0; +} + +static INLINE int pthread_mutex_destroy(pthread_mutex_t *const mutex) { + DeleteCriticalSection(mutex); + return 0; +} + +// Condition +static INLINE int pthread_cond_destroy(pthread_cond_t *const condition) { + (void)condition; + return 0; +} + +static INLINE int pthread_cond_init(pthread_cond_t *const condition, + void *cond_attr) { + (void)cond_attr; + InitializeConditionVariable(condition); + return 0; +} + +static INLINE int pthread_cond_signal(pthread_cond_t *const condition) { + WakeConditionVariable(condition); + return 0; +} + +static INLINE int pthread_cond_broadcast(pthread_cond_t *const condition) { + WakeAllConditionVariable(condition); + return 0; +} + +static INLINE int pthread_cond_wait(pthread_cond_t *const condition, + pthread_mutex_t *const mutex) { + int ok; + ok = SleepConditionVariableCS(condition, mutex, INFINITE); + return !ok; +} +#else // _WIN32 +#include // NOLINT +#define THREADFN void * +#define THREAD_EXIT_SUCCESS NULL +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // CONFIG_MULTITHREAD + +#endif // AOM_AOM_UTIL_AOM_PTHREAD_H_ diff --git a/third_party/aom/aom_util/aom_thread.c b/third_party/aom/aom_util/aom_thread.c index fa3b0a25e4..bdf2b7dfa6 100644 --- a/third_party/aom/aom_util/aom_thread.c +++ b/third_party/aom/aom_util/aom_thread.c @@ -23,8 +23,11 @@ #include #include // for memset() +#include "config/aom_config.h" + #include "aom_mem/aom_mem.h" #include "aom_ports/sanitizer.h" +#include "aom_util/aom_pthread.h" #include "aom_util/aom_thread.h" #if CONFIG_MULTITHREAD @@ -65,29 +68,30 @@ static THREADFN thread_loop(void *ptr) { #endif pthread_mutex_lock(&worker->impl_->mutex_); for (;;) { - while (worker->status_ == OK) { // wait in idling mode + while (worker->status_ == AVX_WORKER_STATUS_OK) { // wait in idling mode pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_); } - if (worker->status_ == WORK) { - // When worker->status_ is WORK, the main thread doesn't change - // worker->status_ and will wait until the worker changes worker->status_ - // to OK. See change_state(). So the worker can safely call execute() - // without holding worker->impl_->mutex_. When the worker reacquires - // worker->impl_->mutex_, worker->status_ must still be WORK. + if (worker->status_ == AVX_WORKER_STATUS_WORKING) { + // When worker->status_ is AVX_WORKER_STATUS_WORKING, the main thread + // doesn't change worker->status_ and will wait until the worker changes + // worker->status_ to AVX_WORKER_STATUS_OK. See change_state(). So the + // worker can safely call execute() without holding worker->impl_->mutex_. + // When the worker reacquires worker->impl_->mutex_, worker->status_ must + // still be AVX_WORKER_STATUS_WORKING. pthread_mutex_unlock(&worker->impl_->mutex_); execute(worker); pthread_mutex_lock(&worker->impl_->mutex_); - assert(worker->status_ == WORK); - worker->status_ = OK; + assert(worker->status_ == AVX_WORKER_STATUS_WORKING); + worker->status_ = AVX_WORKER_STATUS_OK; // signal to the main thread that we're done (for sync()) pthread_cond_signal(&worker->impl_->condition_); } else { - assert(worker->status_ == NOT_OK); // finish the worker + assert(worker->status_ == AVX_WORKER_STATUS_NOT_OK); // finish the worker break; } } pthread_mutex_unlock(&worker->impl_->mutex_); - return THREAD_RETURN(NULL); // Thread is finished + return THREAD_EXIT_SUCCESS; // Thread is finished } // main thread state control @@ -98,13 +102,13 @@ static void change_state(AVxWorker *const worker, AVxWorkerStatus new_status) { if (worker->impl_ == NULL) return; pthread_mutex_lock(&worker->impl_->mutex_); - if (worker->status_ >= OK) { + if (worker->status_ >= AVX_WORKER_STATUS_OK) { // wait for the worker to finish - while (worker->status_ != OK) { + while (worker->status_ != AVX_WORKER_STATUS_OK) { pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_); } // assign new status and release the working thread if needed - if (new_status != OK) { + if (new_status != AVX_WORKER_STATUS_OK) { worker->status_ = new_status; pthread_cond_signal(&worker->impl_->condition_); } @@ -118,21 +122,21 @@ static void change_state(AVxWorker *const worker, AVxWorkerStatus new_status) { static void init(AVxWorker *const worker) { memset(worker, 0, sizeof(*worker)); - worker->status_ = NOT_OK; + worker->status_ = AVX_WORKER_STATUS_NOT_OK; } static int sync(AVxWorker *const worker) { #if CONFIG_MULTITHREAD - change_state(worker, OK); + change_state(worker, AVX_WORKER_STATUS_OK); #endif - assert(worker->status_ <= OK); + assert(worker->status_ <= AVX_WORKER_STATUS_OK); return !worker->had_error; } static int reset(AVxWorker *const worker) { int ok = 1; worker->had_error = 0; - if (worker->status_ < OK) { + if (worker->status_ < AVX_WORKER_STATUS_OK) { #if CONFIG_MULTITHREAD worker->impl_ = (AVxWorkerImpl *)aom_calloc(1, sizeof(*worker->impl_)); if (worker->impl_ == NULL) { @@ -164,7 +168,7 @@ static int reset(AVxWorker *const worker) { #endif pthread_mutex_lock(&worker->impl_->mutex_); ok = !pthread_create(&worker->impl_->thread_, &attr, thread_loop, worker); - if (ok) worker->status_ = OK; + if (ok) worker->status_ = AVX_WORKER_STATUS_OK; pthread_mutex_unlock(&worker->impl_->mutex_); pthread_attr_destroy(&attr); if (!ok) { @@ -177,12 +181,12 @@ static int reset(AVxWorker *const worker) { return 0; } #else - worker->status_ = OK; + worker->status_ = AVX_WORKER_STATUS_OK; #endif - } else if (worker->status_ > OK) { + } else if (worker->status_ > AVX_WORKER_STATUS_OK) { ok = sync(worker); } - assert(!ok || (worker->status_ == OK)); + assert(!ok || (worker->status_ == AVX_WORKER_STATUS_OK)); return ok; } @@ -194,7 +198,7 @@ static void execute(AVxWorker *const worker) { static void launch(AVxWorker *const worker) { #if CONFIG_MULTITHREAD - change_state(worker, WORK); + change_state(worker, AVX_WORKER_STATUS_WORKING); #else execute(worker); #endif @@ -203,7 +207,7 @@ static void launch(AVxWorker *const worker) { static void end(AVxWorker *const worker) { #if CONFIG_MULTITHREAD if (worker->impl_ != NULL) { - change_state(worker, NOT_OK); + change_state(worker, AVX_WORKER_STATUS_NOT_OK); pthread_join(worker->impl_->thread_, NULL); pthread_mutex_destroy(&worker->impl_->mutex_); pthread_cond_destroy(&worker->impl_->condition_); @@ -211,10 +215,10 @@ static void end(AVxWorker *const worker) { worker->impl_ = NULL; } #else - worker->status_ = NOT_OK; + worker->status_ = AVX_WORKER_STATUS_NOT_OK; assert(worker->impl_ == NULL); #endif - assert(worker->status_ == NOT_OK); + assert(worker->status_ == AVX_WORKER_STATUS_NOT_OK); } //------------------------------------------------------------------------------ diff --git a/third_party/aom/aom_util/aom_thread.h b/third_party/aom/aom_util/aom_thread.h index ec2ea43491..92e162f121 100644 --- a/third_party/aom/aom_util/aom_thread.h +++ b/third_party/aom/aom_util/aom_thread.h @@ -17,157 +17,17 @@ #ifndef AOM_AOM_UTIL_AOM_THREAD_H_ #define AOM_AOM_UTIL_AOM_THREAD_H_ -#include "config/aom_config.h" - #ifdef __cplusplus extern "C" { #endif #define MAX_NUM_THREADS 64 -#if CONFIG_MULTITHREAD - -#if defined(_WIN32) && !HAVE_PTHREAD_H -// Prevent leaking max/min macros. -#undef NOMINMAX -#define NOMINMAX -#undef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#include // NOLINT -#include // NOLINT -#include // NOLINT -typedef HANDLE pthread_t; -typedef int pthread_attr_t; -typedef CRITICAL_SECTION pthread_mutex_t; - -#if _WIN32_WINNT < 0x0600 -#error _WIN32_WINNT must target Windows Vista / Server 2008 or newer. -#endif -typedef CONDITION_VARIABLE pthread_cond_t; - -#ifndef WINAPI_FAMILY_PARTITION -#define WINAPI_PARTITION_DESKTOP 1 -#define WINAPI_FAMILY_PARTITION(x) x -#endif - -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define USE_CREATE_THREAD -#endif - -//------------------------------------------------------------------------------ -// simplistic pthread emulation layer - -// _beginthreadex requires __stdcall -#define THREADFN unsigned int __stdcall -#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val) - -static INLINE int pthread_attr_init(pthread_attr_t *attr) { - (void)attr; - return 0; -} - -static INLINE int pthread_attr_destroy(pthread_attr_t *attr) { - (void)attr; - return 0; -} - -static INLINE int pthread_create(pthread_t *const thread, - const pthread_attr_t *attr, - unsigned int(__stdcall *start)(void *), - void *arg) { - (void)attr; -#ifdef USE_CREATE_THREAD - *thread = CreateThread(NULL, /* lpThreadAttributes */ - 0, /* dwStackSize */ - start, arg, 0, /* dwStackSize */ - NULL); /* lpThreadId */ -#else - *thread = (pthread_t)_beginthreadex(NULL, /* void *security */ - 0, /* unsigned stack_size */ - start, arg, 0, /* unsigned initflag */ - NULL); /* unsigned *thrdaddr */ -#endif - if (*thread == NULL) return 1; - SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL); - return 0; -} - -static INLINE int pthread_join(pthread_t thread, void **value_ptr) { - (void)value_ptr; - return (WaitForSingleObjectEx(thread, INFINITE, FALSE /*bAlertable*/) != - WAIT_OBJECT_0 || - CloseHandle(thread) == 0); -} - -// Mutex -static INLINE int pthread_mutex_init(pthread_mutex_t *const mutex, - void *mutexattr) { - (void)mutexattr; - InitializeCriticalSectionEx(mutex, 0 /*dwSpinCount*/, 0 /*Flags*/); - return 0; -} - -static INLINE int pthread_mutex_trylock(pthread_mutex_t *const mutex) { - return TryEnterCriticalSection(mutex) ? 0 : EBUSY; -} - -static INLINE int pthread_mutex_lock(pthread_mutex_t *const mutex) { - EnterCriticalSection(mutex); - return 0; -} - -static INLINE int pthread_mutex_unlock(pthread_mutex_t *const mutex) { - LeaveCriticalSection(mutex); - return 0; -} - -static INLINE int pthread_mutex_destroy(pthread_mutex_t *const mutex) { - DeleteCriticalSection(mutex); - return 0; -} - -// Condition -static INLINE int pthread_cond_destroy(pthread_cond_t *const condition) { - (void)condition; - return 0; -} - -static INLINE int pthread_cond_init(pthread_cond_t *const condition, - void *cond_attr) { - (void)cond_attr; - InitializeConditionVariable(condition); - return 0; -} - -static INLINE int pthread_cond_signal(pthread_cond_t *const condition) { - WakeConditionVariable(condition); - return 0; -} - -static INLINE int pthread_cond_broadcast(pthread_cond_t *const condition) { - WakeAllConditionVariable(condition); - return 0; -} - -static INLINE int pthread_cond_wait(pthread_cond_t *const condition, - pthread_mutex_t *const mutex) { - int ok; - ok = SleepConditionVariableCS(condition, mutex, INFINITE); - return !ok; -} -#else // _WIN32 -#include // NOLINT -#define THREADFN void * -#define THREAD_RETURN(val) val -#endif - -#endif // CONFIG_MULTITHREAD - // State of the worker thread object typedef enum { - NOT_OK = 0, // object is unusable - OK, // ready to work - WORK // busy finishing the current task + AVX_WORKER_STATUS_NOT_OK = 0, // object is unusable + AVX_WORKER_STATUS_OK, // ready to work + AVX_WORKER_STATUS_WORKING // busy finishing the current task } AVxWorkerStatus; // Function to be called by the worker thread. Takes two opaque pointers as diff --git a/third_party/aom/aom_util/aom_util.cmake b/third_party/aom/aom_util/aom_util.cmake index 6bf4fafc4c..d3da550485 100644 --- a/third_party/aom/aom_util/aom_util.cmake +++ b/third_party/aom/aom_util/aom_util.cmake @@ -13,7 +13,8 @@ if(AOM_AOM_UTIL_AOM_UTIL_CMAKE_) endif() # AOM_AOM_UTIL_AOM_UTIL_CMAKE_ set(AOM_AOM_UTIL_AOM_UTIL_CMAKE_ 1) -list(APPEND AOM_UTIL_SOURCES "${AOM_ROOT}/aom_util/aom_thread.c" +list(APPEND AOM_UTIL_SOURCES "${AOM_ROOT}/aom_util/aom_pthread.h" + "${AOM_ROOT}/aom_util/aom_thread.c" "${AOM_ROOT}/aom_util/aom_thread.h" "${AOM_ROOT}/aom_util/endian_inl.h") diff --git a/third_party/aom/apps/aomenc.c b/third_party/aom/apps/aomenc.c index 3c9c136eed..799fb3a4f8 100644 --- a/third_party/aom/apps/aomenc.c +++ b/third_party/aom/apps/aomenc.c @@ -442,12 +442,12 @@ const arg_def_t *av1_ctrl_args[] = { #endif &g_av1_codec_arg_defs.dv_cost_upd_freq, &g_av1_codec_arg_defs.partition_info_path, - &g_av1_codec_arg_defs.enable_rate_guide_deltaq, - &g_av1_codec_arg_defs.rate_distribution_info, &g_av1_codec_arg_defs.enable_directional_intra, &g_av1_codec_arg_defs.enable_tx_size_search, &g_av1_codec_arg_defs.loopfilter_control, &g_av1_codec_arg_defs.auto_intra_tools_off, + &g_av1_codec_arg_defs.enable_rate_guide_deltaq, + &g_av1_codec_arg_defs.rate_distribution_info, NULL, }; diff --git a/third_party/aom/av1/av1.cmake b/third_party/aom/av1/av1.cmake index c66a748d40..32645f6065 100644 --- a/third_party/aom/av1/av1.cmake +++ b/third_party/aom/av1/av1.cmake @@ -262,7 +262,6 @@ list(APPEND AOM_AV1_ENCODER_SOURCES list(APPEND AOM_AV1_COMMON_INTRIN_SSE2 "${AOM_ROOT}/av1/common/x86/av1_txfm_sse2.h" - "${AOM_ROOT}/av1/common/x86/cdef_block_sse2.c" "${AOM_ROOT}/av1/common/x86/cfl_sse2.c" "${AOM_ROOT}/av1/common/x86/convolve_2d_sse2.c" "${AOM_ROOT}/av1/common/x86/convolve_sse2.c" @@ -272,11 +271,14 @@ list(APPEND AOM_AV1_COMMON_INTRIN_SSE2 list(APPEND AOM_AV1_COMMON_INTRIN_SSSE3 "${AOM_ROOT}/av1/common/x86/av1_inv_txfm_ssse3.c" "${AOM_ROOT}/av1/common/x86/av1_inv_txfm_ssse3.h" - "${AOM_ROOT}/av1/common/x86/cdef_block_ssse3.c" "${AOM_ROOT}/av1/common/x86/cfl_ssse3.c" "${AOM_ROOT}/av1/common/x86/jnt_convolve_ssse3.c" "${AOM_ROOT}/av1/common/x86/resize_ssse3.c") +# Fallbacks to support Valgrind on 32-bit x86 +list(APPEND AOM_AV1_COMMON_INTRIN_SSSE3_X86 + "${AOM_ROOT}/av1/common/x86/cdef_block_ssse3.c") + list(APPEND AOM_AV1_COMMON_INTRIN_SSE4_1 "${AOM_ROOT}/av1/common/x86/av1_convolve_horiz_rs_sse4.c" "${AOM_ROOT}/av1/common/x86/av1_convolve_scale_sse4.c" @@ -372,7 +374,8 @@ list(APPEND AOM_AV1_ENCODER_INTRIN_NEON_DOTPROD "${AOM_ROOT}/av1/encoder/arm/neon/temporal_filter_neon_dotprod.c") list(APPEND AOM_AV1_ENCODER_INTRIN_SVE - "${AOM_ROOT}/av1/encoder/arm/neon/av1_error_sve.c") + "${AOM_ROOT}/av1/encoder/arm/neon/av1_error_sve.c" + "${AOM_ROOT}/av1/encoder/arm/neon/wedge_utils_sve.c") list(APPEND AOM_AV1_ENCODER_INTRIN_ARM_CRC32 "${AOM_ROOT}/av1/encoder/arm/crc32/hash_arm_crc32.c") @@ -477,6 +480,10 @@ if(CONFIG_AV1_HIGHBITDEPTH) "${AOM_ROOT}/av1/common/arm/highbd_warp_plane_neon.c" "${AOM_ROOT}/av1/common/arm/highbd_wiener_convolve_neon.c") + list(APPEND AOM_AV1_COMMON_INTRIN_SVE2 + "${AOM_ROOT}/av1/common/arm/highbd_compound_convolve_sve2.c" + "${AOM_ROOT}/av1/common/arm/highbd_convolve_sve2.c") + list(APPEND AOM_AV1_ENCODER_INTRIN_SSE2 "${AOM_ROOT}/av1/encoder/x86/highbd_block_error_intrin_sse2.c" "${AOM_ROOT}/av1/encoder/x86/highbd_temporal_filter_sse2.c") @@ -605,6 +612,10 @@ function(setup_av1_targets) require_compiler_flag_nomsvc("-mssse3" NO) add_intrinsics_object_library("-mssse3" "ssse3" "aom_av1_common" "AOM_AV1_COMMON_INTRIN_SSSE3") + if(AOM_ARCH_X86) + add_intrinsics_object_library("-mssse3" "ssse3_x86" "aom_av1_common" + "AOM_AV1_COMMON_INTRIN_SSSE3_X86") + endif() if(CONFIG_AV1_DECODER) if(AOM_AV1_DECODER_INTRIN_SSSE3) @@ -703,6 +714,11 @@ function(setup_av1_targets) endif() endif() + if(HAVE_SVE2) + add_intrinsics_object_library("${AOM_SVE2_FLAG}" "sve2" "aom_av1_common" + "AOM_AV1_COMMON_INTRIN_SVE2") + endif() + if(HAVE_VSX) if(AOM_AV1_COMMON_INTRIN_VSX) add_intrinsics_object_library("-mvsx -maltivec" "vsx" "aom_av1_common" diff --git a/third_party/aom/av1/av1_cx_iface.c b/third_party/aom/av1/av1_cx_iface.c index 9214feb4e6..2b6b1504e6 100644 --- a/third_party/aom/av1/av1_cx_iface.c +++ b/third_party/aom/av1/av1_cx_iface.c @@ -9,22 +9,28 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ #include +#include #include #include -#include "aom_mem/aom_mem.h" #include "config/aom_config.h" #include "config/aom_version.h" -#include "aom_ports/mem_ops.h" - +#include "aom/aomcx.h" #include "aom/aom_encoder.h" +#include "aom/aom_external_partition.h" +#include "aom/aom_image.h" #include "aom/internal/aom_codec_internal.h" - #include "aom_dsp/flow_estimation/flow_estimation.h" +#include "aom_mem/aom_mem.h" +#include "aom_scale/yv12config.h" +#include "aom_util/aom_pthread.h" #include "av1/av1_cx_iface.h" #include "av1/av1_iface_common.h" +#include "av1/common/av1_common_int.h" +#include "av1/common/enums.h" +#include "av1/common/scale.h" #include "av1/encoder/bitstream.h" #include "av1/encoder/encoder.h" #include "av1/encoder/encoder_alloc.h" @@ -32,6 +38,7 @@ #include "av1/encoder/ethread.h" #include "av1/encoder/external_partition.h" #include "av1/encoder/firstpass.h" +#include "av1/encoder/lookahead.h" #include "av1/encoder/rc_utils.h" #include "av1/arg_defs.h" @@ -1836,6 +1843,11 @@ static aom_codec_err_t ctrl_set_enable_qm(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; extra_cfg.enable_qm = CAST(AV1E_SET_ENABLE_QM, args); +#if !CONFIG_QUANT_MATRIX + if (extra_cfg.enable_qm) { + ERROR("QM can't be enabled with CONFIG_QUANT_MATRIX=0."); + } +#endif return update_extra_cfg(ctx, &extra_cfg); } static aom_codec_err_t ctrl_set_qm_y(aom_codec_alg_priv_t *ctx, va_list args) { @@ -3072,11 +3084,36 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, ctx->pts_offset = ptsvol; ctx->pts_offset_initialized = 1; } + if (ptsvol < ctx->pts_offset) { + aom_internal_error(&ppi->error, AOM_CODEC_INVALID_PARAM, + "pts is smaller than initial pts"); + } ptsvol -= ctx->pts_offset; + if (ptsvol > INT64_MAX / cpi_data.timestamp_ratio->num) { + aom_internal_error( + &ppi->error, AOM_CODEC_INVALID_PARAM, + "conversion of relative pts to ticks would overflow"); + } int64_t src_time_stamp = timebase_units_to_ticks(cpi_data.timestamp_ratio, ptsvol); +#if ULONG_MAX > INT64_MAX + if (duration > INT64_MAX) { + aom_internal_error(&ppi->error, AOM_CODEC_INVALID_PARAM, + "duration is too big"); + } +#endif + if (ptsvol > INT64_MAX - (int64_t)duration) { + aom_internal_error(&ppi->error, AOM_CODEC_INVALID_PARAM, + "relative pts + duration is too big"); + } + aom_codec_pts_t pts_end = ptsvol + (int64_t)duration; + if (pts_end > INT64_MAX / cpi_data.timestamp_ratio->num) { + aom_internal_error( + &ppi->error, AOM_CODEC_INVALID_PARAM, + "conversion of relative pts + duration to ticks would overflow"); + } int64_t src_end_time_stamp = - timebase_units_to_ticks(cpi_data.timestamp_ratio, ptsvol + duration); + timebase_units_to_ticks(cpi_data.timestamp_ratio, pts_end); YV12_BUFFER_CONFIG sd; res = image2yuvconfig(img, &sd); @@ -3110,7 +3147,7 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, subsampling_x, subsampling_y, use_highbitdepth, lag_in_frames, src_border_in_pixels, cpi->common.features.byte_alignment, ctx->num_lap_buffers, (cpi->oxcf.kf_cfg.key_freq_max == 0), - cpi->image_pyramid_levels); + cpi->alloc_pyramid); } if (!ppi->lookahead) aom_internal_error(&ppi->error, AOM_CODEC_MEM_ERROR, diff --git a/third_party/aom/av1/av1_dx_iface.c b/third_party/aom/av1/av1_dx_iface.c index 3d7e132ab8..1a2dea37b6 100644 --- a/third_party/aom/av1/av1_dx_iface.c +++ b/third_party/aom/av1/av1_dx_iface.c @@ -19,18 +19,23 @@ #include "aom/internal/aom_image_internal.h" #include "aom/aomdx.h" #include "aom/aom_decoder.h" +#include "aom/aom_image.h" #include "aom_dsp/bitreader_buffer.h" #include "aom_dsp/aom_dsp_common.h" +#include "aom_ports/mem.h" #include "aom_ports/mem_ops.h" +#include "aom_util/aom_pthread.h" #include "aom_util/aom_thread.h" #include "av1/common/alloccommon.h" +#include "av1/common/av1_common_int.h" #include "av1/common/frame_buffers.h" #include "av1/common/enums.h" #include "av1/common/obu_util.h" #include "av1/decoder/decoder.h" #include "av1/decoder/decodeframe.h" +#include "av1/decoder/dthread.h" #include "av1/decoder/grain_synthesis.h" #include "av1/decoder/obu.h" @@ -865,7 +870,9 @@ static aom_image_t *decoder_get_frame(aom_codec_alg_priv_t *ctx, if (pbi->ext_tile_debug && tiles->single_tile_decoding && pbi->dec_tile_row >= 0) { int tile_width, tile_height; - av1_get_uniform_tile_size(cm, &tile_width, &tile_height); + if (!av1_get_uniform_tile_size(cm, &tile_width, &tile_height)) { + return NULL; + } const int tile_row = AOMMIN(pbi->dec_tile_row, tiles->rows - 1); const int mi_row = tile_row * tile_height; const int ssy = ctx->img.y_chroma_shift; @@ -884,7 +891,9 @@ static aom_image_t *decoder_get_frame(aom_codec_alg_priv_t *ctx, if (pbi->ext_tile_debug && tiles->single_tile_decoding && pbi->dec_tile_col >= 0) { int tile_width, tile_height; - av1_get_uniform_tile_size(cm, &tile_width, &tile_height); + if (!av1_get_uniform_tile_size(cm, &tile_width, &tile_height)) { + return NULL; + } const int tile_col = AOMMIN(pbi->dec_tile_col, tiles->cols - 1); const int mi_col = tile_col * tile_width; const int ssx = ctx->img.x_chroma_shift; @@ -1428,7 +1437,9 @@ static aom_codec_err_t ctrl_get_tile_size(aom_codec_alg_priv_t *ctx, (FrameWorkerData *)worker->data1; const AV1_COMMON *const cm = &frame_worker_data->pbi->common; int tile_width, tile_height; - av1_get_uniform_tile_size(cm, &tile_width, &tile_height); + if (!av1_get_uniform_tile_size(cm, &tile_width, &tile_height)) { + return AOM_CODEC_CORRUPT_FRAME; + } *tile_size = ((tile_width * MI_SIZE) << 16) + tile_height * MI_SIZE; return AOM_CODEC_OK; } else { diff --git a/third_party/aom/av1/common/alloccommon.c b/third_party/aom/av1/common/alloccommon.c index 2a9a8beb40..e9a38c4a60 100644 --- a/third_party/aom/av1/common/alloccommon.c +++ b/third_party/aom/av1/common/alloccommon.c @@ -13,6 +13,8 @@ #include "config/aom_config.h" #include "aom_mem/aom_mem.h" +#include "aom_scale/yv12config.h" +#include "aom_util/aom_pthread.h" #include "av1/common/alloccommon.h" #include "av1/common/av1_common_int.h" @@ -20,6 +22,8 @@ #include "av1/common/cdef_block.h" #include "av1/common/entropymode.h" #include "av1/common/entropymv.h" +#include "av1/common/enums.h" +#include "av1/common/restoration.h" #include "av1/common/thread_common.h" int av1_get_MBs(int width, int height) { @@ -200,7 +204,7 @@ void av1_alloc_cdef_buffers(AV1_COMMON *const cm, const int is_num_workers_changed = cdef_info->allocated_num_workers != num_workers; const int is_cdef_enabled = - cm->seq_params->enable_cdef && !cm->tiles.large_scale; + cm->seq_params->enable_cdef && !cm->tiles.single_tile_decoding; // num-bufs=3 represents ping-pong buffers for top linebuf, // followed by bottom linebuf. diff --git a/third_party/aom/av1/common/arm/highbd_compound_convolve_neon.c b/third_party/aom/av1/common/arm/highbd_compound_convolve_neon.c index fc03a2ee04..9247ded6bf 100644 --- a/third_party/aom/av1/common/arm/highbd_compound_convolve_neon.c +++ b/third_party/aom/av1/common/arm/highbd_compound_convolve_neon.c @@ -20,266 +20,9 @@ #include "aom_ports/mem.h" #include "av1/common/convolve.h" #include "av1/common/filter.h" +#include "av1/common/arm/highbd_compound_convolve_neon.h" #include "av1/common/arm/highbd_convolve_neon.h" -#define ROUND_SHIFT 2 * FILTER_BITS - ROUND0_BITS - COMPOUND_ROUND1_BITS - -static INLINE void highbd_12_comp_avg_neon(const uint16_t *src_ptr, - int src_stride, uint16_t *dst_ptr, - int dst_stride, int w, int h, - ConvolveParams *conv_params, - const int offset, const int bd) { - CONV_BUF_TYPE *ref_ptr = conv_params->dst; - const int ref_stride = conv_params->dst_stride; - const uint16x4_t offset_vec = vdup_n_u16(offset); - const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); - - if (w == 4) { - do { - const uint16x4_t src = vld1_u16(src_ptr); - const uint16x4_t ref = vld1_u16(ref_ptr); - - uint16x4_t avg = vhadd_u16(src, ref); - int32x4_t d0 = vreinterpretq_s32_u32(vsubl_u16(avg, offset_vec)); - - uint16x4_t d0_u16 = vqrshrun_n_s32(d0, ROUND_SHIFT - 2); - d0_u16 = vmin_u16(d0_u16, vget_low_u16(max)); - - vst1_u16(dst_ptr, d0_u16); - - src_ptr += src_stride; - ref_ptr += ref_stride; - dst_ptr += dst_stride; - } while (--h != 0); - } else { - do { - int width = w; - const uint16_t *src = src_ptr; - const uint16_t *ref = ref_ptr; - uint16_t *dst = dst_ptr; - do { - const uint16x8_t s = vld1q_u16(src); - const uint16x8_t r = vld1q_u16(ref); - - uint16x8_t avg = vhaddq_u16(s, r); - int32x4_t d0_lo = - vreinterpretq_s32_u32(vsubl_u16(vget_low_u16(avg), offset_vec)); - int32x4_t d0_hi = - vreinterpretq_s32_u32(vsubl_u16(vget_high_u16(avg), offset_vec)); - - uint16x8_t d0 = vcombine_u16(vqrshrun_n_s32(d0_lo, ROUND_SHIFT - 2), - vqrshrun_n_s32(d0_hi, ROUND_SHIFT - 2)); - d0 = vminq_u16(d0, max); - vst1q_u16(dst, d0); - - src += 8; - ref += 8; - dst += 8; - width -= 8; - } while (width != 0); - - src_ptr += src_stride; - ref_ptr += ref_stride; - dst_ptr += dst_stride; - } while (--h != 0); - } -} - -static INLINE void highbd_comp_avg_neon(const uint16_t *src_ptr, int src_stride, - uint16_t *dst_ptr, int dst_stride, - int w, int h, - ConvolveParams *conv_params, - const int offset, const int bd) { - CONV_BUF_TYPE *ref_ptr = conv_params->dst; - const int ref_stride = conv_params->dst_stride; - const uint16x4_t offset_vec = vdup_n_u16(offset); - const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); - - if (w == 4) { - do { - const uint16x4_t src = vld1_u16(src_ptr); - const uint16x4_t ref = vld1_u16(ref_ptr); - - uint16x4_t avg = vhadd_u16(src, ref); - int32x4_t d0 = vreinterpretq_s32_u32(vsubl_u16(avg, offset_vec)); - - uint16x4_t d0_u16 = vqrshrun_n_s32(d0, ROUND_SHIFT); - d0_u16 = vmin_u16(d0_u16, vget_low_u16(max)); - - vst1_u16(dst_ptr, d0_u16); - - src_ptr += src_stride; - ref_ptr += ref_stride; - dst_ptr += dst_stride; - } while (--h != 0); - } else { - do { - int width = w; - const uint16_t *src = src_ptr; - const uint16_t *ref = ref_ptr; - uint16_t *dst = dst_ptr; - do { - const uint16x8_t s = vld1q_u16(src); - const uint16x8_t r = vld1q_u16(ref); - - uint16x8_t avg = vhaddq_u16(s, r); - int32x4_t d0_lo = - vreinterpretq_s32_u32(vsubl_u16(vget_low_u16(avg), offset_vec)); - int32x4_t d0_hi = - vreinterpretq_s32_u32(vsubl_u16(vget_high_u16(avg), offset_vec)); - - uint16x8_t d0 = vcombine_u16(vqrshrun_n_s32(d0_lo, ROUND_SHIFT), - vqrshrun_n_s32(d0_hi, ROUND_SHIFT)); - d0 = vminq_u16(d0, max); - vst1q_u16(dst, d0); - - src += 8; - ref += 8; - dst += 8; - width -= 8; - } while (width != 0); - - src_ptr += src_stride; - ref_ptr += ref_stride; - dst_ptr += dst_stride; - } while (--h != 0); - } -} - -static INLINE void highbd_12_dist_wtd_comp_avg_neon( - const uint16_t *src_ptr, int src_stride, uint16_t *dst_ptr, int dst_stride, - int w, int h, ConvolveParams *conv_params, const int offset, const int bd) { - CONV_BUF_TYPE *ref_ptr = conv_params->dst; - const int ref_stride = conv_params->dst_stride; - const uint32x4_t offset_vec = vdupq_n_u32(offset); - const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); - uint16x4_t fwd_offset = vdup_n_u16(conv_params->fwd_offset); - uint16x4_t bck_offset = vdup_n_u16(conv_params->bck_offset); - - // Weighted averaging - if (w == 4) { - do { - const uint16x4_t src = vld1_u16(src_ptr); - const uint16x4_t ref = vld1_u16(ref_ptr); - - uint32x4_t wtd_avg = vmull_u16(ref, fwd_offset); - wtd_avg = vmlal_u16(wtd_avg, src, bck_offset); - wtd_avg = vshrq_n_u32(wtd_avg, DIST_PRECISION_BITS); - int32x4_t d0 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg, offset_vec)); - - uint16x4_t d0_u16 = vqrshrun_n_s32(d0, ROUND_SHIFT - 2); - d0_u16 = vmin_u16(d0_u16, vget_low_u16(max)); - - vst1_u16(dst_ptr, d0_u16); - - src_ptr += src_stride; - dst_ptr += dst_stride; - ref_ptr += ref_stride; - } while (--h != 0); - } else { - do { - int width = w; - const uint16_t *src = src_ptr; - const uint16_t *ref = ref_ptr; - uint16_t *dst = dst_ptr; - do { - const uint16x8_t s = vld1q_u16(src); - const uint16x8_t r = vld1q_u16(ref); - - uint32x4_t wtd_avg0 = vmull_u16(vget_low_u16(r), fwd_offset); - wtd_avg0 = vmlal_u16(wtd_avg0, vget_low_u16(s), bck_offset); - wtd_avg0 = vshrq_n_u32(wtd_avg0, DIST_PRECISION_BITS); - int32x4_t d0 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg0, offset_vec)); - - uint32x4_t wtd_avg1 = vmull_u16(vget_high_u16(r), fwd_offset); - wtd_avg1 = vmlal_u16(wtd_avg1, vget_high_u16(s), bck_offset); - wtd_avg1 = vshrq_n_u32(wtd_avg1, DIST_PRECISION_BITS); - int32x4_t d1 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg1, offset_vec)); - - uint16x8_t d01 = vcombine_u16(vqrshrun_n_s32(d0, ROUND_SHIFT - 2), - vqrshrun_n_s32(d1, ROUND_SHIFT - 2)); - d01 = vminq_u16(d01, max); - vst1q_u16(dst, d01); - - src += 8; - ref += 8; - dst += 8; - width -= 8; - } while (width != 0); - src_ptr += src_stride; - dst_ptr += dst_stride; - ref_ptr += ref_stride; - } while (--h != 0); - } -} - -static INLINE void highbd_dist_wtd_comp_avg_neon( - const uint16_t *src_ptr, int src_stride, uint16_t *dst_ptr, int dst_stride, - int w, int h, ConvolveParams *conv_params, const int offset, const int bd) { - CONV_BUF_TYPE *ref_ptr = conv_params->dst; - const int ref_stride = conv_params->dst_stride; - const uint32x4_t offset_vec = vdupq_n_u32(offset); - const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); - uint16x4_t fwd_offset = vdup_n_u16(conv_params->fwd_offset); - uint16x4_t bck_offset = vdup_n_u16(conv_params->bck_offset); - - // Weighted averaging - if (w == 4) { - do { - const uint16x4_t src = vld1_u16(src_ptr); - const uint16x4_t ref = vld1_u16(ref_ptr); - - uint32x4_t wtd_avg = vmull_u16(ref, fwd_offset); - wtd_avg = vmlal_u16(wtd_avg, src, bck_offset); - wtd_avg = vshrq_n_u32(wtd_avg, DIST_PRECISION_BITS); - int32x4_t d0 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg, offset_vec)); - - uint16x4_t d0_u16 = vqrshrun_n_s32(d0, ROUND_SHIFT); - d0_u16 = vmin_u16(d0_u16, vget_low_u16(max)); - - vst1_u16(dst_ptr, d0_u16); - - src_ptr += src_stride; - dst_ptr += dst_stride; - ref_ptr += ref_stride; - } while (--h != 0); - } else { - do { - int width = w; - const uint16_t *src = src_ptr; - const uint16_t *ref = ref_ptr; - uint16_t *dst = dst_ptr; - do { - const uint16x8_t s = vld1q_u16(src); - const uint16x8_t r = vld1q_u16(ref); - - uint32x4_t wtd_avg0 = vmull_u16(vget_low_u16(r), fwd_offset); - wtd_avg0 = vmlal_u16(wtd_avg0, vget_low_u16(s), bck_offset); - wtd_avg0 = vshrq_n_u32(wtd_avg0, DIST_PRECISION_BITS); - int32x4_t d0 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg0, offset_vec)); - - uint32x4_t wtd_avg1 = vmull_u16(vget_high_u16(r), fwd_offset); - wtd_avg1 = vmlal_u16(wtd_avg1, vget_high_u16(s), bck_offset); - wtd_avg1 = vshrq_n_u32(wtd_avg1, DIST_PRECISION_BITS); - int32x4_t d1 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg1, offset_vec)); - - uint16x8_t d01 = vcombine_u16(vqrshrun_n_s32(d0, ROUND_SHIFT), - vqrshrun_n_s32(d1, ROUND_SHIFT)); - d01 = vminq_u16(d01, max); - vst1q_u16(dst, d01); - - src += 8; - ref += 8; - dst += 8; - width -= 8; - } while (width != 0); - src_ptr += src_stride; - dst_ptr += dst_stride; - ref_ptr += ref_stride; - } while (--h != 0); - } -} - static INLINE uint16x4_t highbd_12_convolve6_4( const int16x4_t s0, const int16x4_t s1, const int16x4_t s2, const int16x4_t s3, const int16x4_t s4, const int16x4_t s5, @@ -743,9 +486,6 @@ void av1_highbd_dist_wtd_convolve_x_neon( const int im_stride = MAX_SB_SIZE; const int horiz_offset = filter_params_x->taps / 2 - 1; assert(FILTER_BITS == COMPOUND_ROUND1_BITS); - const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; - const int offset_avg = (1 << (offset_bits - conv_params->round_1)) + - (1 << (offset_bits - conv_params->round_1 - 1)); const int offset_convolve = (1 << (conv_params->round_0 - 1)) + (1 << (bd + FILTER_BITS)) + (1 << (bd + FILTER_BITS - 1)); @@ -768,10 +508,10 @@ void av1_highbd_dist_wtd_convolve_x_neon( } if (conv_params->use_dist_wtd_comp_avg) { highbd_12_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, - w, h, conv_params, offset_avg, bd); + w, h, conv_params); } else { highbd_12_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, - conv_params, offset_avg, bd); + conv_params); } } else { if (x_filter_taps <= 6 && w != 4) { @@ -795,10 +535,10 @@ void av1_highbd_dist_wtd_convolve_x_neon( } if (conv_params->use_dist_wtd_comp_avg) { highbd_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, - h, conv_params, offset_avg, bd); + h, conv_params, bd); } else { highbd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, - conv_params, offset_avg, bd); + conv_params, bd); } } else { if (x_filter_taps <= 6 && w != 4) { @@ -971,6 +711,212 @@ static INLINE void highbd_dist_wtd_convolve_y_6tap_neon( } } +static INLINE uint16x4_t highbd_12_convolve4_4( + const int16x4_t s0, const int16x4_t s1, const int16x4_t s2, + const int16x4_t s3, const int16x4_t filter, const int32x4_t offset) { + int32x4_t sum = vmlal_lane_s16(offset, s0, filter, 0); + sum = vmlal_lane_s16(sum, s1, filter, 1); + sum = vmlal_lane_s16(sum, s2, filter, 2); + sum = vmlal_lane_s16(sum, s3, filter, 3); + + return vqshrun_n_s32(sum, ROUND0_BITS + 2); +} + +static INLINE uint16x8_t highbd_12_convolve4_8( + const int16x8_t s0, const int16x8_t s1, const int16x8_t s2, + const int16x8_t s3, const int16x4_t filter, const int32x4_t offset) { + int32x4_t sum0 = vmlal_lane_s16(offset, vget_low_s16(s0), filter, 0); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s1), filter, 1); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s2), filter, 2); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s3), filter, 3); + + int32x4_t sum1 = vmlal_lane_s16(offset, vget_high_s16(s0), filter, 0); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s1), filter, 1); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s2), filter, 2); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s3), filter, 3); + + return vcombine_u16(vqshrun_n_s32(sum0, ROUND0_BITS + 2), + vqshrun_n_s32(sum1, ROUND0_BITS + 2)); +} + +static INLINE void highbd_12_dist_wtd_convolve_y_4tap_neon( + const uint16_t *src_ptr, int src_stride, uint16_t *dst_ptr, int dst_stride, + int w, int h, const int16_t *y_filter_ptr, const int offset) { + const int16x4_t y_filter = vld1_s16(y_filter_ptr + 2); + const int32x4_t offset_vec = vdupq_n_s32(offset); + + if (w == 4) { + const int16_t *s = (const int16_t *)src_ptr; + uint16_t *d = dst_ptr; + + int16x4_t s0, s1, s2; + load_s16_4x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x4_t s3, s4, s5, s6; + load_s16_4x4(s, src_stride, &s3, &s4, &s5, &s6); + + uint16x4_t d0 = + highbd_12_convolve4_4(s0, s1, s2, s3, y_filter, offset_vec); + uint16x4_t d1 = + highbd_12_convolve4_4(s1, s2, s3, s4, y_filter, offset_vec); + uint16x4_t d2 = + highbd_12_convolve4_4(s2, s3, s4, s5, y_filter, offset_vec); + uint16x4_t d3 = + highbd_12_convolve4_4(s3, s4, s5, s6, y_filter, offset_vec); + + store_u16_4x4(d, dst_stride, d0, d1, d2, d3); + + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + } else { + do { + int height = h; + const int16_t *s = (const int16_t *)src_ptr; + uint16_t *d = dst_ptr; + + int16x8_t s0, s1, s2; + load_s16_8x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x8_t s3, s4, s5, s6; + load_s16_8x4(s, src_stride, &s3, &s4, &s5, &s6); + + uint16x8_t d0 = + highbd_12_convolve4_8(s0, s1, s2, s3, y_filter, offset_vec); + uint16x8_t d1 = + highbd_12_convolve4_8(s1, s2, s3, s4, y_filter, offset_vec); + uint16x8_t d2 = + highbd_12_convolve4_8(s2, s3, s4, s5, y_filter, offset_vec); + uint16x8_t d3 = + highbd_12_convolve4_8(s3, s4, s5, s6, y_filter, offset_vec); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + height -= 4; + } while (height != 0); + src_ptr += 8; + dst_ptr += 8; + w -= 8; + } while (w != 0); + } +} + +static INLINE uint16x4_t highbd_convolve4_4( + const int16x4_t s0, const int16x4_t s1, const int16x4_t s2, + const int16x4_t s3, const int16x4_t filter, const int32x4_t offset) { + int32x4_t sum = vmlal_lane_s16(offset, s0, filter, 0); + sum = vmlal_lane_s16(sum, s1, filter, 1); + sum = vmlal_lane_s16(sum, s2, filter, 2); + sum = vmlal_lane_s16(sum, s3, filter, 3); + + return vqshrun_n_s32(sum, ROUND0_BITS); +} + +static INLINE uint16x8_t highbd_convolve4_8( + const int16x8_t s0, const int16x8_t s1, const int16x8_t s2, + const int16x8_t s3, const int16x4_t filter, const int32x4_t offset) { + int32x4_t sum0 = vmlal_lane_s16(offset, vget_low_s16(s0), filter, 0); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s1), filter, 1); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s2), filter, 2); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s3), filter, 3); + + int32x4_t sum1 = vmlal_lane_s16(offset, vget_high_s16(s0), filter, 0); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s1), filter, 1); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s2), filter, 2); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s3), filter, 3); + + return vcombine_u16(vqshrun_n_s32(sum0, ROUND0_BITS), + vqshrun_n_s32(sum1, ROUND0_BITS)); +} + +static INLINE void highbd_dist_wtd_convolve_y_4tap_neon( + const uint16_t *src_ptr, int src_stride, uint16_t *dst_ptr, int dst_stride, + int w, int h, const int16_t *y_filter_ptr, const int offset) { + const int16x4_t y_filter = vld1_s16(y_filter_ptr + 2); + const int32x4_t offset_vec = vdupq_n_s32(offset); + + if (w == 4) { + const int16_t *s = (const int16_t *)src_ptr; + uint16_t *d = dst_ptr; + + int16x4_t s0, s1, s2; + load_s16_4x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x4_t s3, s4, s5, s6; + load_s16_4x4(s, src_stride, &s3, &s4, &s5, &s6); + + uint16x4_t d0 = highbd_convolve4_4(s0, s1, s2, s3, y_filter, offset_vec); + uint16x4_t d1 = highbd_convolve4_4(s1, s2, s3, s4, y_filter, offset_vec); + uint16x4_t d2 = highbd_convolve4_4(s2, s3, s4, s5, y_filter, offset_vec); + uint16x4_t d3 = highbd_convolve4_4(s3, s4, s5, s6, y_filter, offset_vec); + + store_u16_4x4(d, dst_stride, d0, d1, d2, d3); + + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + } else { + do { + int height = h; + const int16_t *s = (const int16_t *)src_ptr; + uint16_t *d = dst_ptr; + + int16x8_t s0, s1, s2; + load_s16_8x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x8_t s3, s4, s5, s6; + load_s16_8x4(s, src_stride, &s3, &s4, &s5, &s6); + + uint16x8_t d0 = + highbd_convolve4_8(s0, s1, s2, s3, y_filter, offset_vec); + uint16x8_t d1 = + highbd_convolve4_8(s1, s2, s3, s4, y_filter, offset_vec); + uint16x8_t d2 = + highbd_convolve4_8(s2, s3, s4, s5, y_filter, offset_vec); + uint16x8_t d3 = + highbd_convolve4_8(s3, s4, s5, s6, y_filter, offset_vec); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + height -= 4; + } while (height != 0); + src_ptr += 8; + dst_ptr += 8; + w -= 8; + } while (w != 0); + } +} + static INLINE void highbd_12_dist_wtd_convolve_y_8tap_neon( const uint16_t *src_ptr, int src_stride, uint16_t *dst_ptr, int dst_stride, int w, int h, const int16_t *y_filter_ptr, const int offset) { @@ -1148,9 +1094,6 @@ void av1_highbd_dist_wtd_convolve_y_neon( const int im_stride = MAX_SB_SIZE; const int vert_offset = filter_params_y->taps / 2 - 1; assert(FILTER_BITS == COMPOUND_ROUND1_BITS); - const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; - const int round_offset_avg = (1 << (offset_bits - conv_params->round_1)) + - (1 << (offset_bits - conv_params->round_1 - 1)); const int round_offset_conv = (1 << (conv_params->round_0 - 1)) + (1 << (bd + FILTER_BITS)) + (1 << (bd + FILTER_BITS - 1)); @@ -1162,7 +1105,11 @@ void av1_highbd_dist_wtd_convolve_y_neon( if (bd == 12) { if (conv_params->do_average) { - if (y_filter_taps <= 6) { + if (y_filter_taps <= 4) { + highbd_12_dist_wtd_convolve_y_4tap_neon( + src + 2 * src_stride, src_stride, im_block, im_stride, w, h, + y_filter_ptr, round_offset_conv); + } else if (y_filter_taps == 6) { highbd_12_dist_wtd_convolve_y_6tap_neon( src + src_stride, src_stride, im_block, im_stride, w, h, y_filter_ptr, round_offset_conv); @@ -1173,14 +1120,17 @@ void av1_highbd_dist_wtd_convolve_y_neon( } if (conv_params->use_dist_wtd_comp_avg) { highbd_12_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, - w, h, conv_params, round_offset_avg, - bd); + w, h, conv_params); } else { highbd_12_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, - conv_params, round_offset_avg, bd); + conv_params); } } else { - if (y_filter_taps <= 6) { + if (y_filter_taps <= 4) { + highbd_12_dist_wtd_convolve_y_4tap_neon( + src + 2 * src_stride, src_stride, dst16, dst16_stride, w, h, + y_filter_ptr, round_offset_conv); + } else if (y_filter_taps == 6) { highbd_12_dist_wtd_convolve_y_6tap_neon( src + src_stride, src_stride, dst16, dst16_stride, w, h, y_filter_ptr, round_offset_conv); @@ -1192,7 +1142,11 @@ void av1_highbd_dist_wtd_convolve_y_neon( } } else { if (conv_params->do_average) { - if (y_filter_taps <= 6) { + if (y_filter_taps <= 4) { + highbd_dist_wtd_convolve_y_4tap_neon(src + 2 * src_stride, src_stride, + im_block, im_stride, w, h, + y_filter_ptr, round_offset_conv); + } else if (y_filter_taps == 6) { highbd_dist_wtd_convolve_y_6tap_neon(src + src_stride, src_stride, im_block, im_stride, w, h, y_filter_ptr, round_offset_conv); @@ -1203,13 +1157,17 @@ void av1_highbd_dist_wtd_convolve_y_neon( } if (conv_params->use_dist_wtd_comp_avg) { highbd_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, - h, conv_params, round_offset_avg, bd); + h, conv_params, bd); } else { highbd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, - conv_params, round_offset_avg, bd); + conv_params, bd); } } else { - if (y_filter_taps <= 6) { + if (y_filter_taps <= 4) { + highbd_dist_wtd_convolve_y_4tap_neon(src + 2 * src_stride, src_stride, + dst16, dst16_stride, w, h, + y_filter_ptr, round_offset_conv); + } else if (y_filter_taps == 6) { highbd_dist_wtd_convolve_y_6tap_neon(src + src_stride, src_stride, dst16, dst16_stride, w, h, y_filter_ptr, round_offset_conv); @@ -1285,18 +1243,18 @@ void av1_highbd_dist_wtd_convolve_2d_copy_neon(const uint16_t *src, if (conv_params->use_dist_wtd_comp_avg) { if (bd == 12) { highbd_12_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, - w, h, conv_params, round_offset, bd); + w, h, conv_params); } else { highbd_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, - h, conv_params, round_offset, bd); + h, conv_params, bd); } } else { if (bd == 12) { highbd_12_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, - conv_params, round_offset, bd); + conv_params); } else { highbd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, - conv_params, round_offset, bd); + conv_params, bd); } } } @@ -1949,9 +1907,6 @@ void av1_highbd_dist_wtd_convolve_2d_neon( (1 << (bd + FILTER_BITS - 1)) + (1 << (conv_params->round_0 - 1)); const int y_offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; const int round_offset_conv_y = (1 << y_offset_bits); - const int round_offset_avg = - ((1 << (y_offset_bits - conv_params->round_1)) + - (1 << (y_offset_bits - conv_params->round_1 - 1))); const uint16_t *src_ptr = src - vert_offset * src_stride - horiz_offset; @@ -2012,19 +1967,18 @@ void av1_highbd_dist_wtd_convolve_2d_neon( if (conv_params->use_dist_wtd_comp_avg) { if (bd == 12) { highbd_12_dist_wtd_comp_avg_neon(im_block2, im_stride, dst, dst_stride, - w, h, conv_params, round_offset_avg, - bd); + w, h, conv_params); } else { highbd_dist_wtd_comp_avg_neon(im_block2, im_stride, dst, dst_stride, w, - h, conv_params, round_offset_avg, bd); + h, conv_params, bd); } } else { if (bd == 12) { highbd_12_comp_avg_neon(im_block2, im_stride, dst, dst_stride, w, h, - conv_params, round_offset_avg, bd); + conv_params); } else { highbd_comp_avg_neon(im_block2, im_stride, dst, dst_stride, w, h, - conv_params, round_offset_avg, bd); + conv_params, bd); } } } diff --git a/third_party/aom/av1/common/arm/highbd_compound_convolve_neon.h b/third_party/aom/av1/common/arm/highbd_compound_convolve_neon.h new file mode 100644 index 0000000000..c9344f3adf --- /dev/null +++ b/third_party/aom/av1/common/arm/highbd_compound_convolve_neon.h @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include +#include + +#include "config/aom_config.h" +#include "config/av1_rtcd.h" + +#include "aom_dsp/aom_dsp_common.h" +#include "aom_dsp/arm/mem_neon.h" +#include "aom_ports/mem.h" + +#define ROUND_SHIFT 2 * FILTER_BITS - ROUND0_BITS - COMPOUND_ROUND1_BITS + +static INLINE void highbd_12_comp_avg_neon(const uint16_t *src_ptr, + int src_stride, uint16_t *dst_ptr, + int dst_stride, int w, int h, + ConvolveParams *conv_params) { + const int offset_bits = 12 + 2 * FILTER_BITS - ROUND0_BITS - 2; + const int offset = (1 << (offset_bits - COMPOUND_ROUND1_BITS)) + + (1 << (offset_bits - COMPOUND_ROUND1_BITS - 1)); + + CONV_BUF_TYPE *ref_ptr = conv_params->dst; + const int ref_stride = conv_params->dst_stride; + const uint16x4_t offset_vec = vdup_n_u16((uint16_t)offset); + const uint16x8_t max = vdupq_n_u16((1 << 12) - 1); + + if (w == 4) { + do { + const uint16x4_t src = vld1_u16(src_ptr); + const uint16x4_t ref = vld1_u16(ref_ptr); + + uint16x4_t avg = vhadd_u16(src, ref); + int32x4_t d0 = vreinterpretq_s32_u32(vsubl_u16(avg, offset_vec)); + + uint16x4_t d0_u16 = vqrshrun_n_s32(d0, ROUND_SHIFT - 2); + d0_u16 = vmin_u16(d0_u16, vget_low_u16(max)); + + vst1_u16(dst_ptr, d0_u16); + + src_ptr += src_stride; + ref_ptr += ref_stride; + dst_ptr += dst_stride; + } while (--h != 0); + } else { + do { + int width = w; + const uint16_t *src = src_ptr; + const uint16_t *ref = ref_ptr; + uint16_t *dst = dst_ptr; + do { + const uint16x8_t s = vld1q_u16(src); + const uint16x8_t r = vld1q_u16(ref); + + uint16x8_t avg = vhaddq_u16(s, r); + int32x4_t d0_lo = + vreinterpretq_s32_u32(vsubl_u16(vget_low_u16(avg), offset_vec)); + int32x4_t d0_hi = + vreinterpretq_s32_u32(vsubl_u16(vget_high_u16(avg), offset_vec)); + + uint16x8_t d0 = vcombine_u16(vqrshrun_n_s32(d0_lo, ROUND_SHIFT - 2), + vqrshrun_n_s32(d0_hi, ROUND_SHIFT - 2)); + d0 = vminq_u16(d0, max); + vst1q_u16(dst, d0); + + src += 8; + ref += 8; + dst += 8; + width -= 8; + } while (width != 0); + + src_ptr += src_stride; + ref_ptr += ref_stride; + dst_ptr += dst_stride; + } while (--h != 0); + } +} + +static INLINE void highbd_comp_avg_neon(const uint16_t *src_ptr, int src_stride, + uint16_t *dst_ptr, int dst_stride, + int w, int h, + ConvolveParams *conv_params, + const int bd) { + const int offset_bits = bd + 2 * FILTER_BITS - ROUND0_BITS; + const int offset = (1 << (offset_bits - COMPOUND_ROUND1_BITS)) + + (1 << (offset_bits - COMPOUND_ROUND1_BITS - 1)); + + CONV_BUF_TYPE *ref_ptr = conv_params->dst; + const int ref_stride = conv_params->dst_stride; + const uint16x4_t offset_vec = vdup_n_u16((uint16_t)offset); + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + + if (w == 4) { + do { + const uint16x4_t src = vld1_u16(src_ptr); + const uint16x4_t ref = vld1_u16(ref_ptr); + + uint16x4_t avg = vhadd_u16(src, ref); + int32x4_t d0 = vreinterpretq_s32_u32(vsubl_u16(avg, offset_vec)); + + uint16x4_t d0_u16 = vqrshrun_n_s32(d0, ROUND_SHIFT); + d0_u16 = vmin_u16(d0_u16, vget_low_u16(max)); + + vst1_u16(dst_ptr, d0_u16); + + src_ptr += src_stride; + ref_ptr += ref_stride; + dst_ptr += dst_stride; + } while (--h != 0); + } else { + do { + int width = w; + const uint16_t *src = src_ptr; + const uint16_t *ref = ref_ptr; + uint16_t *dst = dst_ptr; + do { + const uint16x8_t s = vld1q_u16(src); + const uint16x8_t r = vld1q_u16(ref); + + uint16x8_t avg = vhaddq_u16(s, r); + int32x4_t d0_lo = + vreinterpretq_s32_u32(vsubl_u16(vget_low_u16(avg), offset_vec)); + int32x4_t d0_hi = + vreinterpretq_s32_u32(vsubl_u16(vget_high_u16(avg), offset_vec)); + + uint16x8_t d0 = vcombine_u16(vqrshrun_n_s32(d0_lo, ROUND_SHIFT), + vqrshrun_n_s32(d0_hi, ROUND_SHIFT)); + d0 = vminq_u16(d0, max); + vst1q_u16(dst, d0); + + src += 8; + ref += 8; + dst += 8; + width -= 8; + } while (width != 0); + + src_ptr += src_stride; + ref_ptr += ref_stride; + dst_ptr += dst_stride; + } while (--h != 0); + } +} + +static INLINE void highbd_12_dist_wtd_comp_avg_neon( + const uint16_t *src_ptr, int src_stride, uint16_t *dst_ptr, int dst_stride, + int w, int h, ConvolveParams *conv_params) { + const int offset_bits = 12 + 2 * FILTER_BITS - ROUND0_BITS - 2; + const int offset = (1 << (offset_bits - COMPOUND_ROUND1_BITS)) + + (1 << (offset_bits - COMPOUND_ROUND1_BITS - 1)); + + CONV_BUF_TYPE *ref_ptr = conv_params->dst; + const int ref_stride = conv_params->dst_stride; + const uint32x4_t offset_vec = vdupq_n_u32(offset); + const uint16x8_t max = vdupq_n_u16((1 << 12) - 1); + uint16x4_t fwd_offset = vdup_n_u16(conv_params->fwd_offset); + uint16x4_t bck_offset = vdup_n_u16(conv_params->bck_offset); + + // Weighted averaging + if (w == 4) { + do { + const uint16x4_t src = vld1_u16(src_ptr); + const uint16x4_t ref = vld1_u16(ref_ptr); + + uint32x4_t wtd_avg = vmull_u16(ref, fwd_offset); + wtd_avg = vmlal_u16(wtd_avg, src, bck_offset); + wtd_avg = vshrq_n_u32(wtd_avg, DIST_PRECISION_BITS); + int32x4_t d0 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg, offset_vec)); + + uint16x4_t d0_u16 = vqrshrun_n_s32(d0, ROUND_SHIFT - 2); + d0_u16 = vmin_u16(d0_u16, vget_low_u16(max)); + + vst1_u16(dst_ptr, d0_u16); + + src_ptr += src_stride; + dst_ptr += dst_stride; + ref_ptr += ref_stride; + } while (--h != 0); + } else { + do { + int width = w; + const uint16_t *src = src_ptr; + const uint16_t *ref = ref_ptr; + uint16_t *dst = dst_ptr; + do { + const uint16x8_t s = vld1q_u16(src); + const uint16x8_t r = vld1q_u16(ref); + + uint32x4_t wtd_avg0 = vmull_u16(vget_low_u16(r), fwd_offset); + wtd_avg0 = vmlal_u16(wtd_avg0, vget_low_u16(s), bck_offset); + wtd_avg0 = vshrq_n_u32(wtd_avg0, DIST_PRECISION_BITS); + int32x4_t d0 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg0, offset_vec)); + + uint32x4_t wtd_avg1 = vmull_u16(vget_high_u16(r), fwd_offset); + wtd_avg1 = vmlal_u16(wtd_avg1, vget_high_u16(s), bck_offset); + wtd_avg1 = vshrq_n_u32(wtd_avg1, DIST_PRECISION_BITS); + int32x4_t d1 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg1, offset_vec)); + + uint16x8_t d01 = vcombine_u16(vqrshrun_n_s32(d0, ROUND_SHIFT - 2), + vqrshrun_n_s32(d1, ROUND_SHIFT - 2)); + d01 = vminq_u16(d01, max); + vst1q_u16(dst, d01); + + src += 8; + ref += 8; + dst += 8; + width -= 8; + } while (width != 0); + src_ptr += src_stride; + dst_ptr += dst_stride; + ref_ptr += ref_stride; + } while (--h != 0); + } +} + +static INLINE void highbd_dist_wtd_comp_avg_neon( + const uint16_t *src_ptr, int src_stride, uint16_t *dst_ptr, int dst_stride, + int w, int h, ConvolveParams *conv_params, const int bd) { + const int offset_bits = bd + 2 * FILTER_BITS - ROUND0_BITS; + const int offset = (1 << (offset_bits - COMPOUND_ROUND1_BITS)) + + (1 << (offset_bits - COMPOUND_ROUND1_BITS - 1)); + + CONV_BUF_TYPE *ref_ptr = conv_params->dst; + const int ref_stride = conv_params->dst_stride; + const uint32x4_t offset_vec = vdupq_n_u32(offset); + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + uint16x4_t fwd_offset = vdup_n_u16(conv_params->fwd_offset); + uint16x4_t bck_offset = vdup_n_u16(conv_params->bck_offset); + + // Weighted averaging + if (w == 4) { + do { + const uint16x4_t src = vld1_u16(src_ptr); + const uint16x4_t ref = vld1_u16(ref_ptr); + + uint32x4_t wtd_avg = vmull_u16(ref, fwd_offset); + wtd_avg = vmlal_u16(wtd_avg, src, bck_offset); + wtd_avg = vshrq_n_u32(wtd_avg, DIST_PRECISION_BITS); + int32x4_t d0 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg, offset_vec)); + + uint16x4_t d0_u16 = vqrshrun_n_s32(d0, ROUND_SHIFT); + d0_u16 = vmin_u16(d0_u16, vget_low_u16(max)); + + vst1_u16(dst_ptr, d0_u16); + + src_ptr += src_stride; + dst_ptr += dst_stride; + ref_ptr += ref_stride; + } while (--h != 0); + } else { + do { + int width = w; + const uint16_t *src = src_ptr; + const uint16_t *ref = ref_ptr; + uint16_t *dst = dst_ptr; + do { + const uint16x8_t s = vld1q_u16(src); + const uint16x8_t r = vld1q_u16(ref); + + uint32x4_t wtd_avg0 = vmull_u16(vget_low_u16(r), fwd_offset); + wtd_avg0 = vmlal_u16(wtd_avg0, vget_low_u16(s), bck_offset); + wtd_avg0 = vshrq_n_u32(wtd_avg0, DIST_PRECISION_BITS); + int32x4_t d0 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg0, offset_vec)); + + uint32x4_t wtd_avg1 = vmull_u16(vget_high_u16(r), fwd_offset); + wtd_avg1 = vmlal_u16(wtd_avg1, vget_high_u16(s), bck_offset); + wtd_avg1 = vshrq_n_u32(wtd_avg1, DIST_PRECISION_BITS); + int32x4_t d1 = vreinterpretq_s32_u32(vsubq_u32(wtd_avg1, offset_vec)); + + uint16x8_t d01 = vcombine_u16(vqrshrun_n_s32(d0, ROUND_SHIFT), + vqrshrun_n_s32(d1, ROUND_SHIFT)); + d01 = vminq_u16(d01, max); + vst1q_u16(dst, d01); + + src += 8; + ref += 8; + dst += 8; + width -= 8; + } while (width != 0); + src_ptr += src_stride; + dst_ptr += dst_stride; + ref_ptr += ref_stride; + } while (--h != 0); + } +} diff --git a/third_party/aom/av1/common/arm/highbd_compound_convolve_sve2.c b/third_party/aom/av1/common/arm/highbd_compound_convolve_sve2.c new file mode 100644 index 0000000000..1d6c9b4faf --- /dev/null +++ b/third_party/aom/av1/common/arm/highbd_compound_convolve_sve2.c @@ -0,0 +1,1555 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include +#include + +#include "config/aom_config.h" +#include "config/av1_rtcd.h" + +#include "aom_dsp/aom_dsp_common.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" +#include "aom_dsp/arm/aom_neon_sve2_bridge.h" +#include "aom_dsp/arm/mem_neon.h" +#include "aom_ports/mem.h" +#include "av1/common/convolve.h" +#include "av1/common/filter.h" +#include "av1/common/filter.h" +#include "av1/common/arm/highbd_compound_convolve_neon.h" +#include "av1/common/arm/highbd_convolve_neon.h" +#include "av1/common/arm/highbd_convolve_sve2.h" + +DECLARE_ALIGNED(16, static const uint16_t, kDotProdTbl[32]) = { + 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, + 4, 5, 6, 7, 5, 6, 7, 0, 6, 7, 0, 1, 7, 0, 1, 2, +}; + +static INLINE uint16x8_t highbd_12_convolve8_8_x(int16x8_t s0[8], + int16x8_t filter, + int64x2_t offset) { + int64x2_t sum[8]; + sum[0] = aom_sdotq_s16(offset, s0[0], filter); + sum[1] = aom_sdotq_s16(offset, s0[1], filter); + sum[2] = aom_sdotq_s16(offset, s0[2], filter); + sum[3] = aom_sdotq_s16(offset, s0[3], filter); + sum[4] = aom_sdotq_s16(offset, s0[4], filter); + sum[5] = aom_sdotq_s16(offset, s0[5], filter); + sum[6] = aom_sdotq_s16(offset, s0[6], filter); + sum[7] = aom_sdotq_s16(offset, s0[7], filter); + + sum[0] = vpaddq_s64(sum[0], sum[1]); + sum[2] = vpaddq_s64(sum[2], sum[3]); + sum[4] = vpaddq_s64(sum[4], sum[5]); + sum[6] = vpaddq_s64(sum[6], sum[7]); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum[0]), vmovn_s64(sum[2])); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum[4]), vmovn_s64(sum[6])); + + return vcombine_u16(vqrshrun_n_s32(sum0123, ROUND0_BITS + 2), + vqrshrun_n_s32(sum4567, ROUND0_BITS + 2)); +} + +static INLINE void highbd_12_dist_wtd_convolve_x_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr) { + const int64x1_t offset_vec = + vcreate_s64((1 << (12 + FILTER_BITS)) + (1 << (12 + FILTER_BITS - 1))); + const int64x2_t offset_lo = vcombine_s64(offset_vec, vdup_n_s64(0)); + + const int16x8_t filter = vld1q_s16(x_filter_ptr); + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[8], s1[8], s2[8], s3[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], + &s2[4], &s2[5], &s2[6], &s2[7]); + load_s16_8x8(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3], + &s3[4], &s3[5], &s3[6], &s3[7]); + + uint16x8_t d0 = highbd_12_convolve8_8_x(s0, filter, offset_lo); + uint16x8_t d1 = highbd_12_convolve8_8_x(s1, filter, offset_lo); + uint16x8_t d2 = highbd_12_convolve8_8_x(s2, filter, offset_lo); + uint16x8_t d3 = highbd_12_convolve8_8_x(s3, filter, offset_lo); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); +} + +static INLINE uint16x8_t highbd_convolve8_8_x(int16x8_t s0[8], int16x8_t filter, + int64x2_t offset) { + int64x2_t sum[8]; + sum[0] = aom_sdotq_s16(offset, s0[0], filter); + sum[1] = aom_sdotq_s16(offset, s0[1], filter); + sum[2] = aom_sdotq_s16(offset, s0[2], filter); + sum[3] = aom_sdotq_s16(offset, s0[3], filter); + sum[4] = aom_sdotq_s16(offset, s0[4], filter); + sum[5] = aom_sdotq_s16(offset, s0[5], filter); + sum[6] = aom_sdotq_s16(offset, s0[6], filter); + sum[7] = aom_sdotq_s16(offset, s0[7], filter); + + sum[0] = vpaddq_s64(sum[0], sum[1]); + sum[2] = vpaddq_s64(sum[2], sum[3]); + sum[4] = vpaddq_s64(sum[4], sum[5]); + sum[6] = vpaddq_s64(sum[6], sum[7]); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum[0]), vmovn_s64(sum[2])); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum[4]), vmovn_s64(sum[6])); + + return vcombine_u16(vqrshrun_n_s32(sum0123, ROUND0_BITS), + vqrshrun_n_s32(sum4567, ROUND0_BITS)); +} + +static INLINE void highbd_dist_wtd_convolve_x_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr, const int bd) { + const int64x1_t offset_vec = + vcreate_s64((1 << (bd + FILTER_BITS)) + (1 << (bd + FILTER_BITS - 1))); + const int64x2_t offset_lo = vcombine_s64(offset_vec, vdup_n_s64(0)); + + const int16x8_t filter = vld1q_s16(x_filter_ptr); + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[8], s1[8], s2[8], s3[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], + &s2[4], &s2[5], &s2[6], &s2[7]); + load_s16_8x8(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3], + &s3[4], &s3[5], &s3[6], &s3[7]); + + uint16x8_t d0 = highbd_convolve8_8_x(s0, filter, offset_lo); + uint16x8_t d1 = highbd_convolve8_8_x(s1, filter, offset_lo); + uint16x8_t d2 = highbd_convolve8_8_x(s2, filter, offset_lo); + uint16x8_t d3 = highbd_convolve8_8_x(s3, filter, offset_lo); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); +} + +// clang-format off +DECLARE_ALIGNED(16, static const uint16_t, kDeinterleaveTbl[8]) = { + 0, 2, 4, 6, 1, 3, 5, 7, +}; +// clang-format on + +static INLINE uint16x4_t highbd_12_convolve4_4_x(int16x8_t s0, int16x8_t filter, + int64x2_t offset, + uint16x8x2_t permute_tbl) { + int16x8_t permuted_samples0 = aom_tbl_s16(s0, permute_tbl.val[0]); + int16x8_t permuted_samples1 = aom_tbl_s16(s0, permute_tbl.val[1]); + + int64x2_t sum01 = aom_svdot_lane_s16(offset, permuted_samples0, filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(offset, permuted_samples1, filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + + return vqrshrun_n_s32(sum0123, ROUND0_BITS + 2); +} + +static INLINE uint16x8_t highbd_12_convolve4_8_x(int16x8_t s0[4], + int16x8_t filter, + int64x2_t offset, + uint16x8_t tbl) { + int64x2_t sum04 = aom_svdot_lane_s16(offset, s0[0], filter, 0); + int64x2_t sum15 = aom_svdot_lane_s16(offset, s0[1], filter, 0); + int64x2_t sum26 = aom_svdot_lane_s16(offset, s0[2], filter, 0); + int64x2_t sum37 = aom_svdot_lane_s16(offset, s0[3], filter, 0); + + int32x4_t sum0415 = vcombine_s32(vmovn_s64(sum04), vmovn_s64(sum15)); + int32x4_t sum2637 = vcombine_s32(vmovn_s64(sum26), vmovn_s64(sum37)); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0415, ROUND0_BITS + 2), + vqrshrun_n_s32(sum2637, ROUND0_BITS + 2)); + return aom_tbl_u16(res, tbl); +} + +static INLINE void highbd_12_dist_wtd_convolve_x_4tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr) { + const int64x2_t offset = + vdupq_n_s64((1 << (12 + FILTER_BITS)) + (1 << (12 + FILTER_BITS - 1))); + + const int16x4_t x_filter = vld1_s16(x_filter_ptr + 2); + const int16x8_t filter = vcombine_s16(x_filter, vdup_n_s16(0)); + + if (width == 4) { + uint16x8x2_t permute_tbl = vld1q_u16_x2(kDotProdTbl); + + const int16_t *s = (const int16_t *)(src); + + do { + int16x8_t s0, s1, s2, s3; + load_s16_8x4(s, src_stride, &s0, &s1, &s2, &s3); + + uint16x4_t d0 = highbd_12_convolve4_4_x(s0, filter, offset, permute_tbl); + uint16x4_t d1 = highbd_12_convolve4_4_x(s1, filter, offset, permute_tbl); + uint16x4_t d2 = highbd_12_convolve4_4_x(s2, filter, offset, permute_tbl); + uint16x4_t d3 = highbd_12_convolve4_4_x(s3, filter, offset, permute_tbl); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + uint16x8_t idx = vld1q_u16(kDeinterleaveTbl); + + do { + const int16_t *s = (const int16_t *)(src); + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[4], s1[4], s2[4], s3[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + load_s16_8x4(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3]); + + uint16x8_t d0 = highbd_12_convolve4_8_x(s0, filter, offset, idx); + uint16x8_t d1 = highbd_12_convolve4_8_x(s1, filter, offset, idx); + uint16x8_t d2 = highbd_12_convolve4_8_x(s2, filter, offset, idx); + uint16x8_t d3 = highbd_12_convolve4_8_x(s3, filter, offset, idx); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } +} + +static INLINE uint16x4_t highbd_convolve4_4_x(int16x8_t s0, int16x8_t filter, + int64x2_t offset, + uint16x8x2_t permute_tbl) { + int16x8_t permuted_samples0 = aom_tbl_s16(s0, permute_tbl.val[0]); + int16x8_t permuted_samples1 = aom_tbl_s16(s0, permute_tbl.val[1]); + + int64x2_t sum01 = aom_svdot_lane_s16(offset, permuted_samples0, filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(offset, permuted_samples1, filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + + return vqrshrun_n_s32(sum0123, ROUND0_BITS); +} + +static INLINE uint16x8_t highbd_convolve4_8_x(int16x8_t s0[4], int16x8_t filter, + int64x2_t offset, + uint16x8_t tbl) { + int64x2_t sum04 = aom_svdot_lane_s16(offset, s0[0], filter, 0); + int64x2_t sum15 = aom_svdot_lane_s16(offset, s0[1], filter, 0); + int64x2_t sum26 = aom_svdot_lane_s16(offset, s0[2], filter, 0); + int64x2_t sum37 = aom_svdot_lane_s16(offset, s0[3], filter, 0); + + int32x4_t sum0415 = vcombine_s32(vmovn_s64(sum04), vmovn_s64(sum15)); + int32x4_t sum2637 = vcombine_s32(vmovn_s64(sum26), vmovn_s64(sum37)); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0415, ROUND0_BITS), + vqrshrun_n_s32(sum2637, ROUND0_BITS)); + return aom_tbl_u16(res, tbl); +} + +static INLINE void highbd_dist_wtd_convolve_x_4tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr, const int bd) { + const int64x2_t offset = + vdupq_n_s64((1 << (bd + FILTER_BITS)) + (1 << (bd + FILTER_BITS - 1))); + + const int16x4_t x_filter = vld1_s16(x_filter_ptr + 2); + const int16x8_t filter = vcombine_s16(x_filter, vdup_n_s16(0)); + + if (width == 4) { + uint16x8x2_t permute_tbl = vld1q_u16_x2(kDotProdTbl); + + const int16_t *s = (const int16_t *)(src); + + do { + int16x8_t s0, s1, s2, s3; + load_s16_8x4(s, src_stride, &s0, &s1, &s2, &s3); + + uint16x4_t d0 = highbd_convolve4_4_x(s0, filter, offset, permute_tbl); + uint16x4_t d1 = highbd_convolve4_4_x(s1, filter, offset, permute_tbl); + uint16x4_t d2 = highbd_convolve4_4_x(s2, filter, offset, permute_tbl); + uint16x4_t d3 = highbd_convolve4_4_x(s3, filter, offset, permute_tbl); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + uint16x8_t idx = vld1q_u16(kDeinterleaveTbl); + + do { + const int16_t *s = (const int16_t *)(src); + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[4], s1[4], s2[4], s3[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + load_s16_8x4(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3]); + + uint16x8_t d0 = highbd_convolve4_8_x(s0, filter, offset, idx); + uint16x8_t d1 = highbd_convolve4_8_x(s1, filter, offset, idx); + uint16x8_t d2 = highbd_convolve4_8_x(s2, filter, offset, idx); + uint16x8_t d3 = highbd_convolve4_8_x(s3, filter, offset, idx); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } +} + +void av1_highbd_dist_wtd_convolve_x_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, int w, + int h, const InterpFilterParams *filter_params_x, const int subpel_x_qn, + ConvolveParams *conv_params, int bd) { + DECLARE_ALIGNED(16, uint16_t, + im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * MAX_SB_SIZE]); + CONV_BUF_TYPE *dst16 = conv_params->dst; + const int x_filter_taps = get_filter_tap(filter_params_x, subpel_x_qn); + + if (x_filter_taps == 6) { + av1_highbd_dist_wtd_convolve_x_neon(src, src_stride, dst, dst_stride, w, h, + filter_params_x, subpel_x_qn, + conv_params, bd); + return; + } + + int dst16_stride = conv_params->dst_stride; + const int im_stride = MAX_SB_SIZE; + const int horiz_offset = filter_params_x->taps / 2 - 1; + assert(FILTER_BITS == COMPOUND_ROUND1_BITS); + + const int16_t *x_filter_ptr = av1_get_interp_filter_subpel_kernel( + filter_params_x, subpel_x_qn & SUBPEL_MASK); + + src -= horiz_offset; + + if (bd == 12) { + if (conv_params->do_average) { + if (x_filter_taps <= 4) { + highbd_12_dist_wtd_convolve_x_4tap_sve2(src + 2, src_stride, im_block, + im_stride, w, h, x_filter_ptr); + } else { + highbd_12_dist_wtd_convolve_x_8tap_sve2(src, src_stride, im_block, + im_stride, w, h, x_filter_ptr); + } + + if (conv_params->use_dist_wtd_comp_avg) { + highbd_12_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, + w, h, conv_params); + + } else { + highbd_12_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, + conv_params); + } + } else { + if (x_filter_taps <= 4) { + highbd_12_dist_wtd_convolve_x_4tap_sve2( + src + 2, src_stride, dst16, dst16_stride, w, h, x_filter_ptr); + } else { + highbd_12_dist_wtd_convolve_x_8tap_sve2( + src, src_stride, dst16, dst16_stride, w, h, x_filter_ptr); + } + } + } else { + if (conv_params->do_average) { + if (x_filter_taps <= 4) { + highbd_dist_wtd_convolve_x_4tap_sve2(src + 2, src_stride, im_block, + im_stride, w, h, x_filter_ptr, bd); + } else { + highbd_dist_wtd_convolve_x_8tap_sve2(src, src_stride, im_block, + im_stride, w, h, x_filter_ptr, bd); + } + + if (conv_params->use_dist_wtd_comp_avg) { + highbd_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, + h, conv_params, bd); + } else { + highbd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, + conv_params, bd); + } + } else { + if (x_filter_taps <= 4) { + highbd_dist_wtd_convolve_x_4tap_sve2( + src + 2, src_stride, dst16, dst16_stride, w, h, x_filter_ptr, bd); + } else { + highbd_dist_wtd_convolve_x_8tap_sve2( + src, src_stride, dst16, dst16_stride, w, h, x_filter_ptr, bd); + } + } + } +} + +static INLINE uint16x4_t highbd_12_convolve8_4_y(int16x8_t samples_lo[2], + int16x8_t samples_hi[2], + int16x8_t filter, + int64x2_t offset) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + + return vqrshrun_n_s32(sum0123, ROUND0_BITS + 2); +} + +static INLINE uint16x8_t highbd_12_convolve8_8_y(int16x8_t samples_lo[4], + int16x8_t samples_hi[4], + int16x8_t filter, + int64x2_t offset) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int64x2_t sum45 = aom_svdot_lane_s16(offset, samples_lo[2], filter, 0); + sum45 = aom_svdot_lane_s16(sum45, samples_hi[2], filter, 1); + + int64x2_t sum67 = aom_svdot_lane_s16(offset, samples_lo[3], filter, 0); + sum67 = aom_svdot_lane_s16(sum67, samples_hi[3], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + return vcombine_u16(vqrshrun_n_s32(sum0123, ROUND0_BITS + 2), + vqrshrun_n_s32(sum4567, ROUND0_BITS + 2)); +} + +static INLINE void highbd_12_dist_wtd_convolve_y_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr) { + const int64x2_t offset = + vdupq_n_s64((1 << (12 + FILTER_BITS)) + (1 << (12 + FILTER_BITS - 1))); + const int16x8_t y_filter = vld1q_s16(y_filter_ptr); + + uint16x8x3_t merge_block_tbl = vld1q_u16_x3(kDotProdMergeBlockTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000000000000ULL)); + merge_block_tbl.val[0] = vaddq_u16(merge_block_tbl.val[0], correction0); + uint16x8_t correction1 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL)); + merge_block_tbl.val[1] = vaddq_u16(merge_block_tbl.val[1], correction1); + + uint16x8_t correction2 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100010000ULL)); + merge_block_tbl.val[2] = vaddq_u16(merge_block_tbl.val[2], correction2); + + if (width == 4) { + int16_t *s = (int16_t *)src; + int16x4_t s0, s1, s2, s3, s4, s5, s6; + load_s16_4x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + do { + int16x4_t s7, s8, s9, s10; + load_s16_4x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[2], s5678[2], s6789[2], s789A[2]; + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_4x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x4_t d0 = highbd_12_convolve8_4_y(s0123, s4567, y_filter, offset); + uint16x4_t d1 = highbd_12_convolve8_4_y(s1234, s5678, y_filter, offset); + uint16x4_t d2 = highbd_12_convolve8_4_y(s2345, s6789, y_filter, offset); + uint16x4_t d3 = highbd_12_convolve8_4_y(s3456, s789A, y_filter, offset); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + do { + int h = height; + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + + int16x8_t s0, s1, s2, s3, s4, s5, s6; + load_s16_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + do { + int16x8_t s7, s8, s9, s10; + load_s16_8x4(s, src_stride, &s7, &s8, &s9, &s10); + int16x8_t s4567[4], s5678[4], s6789[4], s789A[4]; + + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_8x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x8_t d0 = highbd_12_convolve8_8_y(s0123, s4567, y_filter, offset); + uint16x8_t d1 = highbd_12_convolve8_8_y(s1234, s5678, y_filter, offset); + uint16x8_t d2 = highbd_12_convolve8_8_y(s2345, s6789, y_filter, offset); + uint16x8_t d3 = highbd_12_convolve8_8_y(s3456, s789A, y_filter, offset); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s0123[2] = s4567[2]; + s0123[3] = s4567[3]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s1234[2] = s5678[2]; + s1234[3] = s5678[3]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s2345[2] = s6789[2]; + s2345[3] = s6789[3]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s3456[2] = s789A[2]; + s3456[3] = s789A[3]; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +static INLINE uint16x4_t highbd_convolve8_4_y(int16x8_t samples_lo[2], + int16x8_t samples_hi[2], + int16x8_t filter, + int64x2_t offset) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + + return vqrshrun_n_s32(sum0123, ROUND0_BITS); +} + +static INLINE uint16x8_t highbd_convolve8_8_y(int16x8_t samples_lo[4], + int16x8_t samples_hi[4], + int16x8_t filter, + int64x2_t offset) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int64x2_t sum45 = aom_svdot_lane_s16(offset, samples_lo[2], filter, 0); + sum45 = aom_svdot_lane_s16(sum45, samples_hi[2], filter, 1); + + int64x2_t sum67 = aom_svdot_lane_s16(offset, samples_lo[3], filter, 0); + sum67 = aom_svdot_lane_s16(sum67, samples_hi[3], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + return vcombine_u16(vqrshrun_n_s32(sum0123, ROUND0_BITS), + vqrshrun_n_s32(sum4567, ROUND0_BITS)); +} + +static INLINE void highbd_dist_wtd_convolve_y_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr, const int bd) { + const int64x2_t offset = + vdupq_n_s64((1 << (bd + FILTER_BITS)) + (1 << (bd + FILTER_BITS - 1))); + const int16x8_t y_filter = vld1q_s16(y_filter_ptr); + + uint16x8x3_t merge_block_tbl = vld1q_u16_x3(kDotProdMergeBlockTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000000000000ULL)); + merge_block_tbl.val[0] = vaddq_u16(merge_block_tbl.val[0], correction0); + uint16x8_t correction1 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL)); + merge_block_tbl.val[1] = vaddq_u16(merge_block_tbl.val[1], correction1); + + uint16x8_t correction2 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100010000ULL)); + merge_block_tbl.val[2] = vaddq_u16(merge_block_tbl.val[2], correction2); + + if (width == 4) { + int16_t *s = (int16_t *)src; + int16x4_t s0, s1, s2, s3, s4, s5, s6; + load_s16_4x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + do { + int16x4_t s7, s8, s9, s10; + load_s16_4x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[2], s5678[2], s6789[2], s789A[2]; + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_4x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x4_t d0 = highbd_convolve8_4_y(s0123, s4567, y_filter, offset); + uint16x4_t d1 = highbd_convolve8_4_y(s1234, s5678, y_filter, offset); + uint16x4_t d2 = highbd_convolve8_4_y(s2345, s6789, y_filter, offset); + uint16x4_t d3 = highbd_convolve8_4_y(s3456, s789A, y_filter, offset); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + do { + int h = height; + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + + int16x8_t s0, s1, s2, s3, s4, s5, s6; + load_s16_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + do { + int16x8_t s7, s8, s9, s10; + load_s16_8x4(s, src_stride, &s7, &s8, &s9, &s10); + int16x8_t s4567[4], s5678[4], s6789[4], s789A[4]; + + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_8x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x8_t d0 = highbd_convolve8_8_y(s0123, s4567, y_filter, offset); + uint16x8_t d1 = highbd_convolve8_8_y(s1234, s5678, y_filter, offset); + uint16x8_t d2 = highbd_convolve8_8_y(s2345, s6789, y_filter, offset); + uint16x8_t d3 = highbd_convolve8_8_y(s3456, s789A, y_filter, offset); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s0123[2] = s4567[2]; + s0123[3] = s4567[3]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s1234[2] = s5678[2]; + s1234[3] = s5678[3]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s2345[2] = s6789[2]; + s2345[3] = s6789[3]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s3456[2] = s789A[2]; + s3456[3] = s789A[3]; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +void av1_highbd_dist_wtd_convolve_y_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, int w, + int h, const InterpFilterParams *filter_params_y, const int subpel_y_qn, + ConvolveParams *conv_params, int bd) { + DECLARE_ALIGNED(16, uint16_t, + im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * MAX_SB_SIZE]); + CONV_BUF_TYPE *dst16 = conv_params->dst; + const int y_filter_taps = get_filter_tap(filter_params_y, subpel_y_qn); + + if (y_filter_taps != 8) { + av1_highbd_dist_wtd_convolve_y_neon(src, src_stride, dst, dst_stride, w, h, + filter_params_y, subpel_y_qn, + conv_params, bd); + return; + } + + int dst16_stride = conv_params->dst_stride; + const int im_stride = MAX_SB_SIZE; + const int vert_offset = filter_params_y->taps / 2 - 1; + assert(FILTER_BITS == COMPOUND_ROUND1_BITS); + + const int16_t *y_filter_ptr = av1_get_interp_filter_subpel_kernel( + filter_params_y, subpel_y_qn & SUBPEL_MASK); + + src -= vert_offset * src_stride; + + if (bd == 12) { + if (conv_params->do_average) { + highbd_12_dist_wtd_convolve_y_8tap_sve2(src, src_stride, im_block, + im_stride, w, h, y_filter_ptr); + if (conv_params->use_dist_wtd_comp_avg) { + highbd_12_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, + w, h, conv_params); + } else { + highbd_12_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, + conv_params); + } + } else { + highbd_12_dist_wtd_convolve_y_8tap_sve2(src, src_stride, dst16, + dst16_stride, w, h, y_filter_ptr); + } + } else { + if (conv_params->do_average) { + highbd_dist_wtd_convolve_y_8tap_sve2(src, src_stride, im_block, im_stride, + w, h, y_filter_ptr, bd); + if (conv_params->use_dist_wtd_comp_avg) { + highbd_dist_wtd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, + h, conv_params, bd); + } else { + highbd_comp_avg_neon(im_block, im_stride, dst, dst_stride, w, h, + conv_params, bd); + } + } else { + highbd_dist_wtd_convolve_y_8tap_sve2(src, src_stride, dst16, dst16_stride, + w, h, y_filter_ptr, bd); + } + } +} + +static INLINE void highbd_12_dist_wtd_convolve_2d_horiz_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr) { + const int64x2_t offset = vdupq_n_s64(1 << (12 + FILTER_BITS - 2)); + const int16x8_t filter = vld1q_s16(x_filter_ptr); + + // We are only doing 8-tap and 4-tap vertical convolutions, therefore we know + // that im_h % 4 = 3, so we can do the loop across the whole block 4 rows at + // a time and then process the last 3 rows separately. + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[8], s1[8], s2[8], s3[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], + &s2[4], &s2[5], &s2[6], &s2[7]); + load_s16_8x8(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3], + &s3[4], &s3[5], &s3[6], &s3[7]); + + uint16x8_t d0 = highbd_12_convolve8_8_x(s0, filter, offset); + uint16x8_t d1 = highbd_12_convolve8_8_x(s1, filter, offset); + uint16x8_t d2 = highbd_12_convolve8_8_x(s2, filter, offset); + uint16x8_t d3 = highbd_12_convolve8_8_x(s3, filter, offset); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 4); + + // Process final 3 rows. + const int16_t *s = (const int16_t *)src; + do { + int16x8_t s0[8], s1[8], s2[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], &s0[4], + &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], &s1[4], + &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], &s2[4], + &s2[5], &s2[6], &s2[7]); + + uint16x8_t d0 = highbd_12_convolve8_8_x(s0, filter, offset); + uint16x8_t d1 = highbd_12_convolve8_8_x(s1, filter, offset); + uint16x8_t d2 = highbd_12_convolve8_8_x(s2, filter, offset); + + store_u16_8x3(dst, dst_stride, d0, d1, d2); + s += 8; + dst += 8; + width -= 8; + } while (width != 0); +} + +static INLINE void highbd_dist_wtd_convolve_2d_horiz_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr, const int bd) { + const int64x2_t offset = vdupq_n_s64(1 << (bd + FILTER_BITS - 2)); + const int16x8_t filter = vld1q_s16(x_filter_ptr); + + // We are only doing 8-tap and 4-tap vertical convolutions, therefore we know + // that im_h % 4 = 3, so we can do the loop across the whole block 4 rows at + // a time and then process the last 3 rows separately. + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[8], s1[8], s2[8], s3[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], + &s2[4], &s2[5], &s2[6], &s2[7]); + load_s16_8x8(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3], + &s3[4], &s3[5], &s3[6], &s3[7]); + + uint16x8_t d0 = highbd_convolve8_8_x(s0, filter, offset); + uint16x8_t d1 = highbd_convolve8_8_x(s1, filter, offset); + uint16x8_t d2 = highbd_convolve8_8_x(s2, filter, offset); + uint16x8_t d3 = highbd_convolve8_8_x(s3, filter, offset); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 4); + + // Process final 3 rows. + const int16_t *s = (const int16_t *)src; + do { + int16x8_t s0[8], s1[8], s2[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], &s0[4], + &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], &s1[4], + &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], &s2[4], + &s2[5], &s2[6], &s2[7]); + + uint16x8_t d0 = highbd_convolve8_8_x(s0, filter, offset); + uint16x8_t d1 = highbd_convolve8_8_x(s1, filter, offset); + uint16x8_t d2 = highbd_convolve8_8_x(s2, filter, offset); + + store_u16_8x3(dst, dst_stride, d0, d1, d2); + s += 8; + dst += 8; + width -= 8; + } while (width != 0); +} + +static INLINE void highbd_12_dist_wtd_convolve_2d_horiz_4tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr) { + const int64x2_t offset = vdupq_n_s64(1 << (12 + FILTER_BITS - 1)); + const int16x4_t x_filter = vld1_s16(x_filter_ptr + 2); + const int16x8_t filter = vcombine_s16(x_filter, vdup_n_s16(0)); + + // We are only doing 8-tap and 4-tap vertical convolutions, therefore we know + // that im_h % 4 = 3, so we can do the loop across the whole block 4 rows at + // a time and then process the last 3 rows separately. + + if (width == 4) { + uint16x8x2_t permute_tbl = vld1q_u16_x2(kDotProdTbl); + + const int16_t *s = (const int16_t *)(src); + + do { + int16x8_t s0, s1, s2, s3; + load_s16_8x4(s, src_stride, &s0, &s1, &s2, &s3); + + uint16x4_t d0 = highbd_12_convolve4_4_x(s0, filter, offset, permute_tbl); + uint16x4_t d1 = highbd_12_convolve4_4_x(s1, filter, offset, permute_tbl); + uint16x4_t d2 = highbd_12_convolve4_4_x(s2, filter, offset, permute_tbl); + uint16x4_t d3 = highbd_12_convolve4_4_x(s3, filter, offset, permute_tbl); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 4); + + // Process final 3 rows. + int16x8_t s0, s1, s2; + load_s16_8x3(s, src_stride, &s0, &s1, &s2); + + uint16x4_t d0 = highbd_12_convolve4_4_x(s0, filter, offset, permute_tbl); + uint16x4_t d1 = highbd_12_convolve4_4_x(s1, filter, offset, permute_tbl); + uint16x4_t d2 = highbd_12_convolve4_4_x(s2, filter, offset, permute_tbl); + + store_u16_4x3(dst, dst_stride, d0, d1, d2); + + } else { + uint16x8_t idx = vld1q_u16(kDeinterleaveTbl); + + do { + const int16_t *s = (const int16_t *)(src); + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[4], s1[4], s2[4], s3[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + load_s16_8x4(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3]); + + uint16x8_t d0 = highbd_12_convolve4_8_x(s0, filter, offset, idx); + uint16x8_t d1 = highbd_12_convolve4_8_x(s1, filter, offset, idx); + uint16x8_t d2 = highbd_12_convolve4_8_x(s2, filter, offset, idx); + uint16x8_t d3 = highbd_12_convolve4_8_x(s3, filter, offset, idx); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 4); + + // Process final 3 rows. + const int16_t *s = (const int16_t *)(src); + + do { + int16x8_t s0[4], s1[4], s2[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + + uint16x8_t d0 = highbd_12_convolve4_8_x(s0, filter, offset, idx); + uint16x8_t d1 = highbd_12_convolve4_8_x(s1, filter, offset, idx); + uint16x8_t d2 = highbd_12_convolve4_8_x(s2, filter, offset, idx); + + store_u16_8x3(dst, dst_stride, d0, d1, d2); + + s += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +static INLINE void highbd_dist_wtd_convolve_2d_horiz_4tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr, const int bd) { + const int64x2_t offset = vdupq_n_s64(1 << (bd + FILTER_BITS - 1)); + const int16x4_t x_filter = vld1_s16(x_filter_ptr + 2); + const int16x8_t filter = vcombine_s16(x_filter, vdup_n_s16(0)); + + // We are only doing 8-tap and 4-tap vertical convolutions, therefore we know + // that im_h % 4 = 3, so we can do the loop across the whole block 4 rows at + // a time and then process the last 3 rows separately. + + if (width == 4) { + uint16x8x2_t permute_tbl = vld1q_u16_x2(kDotProdTbl); + + const int16_t *s = (const int16_t *)(src); + + do { + int16x8_t s0, s1, s2, s3; + load_s16_8x4(s, src_stride, &s0, &s1, &s2, &s3); + + uint16x4_t d0 = highbd_convolve4_4_x(s0, filter, offset, permute_tbl); + uint16x4_t d1 = highbd_convolve4_4_x(s1, filter, offset, permute_tbl); + uint16x4_t d2 = highbd_convolve4_4_x(s2, filter, offset, permute_tbl); + uint16x4_t d3 = highbd_convolve4_4_x(s3, filter, offset, permute_tbl); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 4); + + // Process final 3 rows. + int16x8_t s0, s1, s2; + load_s16_8x3(s, src_stride, &s0, &s1, &s2); + + uint16x4_t d0 = highbd_convolve4_4_x(s0, filter, offset, permute_tbl); + uint16x4_t d1 = highbd_convolve4_4_x(s1, filter, offset, permute_tbl); + uint16x4_t d2 = highbd_convolve4_4_x(s2, filter, offset, permute_tbl); + + store_u16_4x3(dst, dst_stride, d0, d1, d2); + } else { + uint16x8_t idx = vld1q_u16(kDeinterleaveTbl); + + do { + const int16_t *s = (const int16_t *)(src); + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[4], s1[4], s2[4], s3[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + load_s16_8x4(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3]); + + uint16x8_t d0 = highbd_convolve4_8_x(s0, filter, offset, idx); + uint16x8_t d1 = highbd_convolve4_8_x(s1, filter, offset, idx); + uint16x8_t d2 = highbd_convolve4_8_x(s2, filter, offset, idx); + uint16x8_t d3 = highbd_convolve4_8_x(s3, filter, offset, idx); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 4); + + // Process final 3 rows. + const int16_t *s = (const int16_t *)(src); + + do { + int16x8_t s0[4], s1[4], s2[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + + uint16x8_t d0 = highbd_convolve4_8_x(s0, filter, offset, idx); + uint16x8_t d1 = highbd_convolve4_8_x(s1, filter, offset, idx); + uint16x8_t d2 = highbd_convolve4_8_x(s2, filter, offset, idx); + + store_u16_8x3(dst, dst_stride, d0, d1, d2); + + s += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +static INLINE uint16x4_t highbd_convolve8_4_2d_v(int16x8_t samples_lo[2], + int16x8_t samples_hi[2], + int16x8_t filter, + int64x2_t offset) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + + return vqrshrun_n_s32(sum0123, COMPOUND_ROUND1_BITS); +} + +static INLINE uint16x8_t highbd_convolve8_8_2d_v(int16x8_t samples_lo[4], + int16x8_t samples_hi[4], + int16x8_t filter, + int64x2_t offset) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int64x2_t sum45 = aom_svdot_lane_s16(offset, samples_lo[2], filter, 0); + sum45 = aom_svdot_lane_s16(sum45, samples_hi[2], filter, 1); + + int64x2_t sum67 = aom_svdot_lane_s16(offset, samples_lo[3], filter, 0); + sum67 = aom_svdot_lane_s16(sum67, samples_hi[3], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + return vcombine_u16(vqrshrun_n_s32(sum0123, COMPOUND_ROUND1_BITS), + vqrshrun_n_s32(sum4567, COMPOUND_ROUND1_BITS)); +} + +static INLINE void highbd_dist_wtd_convolve_2d_vert_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr, int offset) { + const int16x8_t y_filter = vld1q_s16(y_filter_ptr); + const int64x2_t offset_s64 = vdupq_n_s64(offset); + + uint16x8x3_t merge_block_tbl = vld1q_u16_x3(kDotProdMergeBlockTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000000000000ULL)); + merge_block_tbl.val[0] = vaddq_u16(merge_block_tbl.val[0], correction0); + + uint16x8_t correction1 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL)); + merge_block_tbl.val[1] = vaddq_u16(merge_block_tbl.val[1], correction1); + + uint16x8_t correction2 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100010000ULL)); + merge_block_tbl.val[2] = vaddq_u16(merge_block_tbl.val[2], correction2); + + if (width == 4) { + int16_t *s = (int16_t *)src; + int16x4_t s0, s1, s2, s3, s4, s5, s6; + load_s16_4x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + do { + int16x4_t s7, s8, s9, s10; + load_s16_4x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[2], s5678[2], s6789[2], s789A[2]; + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_4x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x4_t d0 = + highbd_convolve8_4_2d_v(s0123, s4567, y_filter, offset_s64); + uint16x4_t d1 = + highbd_convolve8_4_2d_v(s1234, s5678, y_filter, offset_s64); + uint16x4_t d2 = + highbd_convolve8_4_2d_v(s2345, s6789, y_filter, offset_s64); + uint16x4_t d3 = + highbd_convolve8_4_2d_v(s3456, s789A, y_filter, offset_s64); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + do { + int h = height; + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + + int16x8_t s0, s1, s2, s3, s4, s5, s6; + load_s16_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + do { + int16x8_t s7, s8, s9, s10; + load_s16_8x4(s, src_stride, &s7, &s8, &s9, &s10); + int16x8_t s4567[4], s5678[4], s6789[4], s789A[4]; + + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_8x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x8_t d0 = + highbd_convolve8_8_2d_v(s0123, s4567, y_filter, offset_s64); + uint16x8_t d1 = + highbd_convolve8_8_2d_v(s1234, s5678, y_filter, offset_s64); + uint16x8_t d2 = + highbd_convolve8_8_2d_v(s2345, s6789, y_filter, offset_s64); + uint16x8_t d3 = + highbd_convolve8_8_2d_v(s3456, s789A, y_filter, offset_s64); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s0123[2] = s4567[2]; + s0123[3] = s4567[3]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s1234[2] = s5678[2]; + s1234[3] = s5678[3]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s2345[2] = s6789[2]; + s2345[3] = s6789[3]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s3456[2] = s789A[2]; + s3456[3] = s789A[3]; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +static INLINE uint16x4_t highbd_convolve4_4_2d_v( + const int16x4_t s0, const int16x4_t s1, const int16x4_t s2, + const int16x4_t s3, const int16x4_t filter, const int32x4_t offset) { + int32x4_t sum = vmlal_lane_s16(offset, s0, filter, 0); + sum = vmlal_lane_s16(sum, s1, filter, 1); + sum = vmlal_lane_s16(sum, s2, filter, 2); + sum = vmlal_lane_s16(sum, s3, filter, 3); + + return vqrshrun_n_s32(sum, COMPOUND_ROUND1_BITS); +} + +static INLINE uint16x8_t highbd_convolve4_8_2d_v( + const int16x8_t s0, const int16x8_t s1, const int16x8_t s2, + const int16x8_t s3, const int16x4_t filter, const int32x4_t offset) { + int32x4_t sum0 = vmlal_lane_s16(offset, vget_low_s16(s0), filter, 0); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s1), filter, 1); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s2), filter, 2); + sum0 = vmlal_lane_s16(sum0, vget_low_s16(s3), filter, 3); + + int32x4_t sum1 = vmlal_lane_s16(offset, vget_high_s16(s0), filter, 0); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s1), filter, 1); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s2), filter, 2); + sum1 = vmlal_lane_s16(sum1, vget_high_s16(s3), filter, 3); + + return vcombine_u16(vqrshrun_n_s32(sum0, COMPOUND_ROUND1_BITS), + vqrshrun_n_s32(sum1, COMPOUND_ROUND1_BITS)); +} + +static INLINE void highbd_dist_wtd_convolve_2d_vert_4tap_neon( + const uint16_t *src_ptr, int src_stride, uint16_t *dst_ptr, int dst_stride, + int w, int h, const int16_t *y_filter_ptr, const int offset) { + const int16x4_t y_filter = vld1_s16(y_filter_ptr + 2); + const int32x4_t offset_vec = vdupq_n_s32(offset); + + if (w == 4) { + const int16_t *s = (const int16_t *)src_ptr; + uint16_t *d = dst_ptr; + + int16x4_t s0, s1, s2; + load_s16_4x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x4_t s3, s4, s5, s6; + load_s16_4x4(s, src_stride, &s3, &s4, &s5, &s6); + + uint16x4_t d0 = + highbd_convolve4_4_2d_v(s0, s1, s2, s3, y_filter, offset_vec); + uint16x4_t d1 = + highbd_convolve4_4_2d_v(s1, s2, s3, s4, y_filter, offset_vec); + uint16x4_t d2 = + highbd_convolve4_4_2d_v(s2, s3, s4, s5, y_filter, offset_vec); + uint16x4_t d3 = + highbd_convolve4_4_2d_v(s3, s4, s5, s6, y_filter, offset_vec); + + store_u16_4x4(d, dst_stride, d0, d1, d2, d3); + + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + } else { + do { + int height = h; + const int16_t *s = (const int16_t *)src_ptr; + uint16_t *d = dst_ptr; + + int16x8_t s0, s1, s2; + load_s16_8x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x8_t s3, s4, s5, s6; + load_s16_8x4(s, src_stride, &s3, &s4, &s5, &s6); + + uint16x8_t d0 = + highbd_convolve4_8_2d_v(s0, s1, s2, s3, y_filter, offset_vec); + uint16x8_t d1 = + highbd_convolve4_8_2d_v(s1, s2, s3, s4, y_filter, offset_vec); + uint16x8_t d2 = + highbd_convolve4_8_2d_v(s2, s3, s4, s5, y_filter, offset_vec); + uint16x8_t d3 = + highbd_convolve4_8_2d_v(s3, s4, s5, s6, y_filter, offset_vec); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + height -= 4; + } while (height != 0); + src_ptr += 8; + dst_ptr += 8; + w -= 8; + } while (w != 0); + } +} + +void av1_highbd_dist_wtd_convolve_2d_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, int w, + int h, const InterpFilterParams *filter_params_x, + const InterpFilterParams *filter_params_y, const int subpel_x_qn, + const int subpel_y_qn, ConvolveParams *conv_params, int bd) { + DECLARE_ALIGNED(16, uint16_t, + im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * MAX_SB_SIZE]); + DECLARE_ALIGNED(16, uint16_t, + im_block2[(MAX_SB_SIZE + MAX_FILTER_TAP) * MAX_SB_SIZE]); + + CONV_BUF_TYPE *dst16 = conv_params->dst; + int dst16_stride = conv_params->dst_stride; + const int x_filter_taps = get_filter_tap(filter_params_x, subpel_x_qn); + const int clamped_x_taps = x_filter_taps < 4 ? 4 : x_filter_taps; + + const int y_filter_taps = get_filter_tap(filter_params_y, subpel_y_qn); + const int clamped_y_taps = y_filter_taps < 4 ? 4 : y_filter_taps; + + if (x_filter_taps == 6 || y_filter_taps == 6) { + av1_highbd_dist_wtd_convolve_2d_neon( + src, src_stride, dst, dst_stride, w, h, filter_params_x, + filter_params_y, subpel_x_qn, subpel_y_qn, conv_params, bd); + return; + } + + const int im_h = h + clamped_y_taps - 1; + const int im_stride = MAX_SB_SIZE; + const int vert_offset = clamped_y_taps / 2 - 1; + const int horiz_offset = clamped_x_taps / 2 - 1; + const int y_offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; + const int round_offset_conv_y = (1 << y_offset_bits); + + const uint16_t *src_ptr = src - vert_offset * src_stride - horiz_offset; + + const int16_t *x_filter_ptr = av1_get_interp_filter_subpel_kernel( + filter_params_x, subpel_x_qn & SUBPEL_MASK); + const int16_t *y_filter_ptr = av1_get_interp_filter_subpel_kernel( + filter_params_y, subpel_y_qn & SUBPEL_MASK); + + if (bd == 12) { + if (x_filter_taps <= 4) { + highbd_12_dist_wtd_convolve_2d_horiz_4tap_sve2( + src_ptr, src_stride, im_block, im_stride, w, im_h, x_filter_ptr); + } else { + highbd_12_dist_wtd_convolve_2d_horiz_8tap_sve2( + src_ptr, src_stride, im_block, im_stride, w, im_h, x_filter_ptr); + } + } else { + if (x_filter_taps <= 4) { + highbd_dist_wtd_convolve_2d_horiz_4tap_sve2( + src_ptr, src_stride, im_block, im_stride, w, im_h, x_filter_ptr, bd); + } else { + highbd_dist_wtd_convolve_2d_horiz_8tap_sve2( + src_ptr, src_stride, im_block, im_stride, w, im_h, x_filter_ptr, bd); + } + } + + if (conv_params->do_average) { + if (y_filter_taps <= 4) { + highbd_dist_wtd_convolve_2d_vert_4tap_neon(im_block, im_stride, im_block2, + im_stride, w, h, y_filter_ptr, + round_offset_conv_y); + } else { + highbd_dist_wtd_convolve_2d_vert_8tap_sve2(im_block, im_stride, im_block2, + im_stride, w, h, y_filter_ptr, + round_offset_conv_y); + } + if (conv_params->use_dist_wtd_comp_avg) { + if (bd == 12) { + highbd_12_dist_wtd_comp_avg_neon(im_block2, im_stride, dst, dst_stride, + w, h, conv_params); + + } else { + highbd_dist_wtd_comp_avg_neon(im_block2, im_stride, dst, dst_stride, w, + h, conv_params, bd); + } + } else { + if (bd == 12) { + highbd_12_comp_avg_neon(im_block2, im_stride, dst, dst_stride, w, h, + conv_params); + + } else { + highbd_comp_avg_neon(im_block2, im_stride, dst, dst_stride, w, h, + conv_params, bd); + } + } + } else { + if (y_filter_taps <= 4) { + highbd_dist_wtd_convolve_2d_vert_4tap_neon( + im_block, im_stride, dst16, dst16_stride, w, h, y_filter_ptr, + round_offset_conv_y); + } else { + highbd_dist_wtd_convolve_2d_vert_8tap_sve2( + im_block, im_stride, dst16, dst16_stride, w, h, y_filter_ptr, + round_offset_conv_y); + } + } +} diff --git a/third_party/aom/av1/common/arm/highbd_convolve_sve2.c b/third_party/aom/av1/common/arm/highbd_convolve_sve2.c new file mode 100644 index 0000000000..82eb12fcea --- /dev/null +++ b/third_party/aom/av1/common/arm/highbd_convolve_sve2.c @@ -0,0 +1,1720 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include +#include + +#include "config/aom_config.h" +#include "config/av1_rtcd.h" + +#include "aom_dsp/aom_dsp_common.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" +#include "aom_dsp/arm/aom_neon_sve2_bridge.h" +#include "aom_dsp/arm/mem_neon.h" +#include "aom_ports/mem.h" +#include "av1/common/convolve.h" +#include "av1/common/filter.h" +#include "av1/common/arm/highbd_convolve_sve2.h" + +DECLARE_ALIGNED(16, static const uint16_t, kDotProdTbl[32]) = { + 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, + 4, 5, 6, 7, 5, 6, 7, 0, 6, 7, 0, 1, 7, 0, 1, 2, +}; + +static INLINE uint16x4_t convolve12_4_x( + int16x8_t s0, int16x8_t s1, int16x8_t filter_0_7, int16x8_t filter_4_11, + const int64x2_t offset, uint16x8x4_t permute_tbl, uint16x4_t max) { + int16x8_t permuted_samples[6]; + permuted_samples[0] = aom_tbl_s16(s0, permute_tbl.val[0]); + permuted_samples[1] = aom_tbl_s16(s0, permute_tbl.val[1]); + permuted_samples[2] = aom_tbl2_s16(s0, s1, permute_tbl.val[2]); + permuted_samples[3] = aom_tbl2_s16(s0, s1, permute_tbl.val[3]); + permuted_samples[4] = aom_tbl_s16(s1, permute_tbl.val[0]); + permuted_samples[5] = aom_tbl_s16(s1, permute_tbl.val[1]); + + int64x2_t sum01 = + aom_svdot_lane_s16(offset, permuted_samples[0], filter_0_7, 0); + sum01 = aom_svdot_lane_s16(sum01, permuted_samples[2], filter_0_7, 1); + sum01 = aom_svdot_lane_s16(sum01, permuted_samples[4], filter_4_11, 1); + + int64x2_t sum23 = + aom_svdot_lane_s16(offset, permuted_samples[1], filter_0_7, 0); + sum23 = aom_svdot_lane_s16(sum23, permuted_samples[3], filter_0_7, 1); + sum23 = aom_svdot_lane_s16(sum23, permuted_samples[5], filter_4_11, 1); + + int32x4_t res0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + uint16x4_t res = vqrshrun_n_s32(res0123, FILTER_BITS); + + return vmin_u16(res, max); +} + +static INLINE uint16x8_t convolve12_8_x(int16x8_t s0, int16x8_t s1, + int16x8_t s2, int16x8_t filter_0_7, + int16x8_t filter_4_11, int64x2_t offset, + uint16x8x4_t permute_tbl, + uint16x8_t max) { + int16x8_t permuted_samples[8]; + permuted_samples[0] = aom_tbl_s16(s0, permute_tbl.val[0]); + permuted_samples[1] = aom_tbl_s16(s0, permute_tbl.val[1]); + permuted_samples[2] = aom_tbl2_s16(s0, s1, permute_tbl.val[2]); + permuted_samples[3] = aom_tbl2_s16(s0, s1, permute_tbl.val[3]); + permuted_samples[4] = aom_tbl_s16(s1, permute_tbl.val[0]); + permuted_samples[5] = aom_tbl_s16(s1, permute_tbl.val[1]); + permuted_samples[6] = aom_tbl2_s16(s1, s2, permute_tbl.val[2]); + permuted_samples[7] = aom_tbl2_s16(s1, s2, permute_tbl.val[3]); + + int64x2_t sum01 = + aom_svdot_lane_s16(offset, permuted_samples[0], filter_0_7, 0); + sum01 = aom_svdot_lane_s16(sum01, permuted_samples[2], filter_0_7, 1); + sum01 = aom_svdot_lane_s16(sum01, permuted_samples[4], filter_4_11, 1); + + int64x2_t sum23 = + aom_svdot_lane_s16(offset, permuted_samples[1], filter_0_7, 0); + sum23 = aom_svdot_lane_s16(sum23, permuted_samples[3], filter_0_7, 1); + sum23 = aom_svdot_lane_s16(sum23, permuted_samples[5], filter_4_11, 1); + + int64x2_t sum45 = + aom_svdot_lane_s16(offset, permuted_samples[2], filter_0_7, 0); + sum45 = aom_svdot_lane_s16(sum45, permuted_samples[4], filter_0_7, 1); + sum45 = aom_svdot_lane_s16(sum45, permuted_samples[6], filter_4_11, 1); + + int64x2_t sum67 = + aom_svdot_lane_s16(offset, permuted_samples[3], filter_0_7, 0); + sum67 = aom_svdot_lane_s16(sum67, permuted_samples[5], filter_0_7, 1); + sum67 = aom_svdot_lane_s16(sum67, permuted_samples[7], filter_4_11, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0123, FILTER_BITS), + vqrshrun_n_s32(sum4567, FILTER_BITS)); + + return vminq_u16(res, max); +} + +static INLINE void highbd_convolve_x_sr_12tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr, + ConvolveParams *conv_params, int bd) { + // This shim allows to do only one rounding shift instead of two. + const int64x2_t offset = vdupq_n_s64(1 << (conv_params->round_0 - 1)); + + const int16x8_t y_filter_0_7 = vld1q_s16(y_filter_ptr); + const int16x8_t y_filter_4_11 = vld1q_s16(y_filter_ptr + 4); + + uint16x8x4_t permute_tbl = vld1q_u16_x4(kDotProdTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = vreinterpretq_u16_u64(vcombine_u64( + vdup_n_u64(0), vdup_n_u64(svcnth() * 0x0001000000000000ULL))); + permute_tbl.val[2] = vaddq_u16(permute_tbl.val[2], correction0); + + uint16x8_t correction1 = vreinterpretq_u16_u64( + vcombine_u64(vdup_n_u64(svcnth() * 0x0001000100000000ULL), + vdup_n_u64(svcnth() * 0x0001000100010000ULL))); + permute_tbl.val[3] = vaddq_u16(permute_tbl.val[3], correction1); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + const int16_t *s = (const int16_t *)src; + + do { + int16x8_t s0, s1, s2, s3, s4, s5, s6, s7; + load_s16_8x4(s, src_stride, &s0, &s2, &s4, &s6); + load_s16_8x4(s + 8, src_stride, &s1, &s3, &s5, &s7); + + uint16x4_t d0 = convolve12_4_x(s0, s1, y_filter_0_7, y_filter_4_11, + offset, permute_tbl, max); + uint16x4_t d1 = convolve12_4_x(s2, s3, y_filter_0_7, y_filter_4_11, + offset, permute_tbl, max); + uint16x4_t d2 = convolve12_4_x(s4, s5, y_filter_0_7, y_filter_4_11, + offset, permute_tbl, max); + uint16x4_t d3 = convolve12_4_x(s6, s7, y_filter_0_7, y_filter_4_11, + offset, permute_tbl, max); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; + load_s16_8x4(s, src_stride, &s0, &s3, &s6, &s9); + load_s16_8x4(s + 8, src_stride, &s1, &s4, &s7, &s10); + load_s16_8x4(s + 16, src_stride, &s2, &s5, &s8, &s11); + + uint16x8_t d0 = convolve12_8_x(s0, s1, s2, y_filter_0_7, y_filter_4_11, + offset, permute_tbl, max); + uint16x8_t d1 = convolve12_8_x(s3, s4, s5, y_filter_0_7, y_filter_4_11, + offset, permute_tbl, max); + uint16x8_t d2 = convolve12_8_x(s6, s7, s8, y_filter_0_7, y_filter_4_11, + offset, permute_tbl, max); + uint16x8_t d3 = convolve12_8_x(s9, s10, s11, y_filter_0_7, + y_filter_4_11, offset, permute_tbl, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } +} + +static INLINE uint16x8_t convolve8_8_x(int16x8_t s0[8], int16x8_t filter, + int64x2_t offset, uint16x8_t max) { + int64x2_t sum[8]; + sum[0] = aom_sdotq_s16(offset, s0[0], filter); + sum[1] = aom_sdotq_s16(offset, s0[1], filter); + sum[2] = aom_sdotq_s16(offset, s0[2], filter); + sum[3] = aom_sdotq_s16(offset, s0[3], filter); + sum[4] = aom_sdotq_s16(offset, s0[4], filter); + sum[5] = aom_sdotq_s16(offset, s0[5], filter); + sum[6] = aom_sdotq_s16(offset, s0[6], filter); + sum[7] = aom_sdotq_s16(offset, s0[7], filter); + + sum[0] = vpaddq_s64(sum[0], sum[1]); + sum[2] = vpaddq_s64(sum[2], sum[3]); + sum[4] = vpaddq_s64(sum[4], sum[5]); + sum[6] = vpaddq_s64(sum[6], sum[7]); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum[0]), vmovn_s64(sum[2])); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum[4]), vmovn_s64(sum[6])); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0123, FILTER_BITS), + vqrshrun_n_s32(sum4567, FILTER_BITS)); + + return vminq_u16(res, max); +} + +static INLINE void highbd_convolve_x_sr_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr, + ConvolveParams *conv_params, int bd) { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + // This shim allows to do only one rounding shift instead of two. + const int64_t offset = 1 << (conv_params->round_0 - 1); + const int64x2_t offset_lo = vcombine_s64((int64x1_t)(offset), vdup_n_s64(0)); + + const int16x8_t filter = vld1q_s16(y_filter_ptr); + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[8], s1[8], s2[8], s3[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], + &s2[4], &s2[5], &s2[6], &s2[7]); + load_s16_8x8(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3], + &s3[4], &s3[5], &s3[6], &s3[7]); + + uint16x8_t d0 = convolve8_8_x(s0, filter, offset_lo, max); + uint16x8_t d1 = convolve8_8_x(s1, filter, offset_lo, max); + uint16x8_t d2 = convolve8_8_x(s2, filter, offset_lo, max); + uint16x8_t d3 = convolve8_8_x(s3, filter, offset_lo, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); +} + +// clang-format off +DECLARE_ALIGNED(16, static const uint16_t, kDeinterleaveTbl[8]) = { + 0, 2, 4, 6, 1, 3, 5, 7, +}; +// clang-format on + +static INLINE uint16x4_t convolve4_4_x(int16x8_t s0, int16x8_t filter, + int64x2_t offset, + uint16x8x2_t permute_tbl, + uint16x4_t max) { + int16x8_t permuted_samples0 = aom_tbl_s16(s0, permute_tbl.val[0]); + int16x8_t permuted_samples1 = aom_tbl_s16(s0, permute_tbl.val[1]); + + int64x2_t sum01 = aom_svdot_lane_s16(offset, permuted_samples0, filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(offset, permuted_samples1, filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + uint16x4_t res = vqrshrun_n_s32(sum0123, FILTER_BITS); + + return vmin_u16(res, max); +} + +static INLINE uint16x8_t convolve4_8_x(int16x8_t s0[4], int16x8_t filter, + int64x2_t offset, uint16x8_t tbl, + uint16x8_t max) { + int64x2_t sum04 = aom_svdot_lane_s16(offset, s0[0], filter, 0); + int64x2_t sum15 = aom_svdot_lane_s16(offset, s0[1], filter, 0); + int64x2_t sum26 = aom_svdot_lane_s16(offset, s0[2], filter, 0); + int64x2_t sum37 = aom_svdot_lane_s16(offset, s0[3], filter, 0); + + int32x4_t sum0415 = vcombine_s32(vmovn_s64(sum04), vmovn_s64(sum15)); + int32x4_t sum2637 = vcombine_s32(vmovn_s64(sum26), vmovn_s64(sum37)); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0415, FILTER_BITS), + vqrshrun_n_s32(sum2637, FILTER_BITS)); + res = aom_tbl_u16(res, tbl); + + return vminq_u16(res, max); +} + +static INLINE void highbd_convolve_x_sr_4tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr, + ConvolveParams *conv_params, int bd) { + // This shim allows to do only one rounding shift instead of two. + const int64x2_t offset = vdupq_n_s64(1 << (conv_params->round_0 - 1)); + + const int16x4_t x_filter = vld1_s16(x_filter_ptr + 2); + const int16x8_t filter = vcombine_s16(x_filter, vdup_n_s16(0)); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + uint16x8x2_t permute_tbl = vld1q_u16_x2(kDotProdTbl); + + const int16_t *s = (const int16_t *)(src); + + do { + int16x8_t s0, s1, s2, s3; + load_s16_8x4(s, src_stride, &s0, &s1, &s2, &s3); + + uint16x4_t d0 = convolve4_4_x(s0, filter, offset, permute_tbl, max); + uint16x4_t d1 = convolve4_4_x(s1, filter, offset, permute_tbl, max); + uint16x4_t d2 = convolve4_4_x(s2, filter, offset, permute_tbl, max); + uint16x4_t d3 = convolve4_4_x(s3, filter, offset, permute_tbl, max); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + uint16x8_t idx = vld1q_u16(kDeinterleaveTbl); + + do { + const int16_t *s = (const int16_t *)(src); + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[4], s1[4], s2[4], s3[4]; + load_s16_8x4(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3]); + load_s16_8x4(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3]); + load_s16_8x4(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3]); + load_s16_8x4(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3]); + + uint16x8_t d0 = convolve4_8_x(s0, filter, offset, idx, max); + uint16x8_t d1 = convolve4_8_x(s1, filter, offset, idx, max); + uint16x8_t d2 = convolve4_8_x(s2, filter, offset, idx, max); + uint16x8_t d3 = convolve4_8_x(s3, filter, offset, idx, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } +} + +void av1_highbd_convolve_x_sr_sve2(const uint16_t *src, int src_stride, + uint16_t *dst, int dst_stride, int w, int h, + const InterpFilterParams *filter_params_x, + const int subpel_x_qn, + ConvolveParams *conv_params, int bd) { + if (w == 2 || h == 2) { + av1_highbd_convolve_x_sr_c(src, src_stride, dst, dst_stride, w, h, + filter_params_x, subpel_x_qn, conv_params, bd); + return; + } + + const int x_filter_taps = get_filter_tap(filter_params_x, subpel_x_qn); + + if (x_filter_taps == 6) { + av1_highbd_convolve_x_sr_neon(src, src_stride, dst, dst_stride, w, h, + filter_params_x, subpel_x_qn, conv_params, + bd); + return; + } + + const int horiz_offset = filter_params_x->taps / 2 - 1; + const int16_t *x_filter_ptr = av1_get_interp_filter_subpel_kernel( + filter_params_x, subpel_x_qn & SUBPEL_MASK); + + src -= horiz_offset; + + if (x_filter_taps == 12) { + highbd_convolve_x_sr_12tap_sve2(src, src_stride, dst, dst_stride, w, h, + x_filter_ptr, conv_params, bd); + return; + } + + if (x_filter_taps == 8) { + highbd_convolve_x_sr_8tap_sve2(src, src_stride, dst, dst_stride, w, h, + x_filter_ptr, conv_params, bd); + return; + } + + highbd_convolve_x_sr_4tap_sve2(src + 2, src_stride, dst, dst_stride, w, h, + x_filter_ptr, conv_params, bd); +} + +static INLINE uint16x4_t highbd_convolve12_4_y(int16x8_t s0[2], int16x8_t s1[2], + int16x8_t s2[2], + int16x8_t filter_0_7, + int16x8_t filter_4_11, + uint16x4_t max) { + int64x2_t sum[2]; + + sum[0] = aom_svdot_lane_s16(vdupq_n_s64(0), s0[0], filter_0_7, 0); + sum[0] = aom_svdot_lane_s16(sum[0], s1[0], filter_0_7, 1); + sum[0] = aom_svdot_lane_s16(sum[0], s2[0], filter_4_11, 1); + + sum[1] = aom_svdot_lane_s16(vdupq_n_s64(0), s0[1], filter_0_7, 0); + sum[1] = aom_svdot_lane_s16(sum[1], s1[1], filter_0_7, 1); + sum[1] = aom_svdot_lane_s16(sum[1], s2[1], filter_4_11, 1); + + int32x4_t res_s32 = vcombine_s32(vmovn_s64(sum[0]), vmovn_s64(sum[1])); + + uint16x4_t res = vqrshrun_n_s32(res_s32, FILTER_BITS); + + return vmin_u16(res, max); +} + +static INLINE void highbd_convolve_y_sr_12tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr, int bd) { + const int16x8_t y_filter_0_7 = vld1q_s16(y_filter_ptr); + const int16x8_t y_filter_4_11 = vld1q_s16(y_filter_ptr + 4); + + uint16x8x3_t merge_block_tbl = vld1q_u16_x3(kDotProdMergeBlockTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000000000000ULL)); + merge_block_tbl.val[0] = vaddq_u16(merge_block_tbl.val[0], correction0); + + uint16x8_t correction1 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL)); + merge_block_tbl.val[1] = vaddq_u16(merge_block_tbl.val[1], correction1); + + uint16x8_t correction2 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100010000ULL)); + merge_block_tbl.val[2] = vaddq_u16(merge_block_tbl.val[2], correction2); + + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + + do { + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + int h = height; + + int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA; + load_s16_4x11(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7, &s8, + &s9, &sA); + s += 11 * src_stride; + + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2], s4567[2], s5678[2], + s6789[2], s789A[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + transpose_concat_4x4(s4, s5, s6, s7, s4567); + transpose_concat_4x4(s5, s6, s7, s8, s5678); + transpose_concat_4x4(s6, s7, s8, s9, s6789); + transpose_concat_4x4(s7, s8, s9, sA, s789A); + + do { + int16x4_t sB, sC, sD, sE; + load_s16_4x4(s, src_stride, &sB, &sC, &sD, &sE); + + int16x8_t s89AB[2], s9ABC[2], sABCD[2], sBCDE[2]; + transpose_concat_4x4(sB, sC, sD, sE, sBCDE); + + // Use the above transpose and reuse data from the previous loop to get + // the rest. + aom_tbl2x2_s16(s789A, sBCDE, merge_block_tbl.val[0], s89AB); + aom_tbl2x2_s16(s789A, sBCDE, merge_block_tbl.val[1], s9ABC); + aom_tbl2x2_s16(s789A, sBCDE, merge_block_tbl.val[2], sABCD); + + uint16x4_t d0 = highbd_convolve12_4_y(s0123, s4567, s89AB, y_filter_0_7, + y_filter_4_11, max); + uint16x4_t d1 = highbd_convolve12_4_y(s1234, s5678, s9ABC, y_filter_0_7, + y_filter_4_11, max); + uint16x4_t d2 = highbd_convolve12_4_y(s2345, s6789, sABCD, y_filter_0_7, + y_filter_4_11, max); + uint16x4_t d3 = highbd_convolve12_4_y(s3456, s789A, sBCDE, y_filter_0_7, + y_filter_4_11, max); + + store_u16_4x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s4567[0] = s89AB[0]; + s4567[1] = s89AB[1]; + s5678[0] = s9ABC[0]; + s5678[1] = s9ABC[1]; + s6789[0] = sABCD[0]; + s6789[1] = sABCD[1]; + s789A[0] = sBCDE[0]; + s789A[1] = sBCDE[1]; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 4; + dst += 4; + width -= 4; + } while (width != 0); +} + +static INLINE uint16x4_t highbd_convolve8_4_y(int16x8_t samples_lo[2], + int16x8_t samples_hi[2], + int16x8_t filter, + uint16x4_t max) { + int64x2_t sum01 = + aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = + aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + uint16x4_t res = vqrshrun_n_s32(sum0123, FILTER_BITS); + return vmin_u16(res, max); +} + +static INLINE uint16x8_t highbd_convolve8_8_y(int16x8_t samples_lo[4], + int16x8_t samples_hi[4], + int16x8_t filter, + uint16x8_t max) { + int64x2_t sum01 = + aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = + aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int64x2_t sum45 = + aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[2], filter, 0); + sum45 = aom_svdot_lane_s16(sum45, samples_hi[2], filter, 1); + + int64x2_t sum67 = + aom_svdot_lane_s16(vdupq_n_s64(0), samples_lo[3], filter, 0); + sum67 = aom_svdot_lane_s16(sum67, samples_hi[3], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0123, FILTER_BITS), + vqrshrun_n_s32(sum4567, FILTER_BITS)); + return vminq_u16(res, max); +} + +void highbd_convolve_y_sr_8tap_sve2(const uint16_t *src, ptrdiff_t src_stride, + uint16_t *dst, ptrdiff_t dst_stride, + int width, int height, + const int16_t *filter_y, int bd) { + assert(w >= 4 && h >= 4); + + const int16x8_t y_filter = vld1q_s16(filter_y); + + uint16x8x3_t merge_block_tbl = vld1q_u16_x3(kDotProdMergeBlockTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000000000000ULL)); + merge_block_tbl.val[0] = vaddq_u16(merge_block_tbl.val[0], correction0); + + uint16x8_t correction1 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL)); + merge_block_tbl.val[1] = vaddq_u16(merge_block_tbl.val[1], correction1); + + uint16x8_t correction2 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100010000ULL)); + merge_block_tbl.val[2] = vaddq_u16(merge_block_tbl.val[2], correction2); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + int16_t *s = (int16_t *)src; + + int16x4_t s0, s1, s2, s3, s4, s5, s6; + load_s16_4x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + do { + int16x4_t s7, s8, s9, s10; + load_s16_4x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[2], s5678[2], s6789[2], s789A[2]; + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_4x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x4_t d0 = highbd_convolve8_4_y(s0123, s4567, y_filter, max); + uint16x4_t d1 = highbd_convolve8_4_y(s1234, s5678, y_filter, max); + uint16x4_t d2 = highbd_convolve8_4_y(s2345, s6789, y_filter, max); + uint16x4_t d3 = highbd_convolve8_4_y(s3456, s789A, y_filter, max); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + + do { + int h = height; + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + + int16x8_t s0, s1, s2, s3, s4, s5, s6; + load_s16_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + do { + int16x8_t s7, s8, s9, s10; + load_s16_8x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[4], s5678[4], s6789[4], s789A[4]; + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_8x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x8_t d0 = highbd_convolve8_8_y(s0123, s4567, y_filter, max); + uint16x8_t d1 = highbd_convolve8_8_y(s1234, s5678, y_filter, max); + uint16x8_t d2 = highbd_convolve8_8_y(s2345, s6789, y_filter, max); + uint16x8_t d3 = highbd_convolve8_8_y(s3456, s789A, y_filter, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s0123[2] = s4567[2]; + s0123[3] = s4567[3]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s1234[2] = s5678[2]; + s1234[3] = s5678[3]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s2345[2] = s6789[2]; + s2345[3] = s6789[3]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s3456[2] = s789A[2]; + s3456[3] = s789A[3]; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +static INLINE uint16x4_t highbd_convolve4_4_y(int16x8_t samples[2], + int16x8_t filter, + uint16x4_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(vdupq_n_s64(0), samples[0], filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(vdupq_n_s64(0), samples[1], filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + uint16x4_t res = vqrshrun_n_s32(sum0123, FILTER_BITS); + return vmin_u16(res, max); +} + +static INLINE uint16x8_t highbd_convolve4_8_y(int16x8_t samples[4], + int16x8_t filter, + uint16x8_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(vdupq_n_s64(0), samples[0], filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(vdupq_n_s64(0), samples[1], filter, 0); + int64x2_t sum45 = aom_svdot_lane_s16(vdupq_n_s64(0), samples[2], filter, 0); + int64x2_t sum67 = aom_svdot_lane_s16(vdupq_n_s64(0), samples[3], filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0123, FILTER_BITS), + vqrshrun_n_s32(sum4567, FILTER_BITS)); + return vminq_u16(res, max); +} + +void highbd_convolve_y_sr_4tap_sve2(const uint16_t *src, ptrdiff_t src_stride, + uint16_t *dst, ptrdiff_t dst_stride, + int width, int height, + const int16_t *filter_y, int bd) { + assert(w >= 4 && h >= 4); + + const int16x8_t y_filter = + vcombine_s16(vld1_s16(filter_y + 2), vdup_n_s16(0)); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + int16_t *s = (int16_t *)src; + + int16x4_t s0, s1, s2; + load_s16_4x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x4_t s3, s4, s5, s6; + load_s16_4x4(s, src_stride, &s3, &s4, &s5, &s6); + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + uint16x4_t d0 = highbd_convolve4_4_y(s0123, y_filter, max); + uint16x4_t d1 = highbd_convolve4_4_y(s1234, y_filter, max); + uint16x4_t d2 = highbd_convolve4_4_y(s2345, y_filter, max); + uint16x4_t d3 = highbd_convolve4_4_y(s3456, y_filter, max); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Shuffle everything up four rows. + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + + do { + int h = height; + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + + int16x8_t s0, s1, s2; + load_s16_8x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x8_t s3, s4, s5, s6; + load_s16_8x4(s, src_stride, &s3, &s4, &s5, &s6); + + // This operation combines a conventional transpose and the sample + // permute required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + uint16x8_t d0 = highbd_convolve4_8_y(s0123, y_filter, max); + uint16x8_t d1 = highbd_convolve4_8_y(s1234, y_filter, max); + uint16x8_t d2 = highbd_convolve4_8_y(s2345, y_filter, max); + uint16x8_t d3 = highbd_convolve4_8_y(s3456, y_filter, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Shuffle everything up four rows. + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +void av1_highbd_convolve_y_sr_sve2(const uint16_t *src, int src_stride, + uint16_t *dst, int dst_stride, int w, int h, + const InterpFilterParams *filter_params_y, + const int subpel_y_qn, int bd) { + if (w == 2 || h == 2) { + av1_highbd_convolve_y_sr_c(src, src_stride, dst, dst_stride, w, h, + filter_params_y, subpel_y_qn, bd); + return; + } + const int y_filter_taps = get_filter_tap(filter_params_y, subpel_y_qn); + + if (y_filter_taps == 6) { + av1_highbd_convolve_y_sr_neon(src, src_stride, dst, dst_stride, w, h, + filter_params_y, subpel_y_qn, bd); + return; + } + + const int vert_offset = filter_params_y->taps / 2 - 1; + const int16_t *y_filter_ptr = av1_get_interp_filter_subpel_kernel( + filter_params_y, subpel_y_qn & SUBPEL_MASK); + + src -= vert_offset * src_stride; + + if (y_filter_taps > 8) { + highbd_convolve_y_sr_12tap_sve2(src, src_stride, dst, dst_stride, w, h, + y_filter_ptr, bd); + return; + } + + if (y_filter_taps == 4) { + highbd_convolve_y_sr_4tap_sve2(src + 2 * src_stride, src_stride, dst, + dst_stride, w, h, y_filter_ptr, bd); + return; + } + + highbd_convolve_y_sr_8tap_sve2(src, src_stride, dst, dst_stride, w, h, + y_filter_ptr, bd); +} + +static INLINE uint16x4_t convolve12_4_2d_h( + int16x8_t s0, int16x8_t s1, int16x8_t filter_0_7, int16x8_t filter_4_11, + const int64x2_t offset, int32x4_t shift, uint16x8x4_t permute_tbl) { + int16x8_t permuted_samples[6]; + permuted_samples[0] = aom_tbl_s16(s0, permute_tbl.val[0]); + permuted_samples[1] = aom_tbl_s16(s0, permute_tbl.val[1]); + permuted_samples[2] = aom_tbl2_s16(s0, s1, permute_tbl.val[2]); + permuted_samples[3] = aom_tbl2_s16(s0, s1, permute_tbl.val[3]); + permuted_samples[4] = aom_tbl_s16(s1, permute_tbl.val[0]); + permuted_samples[5] = aom_tbl_s16(s1, permute_tbl.val[1]); + + int64x2_t sum01 = + aom_svdot_lane_s16(offset, permuted_samples[0], filter_0_7, 0); + sum01 = aom_svdot_lane_s16(sum01, permuted_samples[2], filter_0_7, 1); + sum01 = aom_svdot_lane_s16(sum01, permuted_samples[4], filter_4_11, 1); + + int64x2_t sum23 = + aom_svdot_lane_s16(offset, permuted_samples[1], filter_0_7, 0); + sum23 = aom_svdot_lane_s16(sum23, permuted_samples[3], filter_0_7, 1); + sum23 = aom_svdot_lane_s16(sum23, permuted_samples[5], filter_4_11, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + sum0123 = vqrshlq_s32(sum0123, shift); + return vqmovun_s32(sum0123); +} + +static INLINE uint16x8_t convolve12_8_2d_h(int16x8_t s0, int16x8_t s1, + int16x8_t s2, int16x8_t filter_0_7, + int16x8_t filter_4_11, + int64x2_t offset, int32x4_t shift, + uint16x8x4_t permute_tbl) { + int16x8_t permuted_samples[8]; + permuted_samples[0] = aom_tbl_s16(s0, permute_tbl.val[0]); + permuted_samples[1] = aom_tbl_s16(s0, permute_tbl.val[1]); + permuted_samples[2] = aom_tbl2_s16(s0, s1, permute_tbl.val[2]); + permuted_samples[3] = aom_tbl2_s16(s0, s1, permute_tbl.val[3]); + permuted_samples[4] = aom_tbl_s16(s1, permute_tbl.val[0]); + permuted_samples[5] = aom_tbl_s16(s1, permute_tbl.val[1]); + permuted_samples[6] = aom_tbl2_s16(s1, s2, permute_tbl.val[2]); + permuted_samples[7] = aom_tbl2_s16(s1, s2, permute_tbl.val[3]); + + int64x2_t sum01 = + aom_svdot_lane_s16(offset, permuted_samples[0], filter_0_7, 0); + sum01 = aom_svdot_lane_s16(sum01, permuted_samples[2], filter_0_7, 1); + sum01 = aom_svdot_lane_s16(sum01, permuted_samples[4], filter_4_11, 1); + + int64x2_t sum23 = + aom_svdot_lane_s16(offset, permuted_samples[1], filter_0_7, 0); + sum23 = aom_svdot_lane_s16(sum23, permuted_samples[3], filter_0_7, 1); + sum23 = aom_svdot_lane_s16(sum23, permuted_samples[5], filter_4_11, 1); + + int64x2_t sum45 = + aom_svdot_lane_s16(offset, permuted_samples[2], filter_0_7, 0); + sum45 = aom_svdot_lane_s16(sum45, permuted_samples[4], filter_0_7, 1); + sum45 = aom_svdot_lane_s16(sum45, permuted_samples[6], filter_4_11, 1); + + int64x2_t sum67 = + aom_svdot_lane_s16(offset, permuted_samples[3], filter_0_7, 0); + sum67 = aom_svdot_lane_s16(sum67, permuted_samples[5], filter_0_7, 1); + sum67 = aom_svdot_lane_s16(sum67, permuted_samples[7], filter_4_11, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + sum0123 = vqrshlq_s32(sum0123, shift); + sum4567 = vqrshlq_s32(sum4567, shift); + + return vcombine_u16(vqmovun_s32(sum0123), vqmovun_s32(sum4567)); +} + +static INLINE void highbd_convolve_2d_sr_horiz_12tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr, + ConvolveParams *conv_params, const int x_offset) { + const int64x2_t offset = vdupq_n_s64(x_offset); + const int32x4_t shift = vdupq_n_s32(-conv_params->round_0); + + const int16x8_t y_filter_0_7 = vld1q_s16(y_filter_ptr); + const int16x8_t y_filter_4_11 = vld1q_s16(y_filter_ptr + 4); + + uint16x8x4_t permute_tbl = vld1q_u16_x4(kDotProdTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = vreinterpretq_u16_u64(vcombine_u64( + vdup_n_u64(0), vdup_n_u64(svcnth() * 0x0001000000000000ULL))); + permute_tbl.val[2] = vaddq_u16(permute_tbl.val[2], correction0); + + uint16x8_t correction1 = vreinterpretq_u16_u64( + vcombine_u64(vdup_n_u64(svcnth() * 0x0001000100000000ULL), + vdup_n_u64(svcnth() * 0x0001000100010000ULL))); + permute_tbl.val[3] = vaddq_u16(permute_tbl.val[3], correction1); + + if (width == 4) { + const int16_t *s = (const int16_t *)src; + + do { + int16x8_t s0, s1, s2, s3, s4, s5, s6, s7; + load_s16_8x4(s, src_stride, &s0, &s2, &s4, &s6); + load_s16_8x4(s + 8, src_stride, &s1, &s3, &s5, &s7); + + uint16x4_t d0 = convolve12_4_2d_h(s0, s1, y_filter_0_7, y_filter_4_11, + offset, shift, permute_tbl); + uint16x4_t d1 = convolve12_4_2d_h(s2, s3, y_filter_0_7, y_filter_4_11, + offset, shift, permute_tbl); + uint16x4_t d2 = convolve12_4_2d_h(s4, s5, y_filter_0_7, y_filter_4_11, + offset, shift, permute_tbl); + uint16x4_t d3 = convolve12_4_2d_h(s6, s7, y_filter_0_7, y_filter_4_11, + offset, shift, permute_tbl); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + dst += 4 * dst_stride; + s += 4 * src_stride; + height -= 4; + } while (height > 0); + } else { + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; + load_s16_8x4(s, src_stride, &s0, &s3, &s6, &s9); + load_s16_8x4(s + 8, src_stride, &s1, &s4, &s7, &s10); + load_s16_8x4(s + 16, src_stride, &s2, &s5, &s8, &s11); + + uint16x8_t d0 = + convolve12_8_2d_h(s0, s1, s2, y_filter_0_7, y_filter_4_11, offset, + shift, permute_tbl); + uint16x8_t d1 = + convolve12_8_2d_h(s3, s4, s5, y_filter_0_7, y_filter_4_11, offset, + shift, permute_tbl); + uint16x8_t d2 = + convolve12_8_2d_h(s6, s7, s8, y_filter_0_7, y_filter_4_11, offset, + shift, permute_tbl); + uint16x8_t d3 = + convolve12_8_2d_h(s9, s10, s11, y_filter_0_7, y_filter_4_11, offset, + shift, permute_tbl); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 0); + } +} + +static INLINE uint16x8_t convolve8_8_2d_h(int16x8_t s0[8], int16x8_t filter, + int64x2_t offset, int32x4_t shift) { + int64x2_t sum[8]; + sum[0] = aom_sdotq_s16(offset, s0[0], filter); + sum[1] = aom_sdotq_s16(offset, s0[1], filter); + sum[2] = aom_sdotq_s16(offset, s0[2], filter); + sum[3] = aom_sdotq_s16(offset, s0[3], filter); + sum[4] = aom_sdotq_s16(offset, s0[4], filter); + sum[5] = aom_sdotq_s16(offset, s0[5], filter); + sum[6] = aom_sdotq_s16(offset, s0[6], filter); + sum[7] = aom_sdotq_s16(offset, s0[7], filter); + + sum[0] = vpaddq_s64(sum[0], sum[1]); + sum[2] = vpaddq_s64(sum[2], sum[3]); + sum[4] = vpaddq_s64(sum[4], sum[5]); + sum[6] = vpaddq_s64(sum[6], sum[7]); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum[0]), vmovn_s64(sum[2])); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum[4]), vmovn_s64(sum[6])); + + sum0123 = vqrshlq_s32(sum0123, shift); + sum4567 = vqrshlq_s32(sum4567, shift); + + return vcombine_u16(vqmovun_s32(sum0123), vqmovun_s32(sum4567)); +} + +static INLINE void highbd_convolve_2d_sr_horiz_8tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr, + ConvolveParams *conv_params, const int x_offset) { + const int64x2_t offset = vdupq_n_s64(x_offset); + const int64x2_t offset_lo = vcombine_s64(vget_low_s64(offset), vdup_n_s64(0)); + const int32x4_t shift = vdupq_n_s32(-conv_params->round_0); + + const int16x8_t filter = vld1q_s16(y_filter_ptr); + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[8], s1[8], s2[8], s3[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], + &s2[4], &s2[5], &s2[6], &s2[7]); + load_s16_8x8(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3], + &s3[4], &s3[5], &s3[6], &s3[7]); + + uint16x8_t d0 = convolve8_8_2d_h(s0, filter, offset_lo, shift); + uint16x8_t d1 = convolve8_8_2d_h(s1, filter, offset_lo, shift); + uint16x8_t d2 = convolve8_8_2d_h(s2, filter, offset_lo, shift); + uint16x8_t d3 = convolve8_8_2d_h(s3, filter, offset_lo, shift); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 0); +} + +static INLINE uint16x4_t convolve4_4_2d_h(int16x8_t s0, int16x8_t filter, + int64x2_t offset, int32x4_t shift, + uint16x8x2_t permute_tbl) { + int16x8_t permuted_samples0 = aom_tbl_s16(s0, permute_tbl.val[0]); + int16x8_t permuted_samples1 = aom_tbl_s16(s0, permute_tbl.val[1]); + + int64x2_t sum01 = aom_svdot_lane_s16(offset, permuted_samples0, filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(offset, permuted_samples1, filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + sum0123 = vqrshlq_s32(sum0123, shift); + return vqmovun_s32(sum0123); +} + +static INLINE uint16x8_t convolve4_8_2d_h(int16x8_t s0[8], int16x8_t filter, + int64x2_t offset, int32x4_t shift, + uint16x8_t tbl) { + int64x2_t sum04 = aom_svdot_lane_s16(offset, s0[0], filter, 0); + int64x2_t sum15 = aom_svdot_lane_s16(offset, s0[1], filter, 0); + int64x2_t sum26 = aom_svdot_lane_s16(offset, s0[2], filter, 0); + int64x2_t sum37 = aom_svdot_lane_s16(offset, s0[3], filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum04), vmovn_s64(sum15)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum26), vmovn_s64(sum37)); + + sum0123 = vqrshlq_s32(sum0123, shift); + sum4567 = vqrshlq_s32(sum4567, shift); + + uint16x8_t res = vcombine_u16(vqmovun_s32(sum0123), vqmovun_s32(sum4567)); + return aom_tbl_u16(res, tbl); +} + +static INLINE void highbd_convolve_2d_sr_horiz_4tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *x_filter_ptr, + ConvolveParams *conv_params, const int x_offset) { + const int64x2_t offset = vdupq_n_s64(x_offset); + const int32x4_t shift = vdupq_n_s32(-conv_params->round_0); + + const int16x4_t x_filter = vld1_s16(x_filter_ptr + 2); + const int16x8_t filter = vcombine_s16(x_filter, vdup_n_s16(0)); + + if (width == 4) { + const int16_t *s = (const int16_t *)(src); + + uint16x8x2_t permute_tbl = vld1q_u16_x2(kDotProdTbl); + + do { + int16x8_t s0, s1, s2, s3; + load_s16_8x4(s, src_stride, &s0, &s1, &s2, &s3); + + uint16x4_t d0 = convolve4_4_2d_h(s0, filter, offset, shift, permute_tbl); + uint16x4_t d1 = convolve4_4_2d_h(s1, filter, offset, shift, permute_tbl); + uint16x4_t d2 = convolve4_4_2d_h(s2, filter, offset, shift, permute_tbl); + uint16x4_t d3 = convolve4_4_2d_h(s3, filter, offset, shift, permute_tbl); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 0); + } else { + uint16x8_t idx = vld1q_u16(kDeinterleaveTbl); + + do { + const int16_t *s = (const int16_t *)(src); + uint16_t *d = dst; + int w = width; + + do { + int16x8_t s0[8], s1[8], s2[8], s3[8]; + load_s16_8x8(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7]); + load_s16_8x8(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7]); + load_s16_8x8(s + 2 * src_stride, 1, &s2[0], &s2[1], &s2[2], &s2[3], + &s2[4], &s2[5], &s2[6], &s2[7]); + load_s16_8x8(s + 3 * src_stride, 1, &s3[0], &s3[1], &s3[2], &s3[3], + &s3[4], &s3[5], &s3[6], &s3[7]); + + uint16x8_t d0 = convolve4_8_2d_h(s0, filter, offset, shift, idx); + uint16x8_t d1 = convolve4_8_2d_h(s1, filter, offset, shift, idx); + uint16x8_t d2 = convolve4_8_2d_h(s2, filter, offset, shift, idx); + uint16x8_t d3 = convolve4_8_2d_h(s3, filter, offset, shift, idx); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s += 8; + d += 8; + w -= 8; + } while (w != 0); + src += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height > 0); + } +} + +static INLINE uint16x4_t highbd_convolve12_4_2d_v( + int16x8_t s0[2], int16x8_t s1[2], int16x8_t s2[2], int16x8_t filter_0_7, + int16x8_t filter_4_11, int32x4_t shift, int64x2_t offset, uint16x4_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, s0[0], filter_0_7, 0); + sum01 = aom_svdot_lane_s16(sum01, s1[0], filter_0_7, 1); + sum01 = aom_svdot_lane_s16(sum01, s2[0], filter_4_11, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, s0[1], filter_0_7, 0); + sum23 = aom_svdot_lane_s16(sum23, s1[1], filter_0_7, 1); + sum23 = aom_svdot_lane_s16(sum23, s2[1], filter_4_11, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + sum0123 = vshlq_s32(sum0123, shift); + + uint16x4_t res = vqmovun_s32(sum0123); + + return vmin_u16(res, max); +} + +static INLINE void highbd_convolve_2d_sr_vert_12tap_sve2( + const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, + int width, int height, const int16_t *y_filter_ptr, + ConvolveParams *conv_params, int bd, const int y_offset) { + const int64x2_t offset = vdupq_n_s64(y_offset); + const int32x4_t shift = vdupq_n_s32(-conv_params->round_1); + + const int16x8_t y_filter_0_7 = vld1q_s16(y_filter_ptr); + const int16x8_t y_filter_4_11 = vld1q_s16(y_filter_ptr + 4); + + uint16x8x3_t merge_block_tbl = vld1q_u16_x3(kDotProdMergeBlockTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000000000000ULL)); + merge_block_tbl.val[0] = vaddq_u16(merge_block_tbl.val[0], correction0); + + uint16x8_t correction1 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL)); + merge_block_tbl.val[1] = vaddq_u16(merge_block_tbl.val[1], correction1); + + uint16x8_t correction2 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100010000ULL)); + merge_block_tbl.val[2] = vaddq_u16(merge_block_tbl.val[2], correction2); + + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + + do { + int16_t *s = (int16_t *)src; + uint16_t *d = (uint16_t *)dst; + int h = height; + + int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA; + load_s16_4x11(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7, &s8, + &s9, &sA); + s += 11 * src_stride; + + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2], s4567[2], s5678[2], + s6789[2], s789A[2]; + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + transpose_concat_4x4(s4, s5, s6, s7, s4567); + transpose_concat_4x4(s5, s6, s7, s8, s5678); + transpose_concat_4x4(s6, s7, s8, s9, s6789); + transpose_concat_4x4(s7, s8, s9, sA, s789A); + + do { + int16x4_t sB, sC, sD, sE; + load_s16_4x4(s, src_stride, &sB, &sC, &sD, &sE); + + int16x8_t s89AB[2], s9ABC[2], sABCD[2], sBCDE[2]; + transpose_concat_4x4(sB, sC, sD, sE, sBCDE); + + // Use the above transpose and reuse data from the previous loop to get + // the rest. + aom_tbl2x2_s16(s789A, sBCDE, merge_block_tbl.val[0], s89AB); + aom_tbl2x2_s16(s789A, sBCDE, merge_block_tbl.val[1], s9ABC); + aom_tbl2x2_s16(s789A, sBCDE, merge_block_tbl.val[2], sABCD); + + uint16x4_t d0 = highbd_convolve12_4_2d_v( + s0123, s4567, s89AB, y_filter_0_7, y_filter_4_11, shift, offset, max); + uint16x4_t d1 = highbd_convolve12_4_2d_v( + s1234, s5678, s9ABC, y_filter_0_7, y_filter_4_11, shift, offset, max); + uint16x4_t d2 = highbd_convolve12_4_2d_v( + s2345, s6789, sABCD, y_filter_0_7, y_filter_4_11, shift, offset, max); + uint16x4_t d3 = highbd_convolve12_4_2d_v( + s3456, s789A, sBCDE, y_filter_0_7, y_filter_4_11, shift, offset, max); + + store_u16_4x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s4567[0] = s89AB[0]; + s4567[1] = s89AB[1]; + s5678[0] = s9ABC[0]; + s5678[1] = s9ABC[1]; + s6789[0] = sABCD[0]; + s6789[1] = sABCD[1]; + s789A[0] = sBCDE[0]; + s789A[1] = sBCDE[1]; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 4; + dst += 4; + width -= 4; + } while (width != 0); +} + +static INLINE uint16x4_t highbd_convolve8_4_2d_v( + int16x8_t samples_lo[2], int16x8_t samples_hi[2], int16x8_t filter, + int32x4_t shift, int64x2_t offset, uint16x4_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + sum0123 = vshlq_s32(sum0123, shift); + + uint16x4_t res = vqmovun_s32(sum0123); + return vmin_u16(res, max); +} + +static INLINE uint16x8_t highbd_convolve8_8_2d_v( + int16x8_t samples_lo[4], int16x8_t samples_hi[4], int16x8_t filter, + int32x4_t shift, int64x2_t offset, uint16x8_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples_lo[0], filter, 0); + sum01 = aom_svdot_lane_s16(sum01, samples_hi[0], filter, 1); + + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples_lo[1], filter, 0); + sum23 = aom_svdot_lane_s16(sum23, samples_hi[1], filter, 1); + + int64x2_t sum45 = aom_svdot_lane_s16(offset, samples_lo[2], filter, 0); + sum45 = aom_svdot_lane_s16(sum45, samples_hi[2], filter, 1); + + int64x2_t sum67 = aom_svdot_lane_s16(offset, samples_lo[3], filter, 0); + sum67 = aom_svdot_lane_s16(sum67, samples_hi[3], filter, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + sum0123 = vshlq_s32(sum0123, shift); + sum4567 = vshlq_s32(sum4567, shift); + + uint16x8_t res = vcombine_u16(vqmovun_s32(sum0123), vqmovun_s32(sum4567)); + return vminq_u16(res, max); +} + +void highbd_convolve_2d_sr_vert_8tap_sve2(const uint16_t *src, + ptrdiff_t src_stride, uint16_t *dst, + ptrdiff_t dst_stride, int width, + int height, const int16_t *filter_y, + ConvolveParams *conv_params, int bd, + const int y_offset) { + assert(w >= 4 && h >= 4); + const int64x2_t offset = vdupq_n_s64(y_offset); + const int32x4_t shift = vdupq_n_s32(-conv_params->round_1); + const int16x8_t y_filter = vld1q_s16(filter_y); + + uint16x8x3_t merge_block_tbl = vld1q_u16_x3(kDotProdMergeBlockTbl); + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + uint16x8_t correction0 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000000000000ULL)); + merge_block_tbl.val[0] = vaddq_u16(merge_block_tbl.val[0], correction0); + + uint16x8_t correction1 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL)); + merge_block_tbl.val[1] = vaddq_u16(merge_block_tbl.val[1], correction1); + + uint16x8_t correction2 = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100010000ULL)); + merge_block_tbl.val[2] = vaddq_u16(merge_block_tbl.val[2], correction2); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + int16_t *s = (int16_t *)src; + + int16x4_t s0, s1, s2, s3, s4, s5, s6; + load_s16_4x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + do { + int16x4_t s7, s8, s9, s10; + load_s16_4x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[2], s5678[2], s6789[2], s789A[2]; + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_4x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x2_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x4_t d0 = + highbd_convolve8_4_2d_v(s0123, s4567, y_filter, shift, offset, max); + uint16x4_t d1 = + highbd_convolve8_4_2d_v(s1234, s5678, y_filter, shift, offset, max); + uint16x4_t d2 = + highbd_convolve8_4_2d_v(s2345, s6789, y_filter, shift, offset, max); + uint16x4_t d3 = + highbd_convolve8_4_2d_v(s3456, s789A, y_filter, shift, offset, max); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + + do { + int h = height; + int16_t *s = (int16_t *)src; + uint16_t *d = dst; + + int16x8_t s0, s1, s2, s3, s4, s5, s6; + load_s16_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); + s += 7 * src_stride; + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + do { + int16x8_t s7, s8, s9, s10; + load_s16_8x4(s, src_stride, &s7, &s8, &s9, &s10); + + int16x8_t s4567[4], s5678[4], s6789[4], s789A[4]; + // Transpose and shuffle the 4 lines that were loaded. + transpose_concat_8x4(s7, s8, s9, s10, s789A); + + // Merge new data into block from previous iteration. + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[0], s4567); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[1], s5678); + aom_tbl2x4_s16(s3456, s789A, merge_block_tbl.val[2], s6789); + + uint16x8_t d0 = + highbd_convolve8_8_2d_v(s0123, s4567, y_filter, shift, offset, max); + uint16x8_t d1 = + highbd_convolve8_8_2d_v(s1234, s5678, y_filter, shift, offset, max); + uint16x8_t d2 = + highbd_convolve8_8_2d_v(s2345, s6789, y_filter, shift, offset, max); + uint16x8_t d3 = + highbd_convolve8_8_2d_v(s3456, s789A, y_filter, shift, offset, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - re-using as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s0123[2] = s4567[2]; + s0123[3] = s4567[3]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s1234[2] = s5678[2]; + s1234[3] = s5678[3]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s2345[2] = s6789[2]; + s2345[3] = s6789[3]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s3456[2] = s789A[2]; + s3456[3] = s789A[3]; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +static INLINE uint16x4_t highbd_convolve4_4_2d_v(int16x8_t samples[2], + int16x8_t filter, + int32x4_t shift, + int64x2_t offset, + uint16x4_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples[0], filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples[1], filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + sum0123 = vshlq_s32(sum0123, shift); + + uint16x4_t res = vqmovun_s32(sum0123); + return vmin_u16(res, max); +} + +static INLINE uint16x8_t highbd_convolve4_8_2d_v(int16x8_t samples[4], + int16x8_t filter, + int32x4_t shift, + int64x2_t offset, + uint16x8_t max) { + int64x2_t sum01 = aom_svdot_lane_s16(offset, samples[0], filter, 0); + int64x2_t sum23 = aom_svdot_lane_s16(offset, samples[1], filter, 0); + int64x2_t sum45 = aom_svdot_lane_s16(offset, samples[2], filter, 0); + int64x2_t sum67 = aom_svdot_lane_s16(offset, samples[3], filter, 0); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + sum0123 = vshlq_s32(sum0123, shift); + sum4567 = vshlq_s32(sum4567, shift); + + uint16x8_t res = vcombine_u16(vqmovun_s32(sum0123), vqmovun_s32(sum4567)); + return vminq_u16(res, max); +} + +void highbd_convolve_2d_sr_vert_4tap_sve2(const uint16_t *src, + ptrdiff_t src_stride, uint16_t *dst, + ptrdiff_t dst_stride, int width, + int height, const int16_t *filter_y, + ConvolveParams *conv_params, int bd, + const int y_offset) { + assert(w >= 4 && h >= 4); + const int64x2_t offset = vdupq_n_s64(y_offset); + const int32x4_t shift = vdupq_n_s32(-conv_params->round_1); + + const int16x8_t y_filter = + vcombine_s16(vld1_s16(filter_y + 2), vdup_n_s16(0)); + + if (width == 4) { + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + int16_t *s = (int16_t *)(src); + + int16x4_t s0, s1, s2; + load_s16_4x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x4_t s3, s4, s5, s6; + load_s16_4x4(s, src_stride, &s3, &s4, &s5, &s6); + + // This operation combines a conventional transpose and the sample permute + // required before computing the dot product. + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; + transpose_concat_4x4(s0, s1, s2, s3, s0123); + transpose_concat_4x4(s1, s2, s3, s4, s1234); + transpose_concat_4x4(s2, s3, s4, s5, s2345); + transpose_concat_4x4(s3, s4, s5, s6, s3456); + + uint16x4_t d0 = + highbd_convolve4_4_2d_v(s0123, y_filter, shift, offset, max); + uint16x4_t d1 = + highbd_convolve4_4_2d_v(s1234, y_filter, shift, offset, max); + uint16x4_t d2 = + highbd_convolve4_4_2d_v(s2345, y_filter, shift, offset, max); + uint16x4_t d3 = + highbd_convolve4_4_2d_v(s3456, y_filter, shift, offset, max); + + store_u16_4x4(dst, dst_stride, d0, d1, d2, d3); + + // Shuffle everything up four rows. + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + dst += 4 * dst_stride; + height -= 4; + } while (height != 0); + } else { + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + + do { + int h = height; + int16_t *s = (int16_t *)(src); + uint16_t *d = dst; + + int16x8_t s0, s1, s2; + load_s16_8x3(s, src_stride, &s0, &s1, &s2); + s += 3 * src_stride; + + do { + int16x8_t s3, s4, s5, s6; + load_s16_8x4(s, src_stride, &s3, &s4, &s5, &s6); + + // This operation combines a conventional transpose and the sample + // permute required before computing the dot product. + int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; + transpose_concat_8x4(s0, s1, s2, s3, s0123); + transpose_concat_8x4(s1, s2, s3, s4, s1234); + transpose_concat_8x4(s2, s3, s4, s5, s2345); + transpose_concat_8x4(s3, s4, s5, s6, s3456); + + uint16x8_t d0 = + highbd_convolve4_8_2d_v(s0123, y_filter, shift, offset, max); + uint16x8_t d1 = + highbd_convolve4_8_2d_v(s1234, y_filter, shift, offset, max); + uint16x8_t d2 = + highbd_convolve4_8_2d_v(s2345, y_filter, shift, offset, max); + uint16x8_t d3 = + highbd_convolve4_8_2d_v(s3456, y_filter, shift, offset, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + // Shuffle everything up four rows. + s0 = s4; + s1 = s5; + s2 = s6; + + s += 4 * src_stride; + d += 4 * dst_stride; + h -= 4; + } while (h != 0); + src += 8; + dst += 8; + width -= 8; + } while (width != 0); + } +} + +void av1_highbd_convolve_2d_sr_sve2(const uint16_t *src, int src_stride, + uint16_t *dst, int dst_stride, int w, int h, + const InterpFilterParams *filter_params_x, + const InterpFilterParams *filter_params_y, + const int subpel_x_qn, + const int subpel_y_qn, + ConvolveParams *conv_params, int bd) { + if (w == 2 || h == 2) { + av1_highbd_convolve_2d_sr_c(src, src_stride, dst, dst_stride, w, h, + filter_params_x, filter_params_y, subpel_x_qn, + subpel_y_qn, conv_params, bd); + return; + } + + DECLARE_ALIGNED(16, uint16_t, + im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * MAX_SB_SIZE]); + const int x_filter_taps = get_filter_tap(filter_params_x, subpel_x_qn); + const int y_filter_taps = get_filter_tap(filter_params_y, subpel_y_qn); + + if (x_filter_taps == 6 || y_filter_taps == 6) { + av1_highbd_convolve_2d_sr_neon(src, src_stride, dst, dst_stride, w, h, + filter_params_x, filter_params_y, + subpel_x_qn, subpel_y_qn, conv_params, bd); + return; + } + + const int clamped_x_taps = x_filter_taps < 4 ? 4 : x_filter_taps; + const int clamped_y_taps = y_filter_taps < 4 ? 4 : y_filter_taps; + + const int im_stride = MAX_SB_SIZE; + const int vert_offset = clamped_y_taps / 2 - 1; + const int horiz_offset = clamped_x_taps / 2 - 1; + const int x_offset = (1 << (bd + FILTER_BITS - 1)); + const int y_offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; + // The extra shim of (1 << (conv_params->round_1 - 1)) allows us to do a + // simple shift left instead of a rounding saturating shift left. + const int y_offset = + (1 << (conv_params->round_1 - 1)) - (1 << (y_offset_bits - 1)); + + const uint16_t *src_ptr = src - vert_offset * src_stride - horiz_offset; + + const int16_t *x_filter_ptr = av1_get_interp_filter_subpel_kernel( + filter_params_x, subpel_x_qn & SUBPEL_MASK); + const int16_t *y_filter_ptr = av1_get_interp_filter_subpel_kernel( + filter_params_y, subpel_y_qn & SUBPEL_MASK); + const int im_h = h + clamped_y_taps - 1; + + if (x_filter_taps > 8) { + highbd_convolve_2d_sr_horiz_12tap_sve2(src_ptr, src_stride, im_block, + im_stride, w, im_h, x_filter_ptr, + conv_params, x_offset); + + highbd_convolve_2d_sr_vert_12tap_sve2(im_block, im_stride, dst, dst_stride, + w, h, y_filter_ptr, conv_params, bd, + y_offset); + return; + } + + if (x_filter_taps <= 4) { + highbd_convolve_2d_sr_horiz_4tap_sve2(src_ptr, src_stride, im_block, + im_stride, w, im_h, x_filter_ptr, + conv_params, x_offset); + } else { + highbd_convolve_2d_sr_horiz_8tap_sve2(src_ptr, src_stride, im_block, + im_stride, w, im_h, x_filter_ptr, + conv_params, x_offset); + } + + if (y_filter_taps <= 4) { + highbd_convolve_2d_sr_vert_4tap_sve2(im_block, im_stride, dst, dst_stride, + w, h, y_filter_ptr, conv_params, bd, + y_offset); + } else { + highbd_convolve_2d_sr_vert_8tap_sve2(im_block, im_stride, dst, dst_stride, + w, h, y_filter_ptr, conv_params, bd, + y_offset); + } +} diff --git a/third_party/aom/av1/common/arm/highbd_convolve_sve2.h b/third_party/aom/av1/common/arm/highbd_convolve_sve2.h new file mode 100644 index 0000000000..05e23deef4 --- /dev/null +++ b/third_party/aom/av1/common/arm/highbd_convolve_sve2.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#ifndef AOM_AV1_COMMON_ARM_HIGHBD_CONVOLVE_SVE2_H_ +#define AOM_AV1_COMMON_ARM_HIGHBD_CONVOLVE_SVE2_H_ + +#include + +#include "aom_dsp/arm/aom_neon_sve2_bridge.h" + +// clang-format off +DECLARE_ALIGNED(16, static const uint16_t, kDotProdMergeBlockTbl[24]) = { + // Shift left and insert new last column in transposed 4x4 block. + 1, 2, 3, 0, 5, 6, 7, 4, + // Shift left and insert two new columns in transposed 4x4 block. + 2, 3, 0, 1, 6, 7, 4, 5, + // Shift left and insert three new columns in transposed 4x4 block. + 3, 0, 1, 2, 7, 4, 5, 6, +}; +// clang-format on + +static INLINE void transpose_concat_4x4(int16x4_t s0, int16x4_t s1, + int16x4_t s2, int16x4_t s3, + int16x8_t res[2]) { + // Transpose 16-bit elements and concatenate result rows as follows: + // s0: 00, 01, 02, 03 + // s1: 10, 11, 12, 13 + // s2: 20, 21, 22, 23 + // s3: 30, 31, 32, 33 + // + // res[0]: 00 10 20 30 01 11 21 31 + // res[1]: 02 12 22 32 03 13 23 33 + + int16x8_t s0q = vcombine_s16(s0, vdup_n_s16(0)); + int16x8_t s1q = vcombine_s16(s1, vdup_n_s16(0)); + int16x8_t s2q = vcombine_s16(s2, vdup_n_s16(0)); + int16x8_t s3q = vcombine_s16(s3, vdup_n_s16(0)); + + int32x4_t s01 = vreinterpretq_s32_s16(vzip1q_s16(s0q, s1q)); + int32x4_t s23 = vreinterpretq_s32_s16(vzip1q_s16(s2q, s3q)); + + int32x4x2_t s0123 = vzipq_s32(s01, s23); + + res[0] = vreinterpretq_s16_s32(s0123.val[0]); + res[1] = vreinterpretq_s16_s32(s0123.val[1]); +} + +static INLINE void transpose_concat_8x4(int16x8_t s0, int16x8_t s1, + int16x8_t s2, int16x8_t s3, + int16x8_t res[4]) { + // Transpose 16-bit elements and concatenate result rows as follows: + // s0: 00, 01, 02, 03, 04, 05, 06, 07 + // s1: 10, 11, 12, 13, 14, 15, 16, 17 + // s2: 20, 21, 22, 23, 24, 25, 26, 27 + // s3: 30, 31, 32, 33, 34, 35, 36, 37 + // + // res[0]: 00 10 20 30 01 11 21 31 + // res[1]: 02 12 22 32 03 13 23 33 + // res[2]: 04 14 24 34 05 15 25 35 + // res[3]: 06 16 26 36 07 17 27 37 + + int16x8x2_t tr01_16 = vzipq_s16(s0, s1); + int16x8x2_t tr23_16 = vzipq_s16(s2, s3); + int32x4x2_t tr01_32 = vzipq_s32(vreinterpretq_s32_s16(tr01_16.val[0]), + vreinterpretq_s32_s16(tr23_16.val[0])); + int32x4x2_t tr23_32 = vzipq_s32(vreinterpretq_s32_s16(tr01_16.val[1]), + vreinterpretq_s32_s16(tr23_16.val[1])); + + res[0] = vreinterpretq_s16_s32(tr01_32.val[0]); + res[1] = vreinterpretq_s16_s32(tr01_32.val[1]); + res[2] = vreinterpretq_s16_s32(tr23_32.val[0]); + res[3] = vreinterpretq_s16_s32(tr23_32.val[1]); +} + +static INLINE void aom_tbl2x4_s16(int16x8_t t0[4], int16x8_t t1[4], + uint16x8_t tbl, int16x8_t res[4]) { + res[0] = aom_tbl2_s16(t0[0], t1[0], tbl); + res[1] = aom_tbl2_s16(t0[1], t1[1], tbl); + res[2] = aom_tbl2_s16(t0[2], t1[2], tbl); + res[3] = aom_tbl2_s16(t0[3], t1[3], tbl); +} + +static INLINE void aom_tbl2x2_s16(int16x8_t t0[2], int16x8_t t1[2], + uint16x8_t tbl, int16x8_t res[2]) { + res[0] = aom_tbl2_s16(t0[0], t1[0], tbl); + res[1] = aom_tbl2_s16(t0[1], t1[1], tbl); +} + +#endif // AOM_AV1_COMMON_ARM_HIGHBD_CONVOLVE_SVE2_H_ diff --git a/third_party/aom/av1/common/arm/highbd_warp_plane_neon.c b/third_party/aom/av1/common/arm/highbd_warp_plane_neon.c index c6f1e3ad92..89647bc921 100644 --- a/third_party/aom/av1/common/arm/highbd_warp_plane_neon.c +++ b/third_party/aom/av1/common/arm/highbd_warp_plane_neon.c @@ -23,8 +23,8 @@ #include "config/av1_rtcd.h" #include "highbd_warp_plane_neon.h" -static INLINE int16x8_t highbd_horizontal_filter_4x1_f4(uint16x8x2_t in, int bd, - int sx, int alpha) { +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_4x1_f4(uint16x8x2_t in, int bd, int sx, int alpha) { int16x8_t f[4]; load_filters_4(f, sx, alpha); @@ -57,8 +57,8 @@ static INLINE int16x8_t highbd_horizontal_filter_4x1_f4(uint16x8x2_t in, int bd, return vcombine_s16(vmovn_s32(res), vdup_n_s16(0)); } -static INLINE int16x8_t highbd_horizontal_filter_8x1_f8(uint16x8x2_t in, int bd, - int sx, int alpha) { +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_8x1_f8(uint16x8x2_t in, int bd, int sx, int alpha) { int16x8_t f[8]; load_filters_8(f, sx, alpha); @@ -111,8 +111,8 @@ static INLINE int16x8_t highbd_horizontal_filter_8x1_f8(uint16x8x2_t in, int bd, return vcombine_s16(vmovn_s32(res0), vmovn_s32(res1)); } -static INLINE int16x8_t highbd_horizontal_filter_4x1_f1(uint16x8x2_t in, int bd, - int sx) { +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_4x1_f1(uint16x8x2_t in, int bd, int sx) { int16x8_t f = load_filters_1(sx); int16x8_t rv0 = vextq_s16(vreinterpretq_s16_u16(in.val[0]), @@ -144,8 +144,8 @@ static INLINE int16x8_t highbd_horizontal_filter_4x1_f1(uint16x8x2_t in, int bd, return vcombine_s16(vmovn_s32(res), vdup_n_s16(0)); } -static INLINE int16x8_t highbd_horizontal_filter_8x1_f1(uint16x8x2_t in, int bd, - int sx) { +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_8x1_f1(uint16x8x2_t in, int bd, int sx) { int16x8_t f = load_filters_1(sx); int16x8_t rv0 = vextq_s16(vreinterpretq_s16_u16(in.val[0]), @@ -197,7 +197,8 @@ static INLINE int16x8_t highbd_horizontal_filter_8x1_f1(uint16x8x2_t in, int bd, return vcombine_s16(vmovn_s32(res0), vmovn_s32(res1)); } -static INLINE int32x4_t vertical_filter_4x1_f1(const int16x8_t *tmp, int sy) { +static AOM_FORCE_INLINE int32x4_t vertical_filter_4x1_f1(const int16x8_t *tmp, + int sy) { const int16x8_t f = load_filters_1(sy); const int16x4_t f0123 = vget_low_s16(f); const int16x4_t f4567 = vget_high_s16(f); @@ -213,7 +214,8 @@ static INLINE int32x4_t vertical_filter_4x1_f1(const int16x8_t *tmp, int sy) { return m0123; } -static INLINE int32x4x2_t vertical_filter_8x1_f1(const int16x8_t *tmp, int sy) { +static AOM_FORCE_INLINE int32x4x2_t vertical_filter_8x1_f1(const int16x8_t *tmp, + int sy) { const int16x8_t f = load_filters_1(sy); const int16x4_t f0123 = vget_low_s16(f); const int16x4_t f4567 = vget_high_s16(f); @@ -238,8 +240,8 @@ static INLINE int32x4x2_t vertical_filter_8x1_f1(const int16x8_t *tmp, int sy) { return (int32x4x2_t){ { m0123, m4567 } }; } -static INLINE int32x4_t vertical_filter_4x1_f4(const int16x8_t *tmp, int sy, - int gamma) { +static AOM_FORCE_INLINE int32x4_t vertical_filter_4x1_f4(const int16x8_t *tmp, + int sy, int gamma) { int16x8_t s0, s1, s2, s3; transpose_elems_s16_4x8( vget_low_s16(tmp[0]), vget_low_s16(tmp[1]), vget_low_s16(tmp[2]), @@ -262,8 +264,8 @@ static INLINE int32x4_t vertical_filter_4x1_f4(const int16x8_t *tmp, int sy, return horizontal_add_4d_s32x4(m0123); } -static INLINE int32x4x2_t vertical_filter_8x1_f8(const int16x8_t *tmp, int sy, - int gamma) { +static AOM_FORCE_INLINE int32x4x2_t vertical_filter_8x1_f8(const int16x8_t *tmp, + int sy, int gamma) { int16x8_t s0 = tmp[0]; int16x8_t s1 = tmp[1]; int16x8_t s2 = tmp[2]; diff --git a/third_party/aom/av1/common/arm/highbd_warp_plane_neon.h b/third_party/aom/av1/common/arm/highbd_warp_plane_neon.h index 3b8982898e..48af4a707b 100644 --- a/third_party/aom/av1/common/arm/highbd_warp_plane_neon.h +++ b/third_party/aom/av1/common/arm/highbd_warp_plane_neon.h @@ -23,29 +23,31 @@ #include "av1/common/warped_motion.h" #include "config/av1_rtcd.h" -static INLINE int16x8_t highbd_horizontal_filter_4x1_f4(uint16x8x2_t in, int bd, - int sx, int alpha); +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_4x1_f4(uint16x8x2_t in, int bd, int sx, int alpha); -static INLINE int16x8_t highbd_horizontal_filter_8x1_f8(uint16x8x2_t in, int bd, - int sx, int alpha); +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_8x1_f8(uint16x8x2_t in, int bd, int sx, int alpha); -static INLINE int16x8_t highbd_horizontal_filter_4x1_f1(uint16x8x2_t in, int bd, - int sx); +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_4x1_f1(uint16x8x2_t in, int bd, int sx); -static INLINE int16x8_t highbd_horizontal_filter_8x1_f1(uint16x8x2_t in, int bd, - int sx); +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_8x1_f1(uint16x8x2_t in, int bd, int sx); -static INLINE int32x4_t vertical_filter_4x1_f1(const int16x8_t *tmp, int sy); +static AOM_FORCE_INLINE int32x4_t vertical_filter_4x1_f1(const int16x8_t *tmp, + int sy); -static INLINE int32x4x2_t vertical_filter_8x1_f1(const int16x8_t *tmp, int sy); +static AOM_FORCE_INLINE int32x4x2_t vertical_filter_8x1_f1(const int16x8_t *tmp, + int sy); -static INLINE int32x4_t vertical_filter_4x1_f4(const int16x8_t *tmp, int sy, - int gamma); +static AOM_FORCE_INLINE int32x4_t vertical_filter_4x1_f4(const int16x8_t *tmp, + int sy, int gamma); -static INLINE int32x4x2_t vertical_filter_8x1_f8(const int16x8_t *tmp, int sy, - int gamma); +static AOM_FORCE_INLINE int32x4x2_t vertical_filter_8x1_f8(const int16x8_t *tmp, + int sy, int gamma); -static INLINE int16x8_t load_filters_1(int ofs) { +static AOM_FORCE_INLINE int16x8_t load_filters_1(int ofs) { const int ofs0 = ROUND_POWER_OF_TWO(ofs, WARPEDDIFF_PREC_BITS); const int16_t *base = @@ -53,7 +55,8 @@ static INLINE int16x8_t load_filters_1(int ofs) { return vld1q_s16(base + ofs0 * 8); } -static INLINE void load_filters_4(int16x8_t out[], int ofs, int stride) { +static AOM_FORCE_INLINE void load_filters_4(int16x8_t out[], int ofs, + int stride) { const int ofs0 = ROUND_POWER_OF_TWO(ofs + stride * 0, WARPEDDIFF_PREC_BITS); const int ofs1 = ROUND_POWER_OF_TWO(ofs + stride * 1, WARPEDDIFF_PREC_BITS); const int ofs2 = ROUND_POWER_OF_TWO(ofs + stride * 2, WARPEDDIFF_PREC_BITS); @@ -67,7 +70,8 @@ static INLINE void load_filters_4(int16x8_t out[], int ofs, int stride) { out[3] = vld1q_s16(base + ofs3 * 8); } -static INLINE void load_filters_8(int16x8_t out[], int ofs, int stride) { +static AOM_FORCE_INLINE void load_filters_8(int16x8_t out[], int ofs, + int stride) { const int ofs0 = ROUND_POWER_OF_TWO(ofs + stride * 0, WARPEDDIFF_PREC_BITS); const int ofs1 = ROUND_POWER_OF_TWO(ofs + stride * 1, WARPEDDIFF_PREC_BITS); const int ofs2 = ROUND_POWER_OF_TWO(ofs + stride * 2, WARPEDDIFF_PREC_BITS); @@ -89,16 +93,18 @@ static INLINE void load_filters_8(int16x8_t out[], int ofs, int stride) { out[7] = vld1q_s16(base + ofs7 * 8); } -static INLINE uint16x4_t clip_pixel_highbd_vec(int32x4_t val, int bd) { +static AOM_FORCE_INLINE uint16x4_t clip_pixel_highbd_vec(int32x4_t val, + int bd) { const int limit = (1 << bd) - 1; return vqmovun_s32(vminq_s32(val, vdupq_n_s32(limit))); } -static INLINE void warp_affine_horizontal(const uint16_t *ref, int width, - int height, int stride, int p_width, - int16_t alpha, int16_t beta, int iy4, - int sx4, int ix4, int16x8_t tmp[], - int bd) { +static AOM_FORCE_INLINE void warp_affine_horizontal(const uint16_t *ref, + int width, int height, + int stride, int p_width, + int16_t alpha, int16_t beta, + int iy4, int sx4, int ix4, + int16x8_t tmp[], int bd) { const int round0 = (bd == 12) ? ROUND0_BITS + 2 : ROUND0_BITS; if (ix4 <= -7) { @@ -197,7 +203,7 @@ static INLINE void warp_affine_horizontal(const uint16_t *ref, int width, } } -static INLINE void highbd_vertical_filter_4x1_f4( +static AOM_FORCE_INLINE void highbd_vertical_filter_4x1_f4( uint16_t *pred, int p_stride, int bd, uint16_t *dst, int dst_stride, bool is_compound, bool do_average, bool use_dist_wtd_comp_avg, int fwd, int bwd, int16_t gamma, const int16x8_t *tmp, int i, int sy, int j) { @@ -253,7 +259,7 @@ static INLINE void highbd_vertical_filter_4x1_f4( vst1_u16(dst16, res0); } -static INLINE void highbd_vertical_filter_8x1_f8( +static AOM_FORCE_INLINE void highbd_vertical_filter_8x1_f8( uint16_t *pred, int p_stride, int bd, uint16_t *dst, int dst_stride, bool is_compound, bool do_average, bool use_dist_wtd_comp_avg, int fwd, int bwd, int16_t gamma, const int16x8_t *tmp, int i, int sy, int j) { @@ -328,7 +334,7 @@ static INLINE void highbd_vertical_filter_8x1_f8( vst1_u16(dst16 + 4, res1); } -static INLINE void warp_affine_vertical( +static AOM_FORCE_INLINE void warp_affine_vertical( uint16_t *pred, int p_width, int p_height, int p_stride, int bd, uint16_t *dst, int dst_stride, bool is_compound, bool do_average, bool use_dist_wtd_comp_avg, int fwd, int bwd, int16_t gamma, int16_t delta, @@ -354,7 +360,7 @@ static INLINE void warp_affine_vertical( } } -static INLINE void highbd_warp_affine_common( +static AOM_FORCE_INLINE void highbd_warp_affine_common( const int32_t *mat, const uint16_t *ref, int width, int height, int stride, uint16_t *pred, int p_col, int p_row, int p_width, int p_height, int p_stride, int subsampling_x, int subsampling_y, int bd, diff --git a/third_party/aom/av1/common/arm/highbd_warp_plane_sve.c b/third_party/aom/av1/common/arm/highbd_warp_plane_sve.c index 7a14f21846..87e033fd00 100644 --- a/third_party/aom/av1/common/arm/highbd_warp_plane_sve.c +++ b/third_party/aom/av1/common/arm/highbd_warp_plane_sve.c @@ -15,7 +15,7 @@ #include #include "aom_dsp/aom_dsp_common.h" -#include "aom_dsp/arm/dot_sve.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" #include "aom_dsp/arm/mem_neon.h" #include "aom_dsp/arm/transpose_neon.h" #include "aom_ports/mem.h" @@ -24,8 +24,8 @@ #include "config/av1_rtcd.h" #include "highbd_warp_plane_neon.h" -static INLINE int16x8_t highbd_horizontal_filter_4x1_f4(uint16x8x2_t in, int bd, - int sx, int alpha) { +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_4x1_f4(uint16x8x2_t in, int bd, int sx, int alpha) { int16x8_t f[4]; load_filters_4(f, sx, alpha); @@ -55,8 +55,8 @@ static INLINE int16x8_t highbd_horizontal_filter_4x1_f4(uint16x8x2_t in, int bd, return vcombine_s16(vmovn_s32(res), vdup_n_s16(0)); } -static INLINE int16x8_t highbd_horizontal_filter_8x1_f8(uint16x8x2_t in, int bd, - int sx, int alpha) { +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_8x1_f8(uint16x8x2_t in, int bd, int sx, int alpha) { int16x8_t f[8]; load_filters_8(f, sx, alpha); @@ -103,8 +103,8 @@ static INLINE int16x8_t highbd_horizontal_filter_8x1_f8(uint16x8x2_t in, int bd, return vcombine_s16(vmovn_s32(res0), vmovn_s32(res1)); } -static INLINE int16x8_t highbd_horizontal_filter_4x1_f1(uint16x8x2_t in, int bd, - int sx) { +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_4x1_f1(uint16x8x2_t in, int bd, int sx) { int16x8_t f = load_filters_1(sx); int16x8_t rv0 = vextq_s16(vreinterpretq_s16_u16(in.val[0]), @@ -133,8 +133,8 @@ static INLINE int16x8_t highbd_horizontal_filter_4x1_f1(uint16x8x2_t in, int bd, return vcombine_s16(vmovn_s32(res), vdup_n_s16(0)); } -static INLINE int16x8_t highbd_horizontal_filter_8x1_f1(uint16x8x2_t in, int bd, - int sx) { +static AOM_FORCE_INLINE int16x8_t +highbd_horizontal_filter_8x1_f1(uint16x8x2_t in, int bd, int sx) { int16x8_t f = load_filters_1(sx); int16x8_t rv0 = vextq_s16(vreinterpretq_s16_u16(in.val[0]), @@ -180,7 +180,8 @@ static INLINE int16x8_t highbd_horizontal_filter_8x1_f1(uint16x8x2_t in, int bd, return vcombine_s16(vmovn_s32(res0), vmovn_s32(res1)); } -static INLINE int32x4_t vertical_filter_4x1_f1(const int16x8_t *tmp, int sy) { +static AOM_FORCE_INLINE int32x4_t vertical_filter_4x1_f1(const int16x8_t *tmp, + int sy) { const int16x8_t f = load_filters_1(sy); const int16x4_t f0123 = vget_low_s16(f); const int16x4_t f4567 = vget_high_s16(f); @@ -197,7 +198,8 @@ static INLINE int32x4_t vertical_filter_4x1_f1(const int16x8_t *tmp, int sy) { return m0123; } -static INLINE int32x4x2_t vertical_filter_8x1_f1(const int16x8_t *tmp, int sy) { +static AOM_FORCE_INLINE int32x4x2_t vertical_filter_8x1_f1(const int16x8_t *tmp, + int sy) { const int16x8_t f = load_filters_1(sy); const int16x4_t f0123 = vget_low_s16(f); const int16x4_t f4567 = vget_high_s16(f); @@ -223,8 +225,8 @@ static INLINE int32x4x2_t vertical_filter_8x1_f1(const int16x8_t *tmp, int sy) { return (int32x4x2_t){ { m0123, m4567 } }; } -static INLINE int32x4_t vertical_filter_4x1_f4(const int16x8_t *tmp, int sy, - int gamma) { +static AOM_FORCE_INLINE int32x4_t vertical_filter_4x1_f4(const int16x8_t *tmp, + int sy, int gamma) { int16x8_t s0, s1, s2, s3; transpose_elems_s16_4x8( vget_low_s16(tmp[0]), vget_low_s16(tmp[1]), vget_low_s16(tmp[2]), @@ -244,8 +246,8 @@ static INLINE int32x4_t vertical_filter_4x1_f4(const int16x8_t *tmp, int sy, return vcombine_s32(vmovn_s64(m01), vmovn_s64(m23)); } -static INLINE int32x4x2_t vertical_filter_8x1_f8(const int16x8_t *tmp, int sy, - int gamma) { +static AOM_FORCE_INLINE int32x4x2_t vertical_filter_8x1_f8(const int16x8_t *tmp, + int sy, int gamma) { int16x8_t s0 = tmp[0]; int16x8_t s1 = tmp[1]; int16x8_t s2 = tmp[2]; diff --git a/third_party/aom/av1/common/arm/warp_plane_neon.c b/third_party/aom/av1/common/arm/warp_plane_neon.c index 4723154398..546aa2965b 100644 --- a/third_party/aom/av1/common/arm/warp_plane_neon.c +++ b/third_party/aom/av1/common/arm/warp_plane_neon.c @@ -11,8 +11,8 @@ #include "warp_plane_neon.h" -static INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, int sx, - int alpha) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, + int sx, int alpha) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); // Loading the 8 filter taps @@ -39,8 +39,8 @@ static INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, int sx, return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, int sx, - int alpha) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, + int sx, int alpha) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); // Loading the 8 filter taps @@ -75,7 +75,8 @@ static INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, int sx, return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, int sx) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, + int sx) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); int16x8_t f_s16 = @@ -101,7 +102,8 @@ static INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, int sx) { return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, int sx) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, + int sx) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); int16x8_t f_s16 = @@ -135,8 +137,8 @@ static INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, int sx) { return vreinterpretq_s16_u16(res); } -static INLINE void vertical_filter_4x1_f1(const int16x8_t *src, int32x4_t *res, - int sy) { +static AOM_FORCE_INLINE void vertical_filter_4x1_f1(const int16x8_t *src, + int32x4_t *res, int sy) { int16x4_t s0 = vget_low_s16(src[0]); int16x4_t s1 = vget_low_s16(src[1]); int16x4_t s2 = vget_low_s16(src[2]); @@ -161,8 +163,9 @@ static INLINE void vertical_filter_4x1_f1(const int16x8_t *src, int32x4_t *res, *res = m0123; } -static INLINE void vertical_filter_4x1_f4(const int16x8_t *src, int32x4_t *res, - int sy, int gamma) { +static AOM_FORCE_INLINE void vertical_filter_4x1_f4(const int16x8_t *src, + int32x4_t *res, int sy, + int gamma) { int16x8_t s0, s1, s2, s3; transpose_elems_s16_4x8( vget_low_s16(src[0]), vget_low_s16(src[1]), vget_low_s16(src[2]), @@ -186,9 +189,10 @@ static INLINE void vertical_filter_4x1_f4(const int16x8_t *src, int32x4_t *res, *res = horizontal_add_4d_s32x4(m0123_pairs); } -static INLINE void vertical_filter_8x1_f1(const int16x8_t *src, - int32x4_t *res_low, - int32x4_t *res_high, int sy) { +static AOM_FORCE_INLINE void vertical_filter_8x1_f1(const int16x8_t *src, + int32x4_t *res_low, + int32x4_t *res_high, + int sy) { int16x8_t s0 = src[0]; int16x8_t s1 = src[1]; int16x8_t s2 = src[2]; @@ -223,10 +227,10 @@ static INLINE void vertical_filter_8x1_f1(const int16x8_t *src, *res_high = m4567; } -static INLINE void vertical_filter_8x1_f8(const int16x8_t *src, - int32x4_t *res_low, - int32x4_t *res_high, int sy, - int gamma) { +static AOM_FORCE_INLINE void vertical_filter_8x1_f8(const int16x8_t *src, + int32x4_t *res_low, + int32x4_t *res_high, int sy, + int gamma) { int16x8_t s0 = src[0]; int16x8_t s1 = src[1]; int16x8_t s2 = src[2]; diff --git a/third_party/aom/av1/common/arm/warp_plane_neon.h b/third_party/aom/av1/common/arm/warp_plane_neon.h index 5afd72f4ab..eece007ef3 100644 --- a/third_party/aom/av1/common/arm/warp_plane_neon.h +++ b/third_party/aom/av1/common/arm/warp_plane_neon.h @@ -24,32 +24,37 @@ #include "av1/common/warped_motion.h" #include "av1/common/scale.h" -static INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, int sx, - int alpha); +static AOM_FORCE_INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, + int sx, int alpha); -static INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, int sx, - int alpha); +static AOM_FORCE_INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, + int sx, int alpha); -static INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, int sx); +static AOM_FORCE_INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, + int sx); -static INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, int sx); +static AOM_FORCE_INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, + int sx); -static INLINE void vertical_filter_4x1_f1(const int16x8_t *src, int32x4_t *res, - int sy); +static AOM_FORCE_INLINE void vertical_filter_4x1_f1(const int16x8_t *src, + int32x4_t *res, int sy); -static INLINE void vertical_filter_4x1_f4(const int16x8_t *src, int32x4_t *res, - int sy, int gamma); +static AOM_FORCE_INLINE void vertical_filter_4x1_f4(const int16x8_t *src, + int32x4_t *res, int sy, + int gamma); -static INLINE void vertical_filter_8x1_f1(const int16x8_t *src, - int32x4_t *res_low, - int32x4_t *res_high, int sy); +static AOM_FORCE_INLINE void vertical_filter_8x1_f1(const int16x8_t *src, + int32x4_t *res_low, + int32x4_t *res_high, + int sy); -static INLINE void vertical_filter_8x1_f8(const int16x8_t *src, - int32x4_t *res_low, - int32x4_t *res_high, int sy, - int gamma); +static AOM_FORCE_INLINE void vertical_filter_8x1_f8(const int16x8_t *src, + int32x4_t *res_low, + int32x4_t *res_high, int sy, + int gamma); -static INLINE void load_filters_4(int16x8_t out[], int offset, int stride) { +static AOM_FORCE_INLINE void load_filters_4(int16x8_t out[], int offset, + int stride) { out[0] = vld1q_s16((int16_t *)(av1_warped_filter + ((offset + 0 * stride) >> WARPEDDIFF_PREC_BITS))); out[1] = vld1q_s16((int16_t *)(av1_warped_filter + ((offset + 1 * stride) >> @@ -60,7 +65,8 @@ static INLINE void load_filters_4(int16x8_t out[], int offset, int stride) { WARPEDDIFF_PREC_BITS))); } -static INLINE void load_filters_8(int16x8_t out[], int offset, int stride) { +static AOM_FORCE_INLINE void load_filters_8(int16x8_t out[], int offset, + int stride) { out[0] = vld1q_s16((int16_t *)(av1_warped_filter + ((offset + 0 * stride) >> WARPEDDIFF_PREC_BITS))); out[1] = vld1q_s16((int16_t *)(av1_warped_filter + ((offset + 1 * stride) >> @@ -79,16 +85,14 @@ static INLINE void load_filters_8(int16x8_t out[], int offset, int stride) { WARPEDDIFF_PREC_BITS))); } -static INLINE int clamp_iy(int iy, int height) { +static AOM_FORCE_INLINE int clamp_iy(int iy, int height) { return clamp(iy, 0, height - 1); } -static INLINE void warp_affine_horizontal(const uint8_t *ref, int width, - int height, int stride, int p_width, - int p_height, int16_t alpha, - int16_t beta, const int64_t x4, - const int64_t y4, const int i, - int16x8_t tmp[]) { +static AOM_FORCE_INLINE void warp_affine_horizontal( + const uint8_t *ref, int width, int height, int stride, int p_width, + int p_height, int16_t alpha, int16_t beta, const int64_t x4, + const int64_t y4, const int i, int16x8_t tmp[]) { const int bd = 8; const int reduce_bits_horiz = ROUND0_BITS; const int height_limit = AOMMIN(8, p_height - i) + 7; @@ -197,7 +201,7 @@ static INLINE void warp_affine_horizontal(const uint8_t *ref, int width, } } -static INLINE void warp_affine_vertical( +static AOM_FORCE_INLINE void warp_affine_vertical( uint8_t *pred, int p_width, int p_height, int p_stride, int is_compound, uint16_t *dst, int dst_stride, int do_average, int use_dist_wtd_comp_avg, int16_t gamma, int16_t delta, const int64_t y4, const int i, const int j, @@ -325,7 +329,7 @@ static INLINE void warp_affine_vertical( } } -static INLINE void av1_warp_affine_common( +static AOM_FORCE_INLINE void av1_warp_affine_common( const int32_t *mat, const uint8_t *ref, int width, int height, int stride, uint8_t *pred, int p_col, int p_row, int p_width, int p_height, int p_stride, int subsampling_x, int subsampling_y, diff --git a/third_party/aom/av1/common/arm/warp_plane_neon_i8mm.c b/third_party/aom/av1/common/arm/warp_plane_neon_i8mm.c index 39e3ad99f4..22a1be17b5 100644 --- a/third_party/aom/av1/common/arm/warp_plane_neon_i8mm.c +++ b/third_party/aom/av1/common/arm/warp_plane_neon_i8mm.c @@ -17,8 +17,8 @@ DECLARE_ALIGNED(16, static const uint8_t, usdot_permute_idx[48]) = { 8, 9, 10, 11, 9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14 }; -static INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, int sx, - int alpha) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, + int sx, int alpha) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); // Loading the 8 filter taps @@ -45,8 +45,8 @@ static INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, int sx, return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, int sx, - int alpha) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, + int sx, int alpha) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); // Loading the 8 filter taps @@ -83,7 +83,8 @@ static INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, int sx, return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, int sx) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, + int sx) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); int16x8_t f_s16 = @@ -112,7 +113,8 @@ static INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, int sx) { return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, int sx) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, + int sx) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); int16x8_t f_s16 = @@ -149,8 +151,8 @@ static INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, int sx) { return vreinterpretq_s16_u16(res); } -static INLINE void vertical_filter_4x1_f1(const int16x8_t *src, int32x4_t *res, - int sy) { +static AOM_FORCE_INLINE void vertical_filter_4x1_f1(const int16x8_t *src, + int32x4_t *res, int sy) { int16x4_t s0 = vget_low_s16(src[0]); int16x4_t s1 = vget_low_s16(src[1]); int16x4_t s2 = vget_low_s16(src[2]); @@ -175,8 +177,9 @@ static INLINE void vertical_filter_4x1_f1(const int16x8_t *src, int32x4_t *res, *res = m0123; } -static INLINE void vertical_filter_4x1_f4(const int16x8_t *src, int32x4_t *res, - int sy, int gamma) { +static AOM_FORCE_INLINE void vertical_filter_4x1_f4(const int16x8_t *src, + int32x4_t *res, int sy, + int gamma) { int16x8_t s0, s1, s2, s3; transpose_elems_s16_4x8( vget_low_s16(src[0]), vget_low_s16(src[1]), vget_low_s16(src[2]), @@ -200,9 +203,10 @@ static INLINE void vertical_filter_4x1_f4(const int16x8_t *src, int32x4_t *res, *res = horizontal_add_4d_s32x4(m0123_pairs); } -static INLINE void vertical_filter_8x1_f1(const int16x8_t *src, - int32x4_t *res_low, - int32x4_t *res_high, int sy) { +static AOM_FORCE_INLINE void vertical_filter_8x1_f1(const int16x8_t *src, + int32x4_t *res_low, + int32x4_t *res_high, + int sy) { int16x8_t s0 = src[0]; int16x8_t s1 = src[1]; int16x8_t s2 = src[2]; @@ -237,10 +241,10 @@ static INLINE void vertical_filter_8x1_f1(const int16x8_t *src, *res_high = m4567; } -static INLINE void vertical_filter_8x1_f8(const int16x8_t *src, - int32x4_t *res_low, - int32x4_t *res_high, int sy, - int gamma) { +static AOM_FORCE_INLINE void vertical_filter_8x1_f8(const int16x8_t *src, + int32x4_t *res_low, + int32x4_t *res_high, int sy, + int gamma) { int16x8_t s0 = src[0]; int16x8_t s1 = src[1]; int16x8_t s2 = src[2]; diff --git a/third_party/aom/av1/common/arm/warp_plane_sve.c b/third_party/aom/av1/common/arm/warp_plane_sve.c index 8a4bf5747b..c70b066174 100644 --- a/third_party/aom/av1/common/arm/warp_plane_sve.c +++ b/third_party/aom/av1/common/arm/warp_plane_sve.c @@ -11,7 +11,7 @@ #include -#include "aom_dsp/arm/dot_sve.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" #include "warp_plane_neon.h" DECLARE_ALIGNED(16, static const uint8_t, usdot_permute_idx[48]) = { @@ -20,8 +20,8 @@ DECLARE_ALIGNED(16, static const uint8_t, usdot_permute_idx[48]) = { 8, 9, 10, 11, 9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14 }; -static INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, int sx, - int alpha) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, + int sx, int alpha) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); // Loading the 8 filter taps @@ -48,8 +48,8 @@ static INLINE int16x8_t horizontal_filter_4x1_f4(const uint8x16_t in, int sx, return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, int sx, - int alpha) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, + int sx, int alpha) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); // Loading the 8 filter taps @@ -86,7 +86,8 @@ static INLINE int16x8_t horizontal_filter_8x1_f8(const uint8x16_t in, int sx, return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, int sx) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, + int sx) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); int16x8_t f_s16 = @@ -115,7 +116,8 @@ static INLINE int16x8_t horizontal_filter_4x1_f1(const uint8x16_t in, int sx) { return vreinterpretq_s16_u16(res); } -static INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, int sx) { +static AOM_FORCE_INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, + int sx) { const int32x4_t add_const = vdupq_n_s32(1 << (8 + FILTER_BITS - 1)); int16x8_t f_s16 = @@ -152,8 +154,8 @@ static INLINE int16x8_t horizontal_filter_8x1_f1(const uint8x16_t in, int sx) { return vreinterpretq_s16_u16(res); } -static INLINE void vertical_filter_4x1_f1(const int16x8_t *src, int32x4_t *res, - int sy) { +static AOM_FORCE_INLINE void vertical_filter_4x1_f1(const int16x8_t *src, + int32x4_t *res, int sy) { int16x4_t s0 = vget_low_s16(src[0]); int16x4_t s1 = vget_low_s16(src[1]); int16x4_t s2 = vget_low_s16(src[2]); @@ -178,8 +180,9 @@ static INLINE void vertical_filter_4x1_f1(const int16x8_t *src, int32x4_t *res, *res = m0123; } -static INLINE void vertical_filter_4x1_f4(const int16x8_t *src, int32x4_t *res, - int sy, int gamma) { +static AOM_FORCE_INLINE void vertical_filter_4x1_f4(const int16x8_t *src, + int32x4_t *res, int sy, + int gamma) { int16x8_t s0, s1, s2, s3; transpose_elems_s16_4x8( vget_low_s16(src[0]), vget_low_s16(src[1]), vget_low_s16(src[2]), @@ -200,9 +203,10 @@ static INLINE void vertical_filter_4x1_f4(const int16x8_t *src, int32x4_t *res, *res = vcombine_s32(vmovn_s64(m01), vmovn_s64(m23)); } -static INLINE void vertical_filter_8x1_f1(const int16x8_t *src, - int32x4_t *res_low, - int32x4_t *res_high, int sy) { +static AOM_FORCE_INLINE void vertical_filter_8x1_f1(const int16x8_t *src, + int32x4_t *res_low, + int32x4_t *res_high, + int sy) { int16x8_t s0 = src[0]; int16x8_t s1 = src[1]; int16x8_t s2 = src[2]; @@ -237,10 +241,10 @@ static INLINE void vertical_filter_8x1_f1(const int16x8_t *src, *res_high = m4567; } -static INLINE void vertical_filter_8x1_f8(const int16x8_t *src, - int32x4_t *res_low, - int32x4_t *res_high, int sy, - int gamma) { +static AOM_FORCE_INLINE void vertical_filter_8x1_f8(const int16x8_t *src, + int32x4_t *res_low, + int32x4_t *res_high, int sy, + int gamma) { int16x8_t s0 = src[0]; int16x8_t s1 = src[1]; int16x8_t s2 = src[2]; diff --git a/third_party/aom/av1/common/av1_common_int.h b/third_party/aom/av1/common/av1_common_int.h index 4c0cb99d2b..4e14c4a8be 100644 --- a/third_party/aom/av1/common/av1_common_int.h +++ b/third_party/aom/av1/common/av1_common_int.h @@ -17,7 +17,7 @@ #include "aom/internal/aom_codec_internal.h" #include "aom_dsp/flow_estimation/corner_detect.h" -#include "aom_util/aom_thread.h" +#include "aom_util/aom_pthread.h" #include "av1/common/alloccommon.h" #include "av1/common/av1_loopfilter.h" #include "av1/common/entropy.h" diff --git a/third_party/aom/av1/common/av1_rtcd_defs.pl b/third_party/aom/av1/common/av1_rtcd_defs.pl index ef999fbba2..c0831330d1 100644 --- a/third_party/aom/av1/common/av1_rtcd_defs.pl +++ b/third_party/aom/av1/common/av1_rtcd_defs.pl @@ -77,6 +77,16 @@ EOF } forward_decls qw/av1_common_forward_decls/; +# Fallbacks for Valgrind support +# For normal use, we require SSE4.1. However, 32-bit Valgrind does not support +# SSE4.1, so we include fallbacks for some critical functions to improve +# performance +$sse2_x86 = $ssse3_x86 = ''; +if ($opts{arch} eq "x86") { + $sse2_x86 = 'sse2'; + $ssse3_x86 = 'ssse3'; +} + # functions that are 64 bit only. $mmx_x86_64 = $sse2_x86_64 = $ssse3_x86_64 = $avx_x86_64 = $avx2_x86_64 = ''; if ($opts{arch} eq "x86_64") { @@ -345,7 +355,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { #fwd txfm add_proto qw/void av1_lowbd_fwd_txfm/, "const int16_t *src_diff, tran_low_t *coeff, int diff_stride, TxfmParam *txfm_param"; - specialize qw/av1_lowbd_fwd_txfm sse2 sse4_1 avx2 neon/; + specialize qw/av1_lowbd_fwd_txfm sse4_1 avx2 neon/, $sse2_x86; add_proto qw/void av1_fwd_txfm2d_4x8/, "const int16_t *input, int32_t *output, int stride, TX_TYPE tx_type, int bd"; specialize qw/av1_fwd_txfm2d_4x8 sse4_1 neon/; @@ -436,9 +446,9 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/av1_txb_init_levels sse4_1 avx2 neon/; add_proto qw/uint64_t av1_wedge_sse_from_residuals/, "const int16_t *r1, const int16_t *d, const uint8_t *m, int N"; - specialize qw/av1_wedge_sse_from_residuals sse2 avx2 neon/; + specialize qw/av1_wedge_sse_from_residuals sse2 avx2 neon sve/; add_proto qw/int8_t av1_wedge_sign_from_residuals/, "const int16_t *ds, const uint8_t *m, int N, int64_t limit"; - specialize qw/av1_wedge_sign_from_residuals sse2 avx2 neon/; + specialize qw/av1_wedge_sign_from_residuals sse2 avx2 neon sve/; add_proto qw/void av1_wedge_compute_delta_squares/, "int16_t *d, const int16_t *a, const int16_t *b, int N"; specialize qw/av1_wedge_compute_delta_squares sse2 avx2 neon/; @@ -521,21 +531,21 @@ add_proto qw/void cdef_copy_rect8_16bit_to_16bit/, "uint16_t *dst, int dstride, # structs as arguments, which makes the v256 type of the intrinsics # hard to support, so optimizations for this target are disabled. if ($opts{config} !~ /libs-x86-win32-vs.*/) { - specialize qw/cdef_find_dir sse2 ssse3 sse4_1 avx2 neon/; - specialize qw/cdef_find_dir_dual sse2 ssse3 sse4_1 avx2 neon/; + specialize qw/cdef_find_dir sse4_1 avx2 neon/, "$ssse3_x86"; + specialize qw/cdef_find_dir_dual sse4_1 avx2 neon/, "$ssse3_x86"; - specialize qw/cdef_filter_8_0 sse2 ssse3 sse4_1 avx2 neon/; - specialize qw/cdef_filter_8_1 sse2 ssse3 sse4_1 avx2 neon/; - specialize qw/cdef_filter_8_2 sse2 ssse3 sse4_1 avx2 neon/; - specialize qw/cdef_filter_8_3 sse2 ssse3 sse4_1 avx2 neon/; + specialize qw/cdef_filter_8_0 sse4_1 avx2 neon/, "$ssse3_x86"; + specialize qw/cdef_filter_8_1 sse4_1 avx2 neon/, "$ssse3_x86"; + specialize qw/cdef_filter_8_2 sse4_1 avx2 neon/, "$ssse3_x86"; + specialize qw/cdef_filter_8_3 sse4_1 avx2 neon/, "$ssse3_x86"; - specialize qw/cdef_filter_16_0 sse2 ssse3 sse4_1 avx2 neon/; - specialize qw/cdef_filter_16_1 sse2 ssse3 sse4_1 avx2 neon/; - specialize qw/cdef_filter_16_2 sse2 ssse3 sse4_1 avx2 neon/; - specialize qw/cdef_filter_16_3 sse2 ssse3 sse4_1 avx2 neon/; + specialize qw/cdef_filter_16_0 sse4_1 avx2 neon/, "$ssse3_x86"; + specialize qw/cdef_filter_16_1 sse4_1 avx2 neon/, "$ssse3_x86"; + specialize qw/cdef_filter_16_2 sse4_1 avx2 neon/, "$ssse3_x86"; + specialize qw/cdef_filter_16_3 sse4_1 avx2 neon/, "$ssse3_x86"; - specialize qw/cdef_copy_rect8_8bit_to_16bit sse2 ssse3 sse4_1 avx2 neon/; - specialize qw/cdef_copy_rect8_16bit_to_16bit sse2 ssse3 sse4_1 avx2 neon/; + specialize qw/cdef_copy_rect8_8bit_to_16bit sse4_1 avx2 neon/, "$ssse3_x86"; + specialize qw/cdef_copy_rect8_16bit_to_16bit sse4_1 avx2 neon/, "$ssse3_x86"; } # WARPED_MOTION / GLOBAL_MOTION functions @@ -591,20 +601,20 @@ if(aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") { specialize qw/av1_convolve_y_sr sse2 avx2 neon/; specialize qw/av1_convolve_y_sr_intrabc neon/; specialize qw/av1_convolve_2d_scale sse4_1/; - specialize qw/av1_dist_wtd_convolve_2d sse2 ssse3 avx2 neon neon_dotprod neon_i8mm/; + specialize qw/av1_dist_wtd_convolve_2d ssse3 avx2 neon neon_dotprod neon_i8mm/; specialize qw/av1_dist_wtd_convolve_2d_copy sse2 avx2 neon/; specialize qw/av1_dist_wtd_convolve_x sse2 avx2 neon neon_dotprod neon_i8mm/; specialize qw/av1_dist_wtd_convolve_y sse2 avx2 neon/; if(aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") { - specialize qw/av1_highbd_dist_wtd_convolve_2d sse4_1 avx2 neon/; - specialize qw/av1_highbd_dist_wtd_convolve_x sse4_1 avx2 neon/; - specialize qw/av1_highbd_dist_wtd_convolve_y sse4_1 avx2 neon/; + specialize qw/av1_highbd_dist_wtd_convolve_2d sse4_1 avx2 neon sve2/; + specialize qw/av1_highbd_dist_wtd_convolve_x sse4_1 avx2 neon sve2/; + specialize qw/av1_highbd_dist_wtd_convolve_y sse4_1 avx2 neon sve2/; specialize qw/av1_highbd_dist_wtd_convolve_2d_copy sse4_1 avx2 neon/; - specialize qw/av1_highbd_convolve_2d_sr ssse3 avx2 neon/; + specialize qw/av1_highbd_convolve_2d_sr ssse3 avx2 neon sve2/; specialize qw/av1_highbd_convolve_2d_sr_intrabc neon/; - specialize qw/av1_highbd_convolve_x_sr ssse3 avx2 neon/; + specialize qw/av1_highbd_convolve_x_sr ssse3 avx2 neon sve2/; specialize qw/av1_highbd_convolve_x_sr_intrabc neon/; - specialize qw/av1_highbd_convolve_y_sr ssse3 avx2 neon/; + specialize qw/av1_highbd_convolve_y_sr ssse3 avx2 neon sve2/; specialize qw/av1_highbd_convolve_y_sr_intrabc neon/; specialize qw/av1_highbd_convolve_2d_scale sse4_1 neon/; } diff --git a/third_party/aom/av1/common/cdef.c b/third_party/aom/av1/common/cdef.c index 12e9545441..5cec940a8e 100644 --- a/third_party/aom/av1/common/cdef.c +++ b/third_party/aom/av1/common/cdef.c @@ -10,15 +10,19 @@ */ #include -#include +#include #include #include "config/aom_scale_rtcd.h" #include "aom/aom_integer.h" +#include "aom_util/aom_pthread.h" #include "av1/common/av1_common_int.h" #include "av1/common/cdef.h" #include "av1/common/cdef_block.h" +#include "av1/common/common.h" +#include "av1/common/common_data.h" +#include "av1/common/enums.h" #include "av1/common/reconinter.h" #include "av1/common/thread_common.h" @@ -92,7 +96,7 @@ void av1_cdef_copy_sb8_16_lowbd(uint16_t *const dst, int dstride, const uint8_t *src, int src_voffset, int src_hoffset, int sstride, int vsize, int hsize) { - const uint8_t *base = &src[src_voffset * sstride + src_hoffset]; + const uint8_t *base = &src[src_voffset * (ptrdiff_t)sstride + src_hoffset]; cdef_copy_rect8_8bit_to_16bit(dst, dstride, base, sstride, hsize, vsize); } @@ -101,7 +105,7 @@ void av1_cdef_copy_sb8_16_highbd(uint16_t *const dst, int dstride, int src_hoffset, int sstride, int vsize, int hsize) { const uint16_t *base = - &CONVERT_TO_SHORTPTR(src)[src_voffset * sstride + src_hoffset]; + &CONVERT_TO_SHORTPTR(src)[src_voffset * (ptrdiff_t)sstride + src_hoffset]; cdef_copy_rect8_16bit_to_16bit(dst, dstride, base, sstride, hsize, vsize); } @@ -247,7 +251,8 @@ static void cdef_prepare_fb(const AV1_COMMON *const cm, CdefBlockInfo *fb_info, static INLINE void cdef_filter_fb(CdefBlockInfo *const fb_info, int plane, uint8_t use_highbitdepth) { - int offset = fb_info->dst_stride * fb_info->roffset + fb_info->coffset; + ptrdiff_t offset = + (ptrdiff_t)fb_info->dst_stride * fb_info->roffset + fb_info->coffset; if (use_highbitdepth) { av1_cdef_filter_fb( NULL, CONVERT_TO_SHORTPTR(fb_info->dst + offset), fb_info->dst_stride, diff --git a/third_party/aom/av1/common/entropymode.h b/third_party/aom/av1/common/entropymode.h index 09cd6bd1e9..028bd21ae3 100644 --- a/third_party/aom/av1/common/entropymode.h +++ b/third_party/aom/av1/common/entropymode.h @@ -12,6 +12,7 @@ #ifndef AOM_AV1_COMMON_ENTROPYMODE_H_ #define AOM_AV1_COMMON_ENTROPYMODE_H_ +#include "aom_ports/bitops.h" #include "av1/common/entropy.h" #include "av1/common/entropymv.h" #include "av1/common/filter.h" @@ -192,13 +193,7 @@ void av1_setup_past_independence(struct AV1Common *cm); // Returns (int)ceil(log2(n)). static INLINE int av1_ceil_log2(int n) { if (n < 2) return 0; - int i = 1; - unsigned int p = 2; - while (p < (unsigned int)n) { - i++; - p = p << 1; - } - return i; + return get_msb(n - 1) + 1; } // Returns the context for palette color index at row 'r' and column 'c', diff --git a/third_party/aom/av1/common/quant_common.c b/third_party/aom/av1/common/quant_common.c index b0976287ef..58eb113370 100644 --- a/third_party/aom/av1/common/quant_common.c +++ b/third_party/aom/av1/common/quant_common.c @@ -9,10 +9,15 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include "config/aom_config.h" + +#include "aom/aom_frame_buffer.h" +#include "aom_scale/yv12config.h" #include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/common.h" #include "av1/common/entropy.h" +#include "av1/common/filter.h" #include "av1/common/quant_common.h" #include "av1/common/seg_common.h" @@ -274,13 +279,16 @@ const qm_val_t *av1_get_qmatrix(const CommonQuantParams *quant_params, : quant_params->gqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size]; } +#if CONFIG_QUANT_MATRIX || CONFIG_AV1_DECODER #define QM_TOTAL_SIZE 3344 // We only use wt_matrix_ref[q] and iwt_matrix_ref[q] // for q = 0, ..., NUM_QM_LEVELS - 2. static const qm_val_t wt_matrix_ref[NUM_QM_LEVELS - 1][2][QM_TOTAL_SIZE]; static const qm_val_t iwt_matrix_ref[NUM_QM_LEVELS - 1][2][QM_TOTAL_SIZE]; +#endif void av1_qm_init(CommonQuantParams *quant_params, int num_planes) { +#if CONFIG_QUANT_MATRIX || CONFIG_AV1_DECODER for (int q = 0; q < NUM_QM_LEVELS; ++q) { for (int c = 0; c < num_planes; ++c) { int current = 0; @@ -306,6 +314,10 @@ void av1_qm_init(CommonQuantParams *quant_params, int num_planes) { } } } +#else + (void)quant_params; + (void)num_planes; +#endif // CONFIG_QUANT_MATRIX || CONFIG_AV1_DECODER } /* Provide 15 sets of quantization matrices for chroma and luma @@ -320,6 +332,8 @@ void av1_qm_init(CommonQuantParams *quant_params, int num_planes) { distances. Matrices for QM level 15 are omitted because they are not used. */ + +#if CONFIG_QUANT_MATRIX || CONFIG_AV1_DECODER static const qm_val_t iwt_matrix_ref[NUM_QM_LEVELS - 1][2][QM_TOTAL_SIZE] = { { { /* Luma */ @@ -12873,4 +12887,6 @@ static const qm_val_t wt_matrix_ref[NUM_QM_LEVELS - 1][2][QM_TOTAL_SIZE] = { 33, 33, 32, 32, 32, 32, 34, 33, 33, 33, 32, 32, 32, 32, 34, 33, 33, 33, 32, 32, 32, 32 }, }, -}; \ No newline at end of file +}; + +#endif // CONFIG_QUANT_MATRIX || CONFIG_AV1_DECODER diff --git a/third_party/aom/av1/common/reconintra.c b/third_party/aom/av1/common/reconintra.c index f68af18cb1..497863e117 100644 --- a/third_party/aom/av1/common/reconintra.c +++ b/third_party/aom/av1/common/reconintra.c @@ -1196,7 +1196,8 @@ static void build_directional_and_filter_intra_predictors( const int need_right = p_angle < 90; const int need_bottom = p_angle > 180; if (p_angle != 90 && p_angle != 180) { - const int ab_le = need_above_left ? 1 : 0; + assert(need_above_left); + const int ab_le = 1; if (need_above && need_left && (txwpx + txhpx >= 24)) { filter_intra_edge_corner(above_row, left_col); } @@ -1500,7 +1501,8 @@ static void highbd_build_directional_and_filter_intra_predictors( const int need_right = p_angle < 90; const int need_bottom = p_angle > 180; if (p_angle != 90 && p_angle != 180) { - const int ab_le = need_above_left ? 1 : 0; + assert(need_above_left); + const int ab_le = 1; if (need_above && need_left && (txwpx + txhpx >= 24)) { highbd_filter_intra_edge_corner(above_row, left_col); } diff --git a/third_party/aom/av1/common/resize.c b/third_party/aom/av1/common/resize.c index 1b348836a5..441323ab1f 100644 --- a/third_party/aom/av1/common/resize.c +++ b/third_party/aom/av1/common/resize.c @@ -524,7 +524,7 @@ static void fill_arr_to_col(uint8_t *img, int stride, int len, uint8_t *arr) { } } -bool av1_resize_plane(const uint8_t *const input, int height, int width, +bool av1_resize_plane(const uint8_t *input, int height, int width, int in_stride, uint8_t *output, int height2, int width2, int out_stride) { int i; @@ -881,7 +881,7 @@ static void highbd_fill_arr_to_col(uint16_t *img, int stride, int len, } } -void av1_highbd_resize_plane(const uint8_t *const input, int height, int width, +void av1_highbd_resize_plane(const uint8_t *input, int height, int width, int in_stride, uint8_t *output, int height2, int width2, int out_stride, int bd) { int i; @@ -980,10 +980,9 @@ static bool highbd_upscale_normative_rect(const uint8_t *const input, } #endif // CONFIG_AV1_HIGHBITDEPTH -void av1_resize_frame420(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, - int uv_stride, int height, int width, uint8_t *oy, - int oy_stride, uint8_t *ou, uint8_t *ov, +void av1_resize_frame420(const uint8_t *y, int y_stride, const uint8_t *u, + const uint8_t *v, int uv_stride, int height, int width, + uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, int owidth) { if (!av1_resize_plane(y, height, width, y_stride, oy, oheight, owidth, oy_stride)) @@ -996,10 +995,9 @@ void av1_resize_frame420(const uint8_t *const y, int y_stride, abort(); } -bool av1_resize_frame422(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, - int uv_stride, int height, int width, uint8_t *oy, - int oy_stride, uint8_t *ou, uint8_t *ov, +bool av1_resize_frame422(const uint8_t *y, int y_stride, const uint8_t *u, + const uint8_t *v, int uv_stride, int height, int width, + uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, int owidth) { if (!av1_resize_plane(y, height, width, y_stride, oy, oheight, owidth, oy_stride)) @@ -1013,10 +1011,9 @@ bool av1_resize_frame422(const uint8_t *const y, int y_stride, return true; } -bool av1_resize_frame444(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, - int uv_stride, int height, int width, uint8_t *oy, - int oy_stride, uint8_t *ou, uint8_t *ov, +bool av1_resize_frame444(const uint8_t *y, int y_stride, const uint8_t *u, + const uint8_t *v, int uv_stride, int height, int width, + uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, int owidth) { if (!av1_resize_plane(y, height, width, y_stride, oy, oheight, owidth, oy_stride)) @@ -1031,8 +1028,8 @@ bool av1_resize_frame444(const uint8_t *const y, int y_stride, } #if CONFIG_AV1_HIGHBITDEPTH -void av1_highbd_resize_frame420(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, +void av1_highbd_resize_frame420(const uint8_t *y, int y_stride, + const uint8_t *u, const uint8_t *v, int uv_stride, int height, int width, uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, @@ -1045,8 +1042,8 @@ void av1_highbd_resize_frame420(const uint8_t *const y, int y_stride, owidth / 2, ouv_stride, bd); } -void av1_highbd_resize_frame422(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, +void av1_highbd_resize_frame422(const uint8_t *y, int y_stride, + const uint8_t *u, const uint8_t *v, int uv_stride, int height, int width, uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, @@ -1059,8 +1056,8 @@ void av1_highbd_resize_frame422(const uint8_t *const y, int y_stride, owidth / 2, ouv_stride, bd); } -void av1_highbd_resize_frame444(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, +void av1_highbd_resize_frame444(const uint8_t *y, int y_stride, + const uint8_t *u, const uint8_t *v, int uv_stride, int height, int width, uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, @@ -1126,7 +1123,7 @@ void av1_resize_and_extend_frame_c(const YV12_BUFFER_CONFIG *src, bool av1_resize_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst, int bd, - const int num_planes) { + int num_planes) { // TODO(dkovalev): replace YV12_BUFFER_CONFIG with aom_image_t // We use AOMMIN(num_planes, MAX_MB_PLANE) instead of num_planes to quiet @@ -1246,8 +1243,7 @@ void av1_upscale_normative_and_extend_frame(const AV1_COMMON *cm, YV12_BUFFER_CONFIG *av1_realloc_and_scale_if_required( AV1_COMMON *cm, YV12_BUFFER_CONFIG *unscaled, YV12_BUFFER_CONFIG *scaled, const InterpFilter filter, const int phase, const bool use_optimized_scaler, - const bool for_psnr, const int border_in_pixels, - const int num_pyramid_levels) { + const bool for_psnr, const int border_in_pixels, const bool alloc_pyramid) { // If scaling is performed for the sole purpose of calculating PSNR, then our // target dimensions are superres upscaled width/height. Otherwise our target // dimensions are coded width/height. @@ -1267,7 +1263,7 @@ YV12_BUFFER_CONFIG *av1_realloc_and_scale_if_required( scaled, scaled_width, scaled_height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, border_in_pixels, cm->features.byte_alignment, NULL, NULL, NULL, - num_pyramid_levels, 0)) + alloc_pyramid, 0)) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate scaled buffer"); @@ -1363,7 +1359,7 @@ static void copy_buffer_config(const YV12_BUFFER_CONFIG *const src, // TODO(afergs): aom_ vs av1_ functions? Which can I use? // Upscale decoded image. void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool, - int num_pyramid_levels) { + bool alloc_pyramid) { const int num_planes = av1_num_planes(cm); if (!av1_superres_scaled(cm)) return; const SequenceHeader *const seq_params = cm->seq_params; @@ -1378,7 +1374,7 @@ void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool, if (aom_alloc_frame_buffer( ©_buffer, aligned_width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - AOM_BORDER_IN_PIXELS, byte_alignment, 0, 0)) + AOM_BORDER_IN_PIXELS, byte_alignment, false, 0)) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate copy buffer for superres upscaling"); @@ -1411,7 +1407,7 @@ void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool, cm->superres_upscaled_height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, AOM_BORDER_IN_PIXELS, byte_alignment, fb, cb, cb_priv, - num_pyramid_levels, 0)) { + alloc_pyramid, 0)) { unlock_buffer_pool(pool); aom_internal_error( cm->error, AOM_CODEC_MEM_ERROR, @@ -1428,7 +1424,7 @@ void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool, frame_to_show, cm->superres_upscaled_width, cm->superres_upscaled_height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - AOM_BORDER_IN_PIXELS, byte_alignment, num_pyramid_levels, 0)) + AOM_BORDER_IN_PIXELS, byte_alignment, alloc_pyramid, 0)) aom_internal_error( cm->error, AOM_CODEC_MEM_ERROR, "Failed to reallocate current frame buffer for superres upscaling"); diff --git a/third_party/aom/av1/common/resize.h b/third_party/aom/av1/common/resize.h index 0ba3108f72..d573a538bf 100644 --- a/third_party/aom/av1/common/resize.h +++ b/third_party/aom/av1/common/resize.h @@ -20,44 +20,41 @@ extern "C" { #endif -bool av1_resize_plane(const uint8_t *const input, int height, int width, +bool av1_resize_plane(const uint8_t *input, int height, int width, int in_stride, uint8_t *output, int height2, int width2, int out_stride); // TODO(aomedia:3228): In libaom 4.0.0, remove av1_resize_frame420 from // av1/exports_com and delete this function. -void av1_resize_frame420(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, - int uv_stride, int height, int width, uint8_t *oy, - int oy_stride, uint8_t *ou, uint8_t *ov, +void av1_resize_frame420(const uint8_t *y, int y_stride, const uint8_t *u, + const uint8_t *v, int uv_stride, int height, int width, + uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, int owidth); -bool av1_resize_frame422(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, - int uv_stride, int height, int width, uint8_t *oy, - int oy_stride, uint8_t *ou, uint8_t *ov, +bool av1_resize_frame422(const uint8_t *y, int y_stride, const uint8_t *u, + const uint8_t *v, int uv_stride, int height, int width, + uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, int owidth); -bool av1_resize_frame444(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, - int uv_stride, int height, int width, uint8_t *oy, - int oy_stride, uint8_t *ou, uint8_t *ov, +bool av1_resize_frame444(const uint8_t *y, int y_stride, const uint8_t *u, + const uint8_t *v, int uv_stride, int height, int width, + uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, int owidth); -void av1_highbd_resize_plane(const uint8_t *const input, int height, int width, +void av1_highbd_resize_plane(const uint8_t *input, int height, int width, int in_stride, uint8_t *output, int height2, int width2, int out_stride, int bd); -void av1_highbd_resize_frame420(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, +void av1_highbd_resize_frame420(const uint8_t *y, int y_stride, + const uint8_t *u, const uint8_t *v, int uv_stride, int height, int width, uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, int owidth, int bd); -void av1_highbd_resize_frame422(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, +void av1_highbd_resize_frame422(const uint8_t *y, int y_stride, + const uint8_t *u, const uint8_t *v, int uv_stride, int height, int width, uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, int owidth, int bd); -void av1_highbd_resize_frame444(const uint8_t *const y, int y_stride, - const uint8_t *const u, const uint8_t *const v, +void av1_highbd_resize_frame444(const uint8_t *y, int y_stride, + const uint8_t *u, const uint8_t *v, int uv_stride, int height, int width, uint8_t *oy, int oy_stride, uint8_t *ou, uint8_t *ov, int ouv_stride, int oheight, @@ -73,12 +70,11 @@ void av1_upscale_normative_and_extend_frame(const AV1_COMMON *cm, YV12_BUFFER_CONFIG *av1_realloc_and_scale_if_required( AV1_COMMON *cm, YV12_BUFFER_CONFIG *unscaled, YV12_BUFFER_CONFIG *scaled, const InterpFilter filter, const int phase, const bool use_optimized_scaler, - const bool for_psnr, const int border_in_pixels, - const int num_pyramid_levels); + const bool for_psnr, const int border_in_pixels, const bool alloc_pyramid); bool av1_resize_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst, int bd, - const int num_planes); + int num_planes); // Calculates the scaled dimensions from the given original dimensions and the // resize scale denominator. @@ -95,7 +91,7 @@ void av1_calculate_scaled_superres_size(int *width, int *height, void av1_calculate_unscaled_superres_size(int *width, int *height, int denom); void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool, - int num_pyramid_levels); + bool alloc_pyramid); // Returns 1 if a superres upscaled frame is scaled and 0 otherwise. static INLINE int av1_superres_scaled(const AV1_COMMON *cm) { diff --git a/third_party/aom/av1/common/restoration.c b/third_party/aom/av1/common/restoration.c index 0be126fa65..335fdc8c2a 100644 --- a/third_party/aom/av1/common/restoration.c +++ b/third_party/aom/av1/common/restoration.c @@ -11,20 +11,24 @@ */ #include +#include #include "config/aom_config.h" -#include "config/aom_dsp_rtcd.h" #include "config/aom_scale_rtcd.h" +#include "aom/internal/aom_codec_internal.h" #include "aom_mem/aom_mem.h" +#include "aom_dsp/aom_dsp_common.h" +#include "aom_mem/aom_mem.h" +#include "aom_ports/mem.h" +#include "aom_util/aom_pthread.h" + #include "av1/common/av1_common_int.h" +#include "av1/common/convolve.h" +#include "av1/common/enums.h" #include "av1/common/resize.h" #include "av1/common/restoration.h" #include "av1/common/thread_common.h" -#include "aom_dsp/aom_dsp_common.h" -#include "aom_mem/aom_mem.h" - -#include "aom_ports/mem.h" // The 's' values are calculated based on original 'r' and 'e' values in the // spec using GenSgrprojVtable(). @@ -115,8 +119,9 @@ void av1_loop_restoration_precal(void) { #endif } -static void extend_frame_lowbd(uint8_t *data, int width, int height, int stride, - int border_horz, int border_vert) { +static void extend_frame_lowbd(uint8_t *data, int width, int height, + ptrdiff_t stride, int border_horz, + int border_vert) { uint8_t *data_p; int i; for (i = 0; i < height; ++i) { @@ -136,7 +141,8 @@ static void extend_frame_lowbd(uint8_t *data, int width, int height, int stride, #if CONFIG_AV1_HIGHBITDEPTH static void extend_frame_highbd(uint16_t *data, int width, int height, - int stride, int border_horz, int border_vert) { + ptrdiff_t stride, int border_horz, + int border_vert) { uint16_t *data_p; int i, j; for (i = 0; i < height; ++i) { @@ -988,8 +994,10 @@ void av1_loop_restoration_filter_unit( int unit_h = limits->v_end - limits->v_start; int unit_w = limits->h_end - limits->h_start; - uint8_t *data8_tl = data8 + limits->v_start * stride + limits->h_start; - uint8_t *dst8_tl = dst8 + limits->v_start * dst_stride + limits->h_start; + uint8_t *data8_tl = + data8 + limits->v_start * (ptrdiff_t)stride + limits->h_start; + uint8_t *dst8_tl = + dst8 + limits->v_start * (ptrdiff_t)dst_stride + limits->h_start; if (unit_rtype == RESTORE_NONE) { copy_rest_unit(unit_w, unit_h, data8_tl, stride, dst8_tl, dst_stride, @@ -1074,7 +1082,8 @@ void av1_loop_restoration_filter_frame_init(AV1LrStruct *lr_ctxt, if (aom_realloc_frame_buffer( lr_ctxt->dst, frame_width, frame_height, seq_params->subsampling_x, seq_params->subsampling_y, highbd, AOM_RESTORATION_FRAME_BORDER, - cm->features.byte_alignment, NULL, NULL, NULL, 0, 0) != AOM_CODEC_OK) + cm->features.byte_alignment, NULL, NULL, NULL, false, + 0) != AOM_CODEC_OK) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate restoration dst buffer"); @@ -1349,7 +1358,7 @@ static void save_deblock_boundary_lines( const int is_uv = plane > 0; const uint8_t *src_buf = REAL_PTR(use_highbd, frame->buffers[plane]); const int src_stride = frame->strides[is_uv] << use_highbd; - const uint8_t *src_rows = src_buf + row * src_stride; + const uint8_t *src_rows = src_buf + row * (ptrdiff_t)src_stride; uint8_t *bdry_buf = is_above ? boundaries->stripe_boundary_above : boundaries->stripe_boundary_below; @@ -1404,7 +1413,7 @@ static void save_cdef_boundary_lines(const YV12_BUFFER_CONFIG *frame, const int is_uv = plane > 0; const uint8_t *src_buf = REAL_PTR(use_highbd, frame->buffers[plane]); const int src_stride = frame->strides[is_uv] << use_highbd; - const uint8_t *src_rows = src_buf + row * src_stride; + const uint8_t *src_rows = src_buf + row * (ptrdiff_t)src_stride; uint8_t *bdry_buf = is_above ? boundaries->stripe_boundary_above : boundaries->stripe_boundary_below; diff --git a/third_party/aom/av1/common/thread_common.c b/third_party/aom/av1/common/thread_common.c index 45695147ff..8a137cc9f7 100644 --- a/third_party/aom/av1/common/thread_common.c +++ b/third_party/aom/av1/common/thread_common.c @@ -14,12 +14,19 @@ #include "config/aom_scale_rtcd.h" #include "aom_dsp/aom_dsp_common.h" +#include "aom_dsp/txfm_common.h" #include "aom_mem/aom_mem.h" +#include "aom_util/aom_pthread.h" +#include "aom_util/aom_thread.h" #include "av1/common/av1_loopfilter.h" +#include "av1/common/blockd.h" +#include "av1/common/cdef.h" #include "av1/common/entropymode.h" +#include "av1/common/enums.h" #include "av1/common/thread_common.h" #include "av1/common/reconinter.h" #include "av1/common/reconintra.h" +#include "av1/common/restoration.h" // Set up nsync by width. static INLINE int get_sync_range(int width) { diff --git a/third_party/aom/av1/common/thread_common.h b/third_party/aom/av1/common/thread_common.h index 675687dc98..7e681f322b 100644 --- a/third_party/aom/av1/common/thread_common.h +++ b/third_party/aom/av1/common/thread_common.h @@ -16,6 +16,7 @@ #include "av1/common/av1_loopfilter.h" #include "av1/common/cdef.h" +#include "aom_util/aom_pthread.h" #include "aom_util/aom_thread.h" #ifdef __cplusplus diff --git a/third_party/aom/av1/common/tile_common.c b/third_party/aom/av1/common/tile_common.c index b964f259b8..45a189d69a 100644 --- a/third_party/aom/av1/common/tile_common.c +++ b/third_party/aom/av1/common/tile_common.c @@ -177,46 +177,16 @@ int av1_get_sb_cols_in_tile(const AV1_COMMON *cm, const TileInfo *tile) { cm->seq_params->mib_size_log2); } -PixelRect av1_get_tile_rect(const TileInfo *tile_info, const AV1_COMMON *cm, - int is_uv) { - PixelRect r; - - // Calculate position in the Y plane - r.left = tile_info->mi_col_start * MI_SIZE; - r.right = tile_info->mi_col_end * MI_SIZE; - r.top = tile_info->mi_row_start * MI_SIZE; - r.bottom = tile_info->mi_row_end * MI_SIZE; - - // If upscaling is enabled, the tile limits need scaling to match the - // upscaled frame where the restoration units live. To do this, scale up the - // top-left and bottom-right of the tile. - if (av1_superres_scaled(cm)) { - av1_calculate_unscaled_superres_size(&r.left, &r.top, - cm->superres_scale_denominator); - av1_calculate_unscaled_superres_size(&r.right, &r.bottom, - cm->superres_scale_denominator); - } - - const int frame_w = cm->superres_upscaled_width; - const int frame_h = cm->superres_upscaled_height; - - // Make sure we don't fall off the bottom-right of the frame. - r.right = AOMMIN(r.right, frame_w); - r.bottom = AOMMIN(r.bottom, frame_h); - - // Convert to coordinates in the appropriate plane - const int ss_x = is_uv && cm->seq_params->subsampling_x; - const int ss_y = is_uv && cm->seq_params->subsampling_y; - - r.left = ROUND_POWER_OF_TWO(r.left, ss_x); - r.right = ROUND_POWER_OF_TWO(r.right, ss_x); - r.top = ROUND_POWER_OF_TWO(r.top, ss_y); - r.bottom = ROUND_POWER_OF_TWO(r.bottom, ss_y); - - return r; -} - -void av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) { +// Section 7.3.1 of the AV1 spec says, on pages 200-201: +// It is a requirement of bitstream conformance that the following conditions +// are met: +// ... +// * TileHeight is equal to (use_128x128_superblock ? 128 : 64) for all +// tiles (i.e. the tile is exactly one superblock high) +// * TileWidth is identical for all tiles and is an integer multiple of +// TileHeight (i.e. the tile is an integer number of superblocks wide) +// ... +bool av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) { const CommonTileParams *const tiles = &cm->tiles; if (tiles->uniform_spacing) { *w = tiles->width; @@ -226,7 +196,10 @@ void av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) { const int tile_width_sb = tiles->col_start_sb[i + 1] - tiles->col_start_sb[i]; const int tile_w = tile_width_sb * cm->seq_params->mib_size; - assert(i == 0 || tile_w == *w); // ensure all tiles have same dimension + // ensure all tiles have same dimension + if (i != 0 && tile_w != *w) { + return false; + } *w = tile_w; } @@ -234,10 +207,14 @@ void av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) { const int tile_height_sb = tiles->row_start_sb[i + 1] - tiles->row_start_sb[i]; const int tile_h = tile_height_sb * cm->seq_params->mib_size; - assert(i == 0 || tile_h == *h); // ensure all tiles have same dimension + // ensure all tiles have same dimension + if (i != 0 && tile_h != *h) { + return false; + } *h = tile_h; } } + return true; } int av1_is_min_tile_width_satisfied(const AV1_COMMON *cm) { diff --git a/third_party/aom/av1/common/tile_common.h b/third_party/aom/av1/common/tile_common.h index 5383ae940b..12228c9e94 100644 --- a/third_party/aom/av1/common/tile_common.h +++ b/third_party/aom/av1/common/tile_common.h @@ -12,13 +12,14 @@ #ifndef AOM_AV1_COMMON_TILE_COMMON_H_ #define AOM_AV1_COMMON_TILE_COMMON_H_ +#include + +#include "config/aom_config.h" + #ifdef __cplusplus extern "C" { #endif -#include "config/aom_config.h" -#include "aom_dsp/rect.h" - struct AV1Common; struct SequenceHeader; struct CommonTileParams; @@ -43,10 +44,6 @@ void av1_tile_set_col(TileInfo *tile, const struct AV1Common *cm, int col); int av1_get_sb_rows_in_tile(const struct AV1Common *cm, const TileInfo *tile); int av1_get_sb_cols_in_tile(const struct AV1Common *cm, const TileInfo *tile); -// Return the pixel extents of the given tile -PixelRect av1_get_tile_rect(const TileInfo *tile_info, - const struct AV1Common *cm, int is_uv); - // Define tile maximum width and area // There is no maximum height since height is limited by area and width limits // The minimum tile width or height is fixed at one superblock @@ -56,7 +53,9 @@ PixelRect av1_get_tile_rect(const TileInfo *tile_info, #define MAX_TILE_AREA_LEVEL_7_AND_ABOVE (4096 * 4608) #endif -void av1_get_uniform_tile_size(const struct AV1Common *cm, int *w, int *h); +// Gets the width and height (in units of MI_SIZE) of the tiles in a tile list. +// Returns true on success, false on failure. +bool av1_get_uniform_tile_size(const struct AV1Common *cm, int *w, int *h); void av1_get_tile_limits(struct AV1Common *const cm); void av1_calculate_tile_cols(const struct SequenceHeader *const seq_params, int cm_mi_rows, int cm_mi_cols, diff --git a/third_party/aom/av1/common/x86/cdef_block_sse2.c b/third_party/aom/av1/common/x86/cdef_block_sse2.c deleted file mode 100644 index 5ab7ffa2ff..0000000000 --- a/third_party/aom/av1/common/x86/cdef_block_sse2.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016, Alliance for Open Media. All rights reserved - * - * This source code is subject to the terms of the BSD 2 Clause License and - * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License - * was not distributed with this source code in the LICENSE file, you can - * obtain it at www.aomedia.org/license/software. If the Alliance for Open - * Media Patent License 1.0 was not distributed with this source code in the - * PATENTS file, you can obtain it at www.aomedia.org/license/patent. - */ - -#include "aom_dsp/aom_simd.h" -#define SIMD_FUNC(name) name##_sse2 -#include "av1/common/cdef_block_simd.h" - -void cdef_find_dir_dual_sse2(const uint16_t *img1, const uint16_t *img2, - int stride, int32_t *var_out_1st, - int32_t *var_out_2nd, int coeff_shift, - int *out_dir_1st_8x8, int *out_dir_2nd_8x8) { - // Process first 8x8. - *out_dir_1st_8x8 = cdef_find_dir(img1, stride, var_out_1st, coeff_shift); - - // Process second 8x8. - *out_dir_2nd_8x8 = cdef_find_dir(img2, stride, var_out_2nd, coeff_shift); -} - -void cdef_copy_rect8_8bit_to_16bit_sse2(uint16_t *dst, int dstride, - const uint8_t *src, int sstride, - int width, int height) { - int j = 0; - for (int i = 0; i < height; i++) { - for (j = 0; j < (width & ~0x7); j += 8) { - v64 row = v64_load_unaligned(&src[i * sstride + j]); - v128_store_unaligned(&dst[i * dstride + j], v128_unpack_u8_s16(row)); - } - for (; j < width; j++) { - dst[i * dstride + j] = src[i * sstride + j]; - } - } -} diff --git a/third_party/aom/av1/common/x86/cdef_block_ssse3.c b/third_party/aom/av1/common/x86/cdef_block_ssse3.c index 0fb36eb6e0..14eb6c9e31 100644 --- a/third_party/aom/av1/common/x86/cdef_block_ssse3.c +++ b/third_party/aom/av1/common/x86/cdef_block_ssse3.c @@ -9,6 +9,17 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +// Include SSSE3 CDEF code only for 32-bit x86, to support Valgrind. +// For normal use, we require SSE4.1, so cdef_*_sse4_1 will be used instead of +// these functions. However, 32-bit Valgrind does not support SSE4.1, so we +// include a fallback to SSSE3 to improve performance + +#include "config/aom_config.h" + +#if !AOM_ARCH_X86 +#error "cdef_block_ssse3.c is included for compatibility with 32-bit x86 only" +#endif // !AOM_ARCH_X86 + #include "aom_dsp/aom_simd.h" #define SIMD_FUNC(name) name##_ssse3 #include "av1/common/cdef_block_simd.h" diff --git a/third_party/aom/av1/common/x86/convolve_2d_avx2.c b/third_party/aom/av1/common/x86/convolve_2d_avx2.c index 1b39a0a8d5..d4c1169cc3 100644 --- a/third_party/aom/av1/common/x86/convolve_2d_avx2.c +++ b/third_party/aom/av1/common/x86/convolve_2d_avx2.c @@ -21,13 +21,11 @@ #include "av1/common/convolve.h" -void av1_convolve_2d_sr_general_avx2(const uint8_t *src, int src_stride, - uint8_t *dst, int dst_stride, int w, int h, - const InterpFilterParams *filter_params_x, - const InterpFilterParams *filter_params_y, - const int subpel_x_qn, - const int subpel_y_qn, - ConvolveParams *conv_params) { +static void convolve_2d_sr_general_avx2( + const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int w, + int h, const InterpFilterParams *filter_params_x, + const InterpFilterParams *filter_params_y, const int subpel_x_qn, + const int subpel_y_qn, ConvolveParams *conv_params) { if (filter_params_x->taps > 8) { const int bd = 8; int im_stride = 8, i; @@ -150,9 +148,9 @@ void av1_convolve_2d_sr_avx2( const bool use_general = (tap_x == 12 || tap_y == 12); if (use_general) { - av1_convolve_2d_sr_general_avx2(src, src_stride, dst, dst_stride, w, h, - filter_params_x, filter_params_y, - subpel_x_q4, subpel_y_q4, conv_params); + convolve_2d_sr_general_avx2(src, src_stride, dst, dst_stride, w, h, + filter_params_x, filter_params_y, subpel_x_q4, + subpel_y_q4, conv_params); } else { av1_convolve_2d_sr_specialized_avx2(src, src_stride, dst, dst_stride, w, h, filter_params_x, filter_params_y, diff --git a/third_party/aom/av1/common/x86/convolve_2d_sse2.c b/third_party/aom/av1/common/x86/convolve_2d_sse2.c index 1b85f37294..68971eacc1 100644 --- a/third_party/aom/av1/common/x86/convolve_2d_sse2.c +++ b/third_party/aom/av1/common/x86/convolve_2d_sse2.c @@ -19,12 +19,11 @@ #include "aom_dsp/x86/convolve_common_intrin.h" #include "av1/common/convolve.h" -void av1_convolve_2d_sr_12tap_sse2(const uint8_t *src, int src_stride, - uint8_t *dst, int dst_stride, int w, int h, - const InterpFilterParams *filter_params_x, - const InterpFilterParams *filter_params_y, - const int subpel_x_qn, const int subpel_y_qn, - ConvolveParams *conv_params) { +static void convolve_2d_sr_12tap_sse2( + const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int w, + int h, const InterpFilterParams *filter_params_x, + const InterpFilterParams *filter_params_y, const int subpel_x_qn, + const int subpel_y_qn, ConvolveParams *conv_params) { const int bd = 8; DECLARE_ALIGNED(16, int16_t, @@ -231,9 +230,9 @@ void av1_convolve_2d_sr_sse2(const uint8_t *src, int src_stride, uint8_t *dst, filter_params_x, filter_params_y, subpel_x_qn, subpel_y_qn, conv_params); } else { - av1_convolve_2d_sr_12tap_sse2(src, src_stride, dst, dst_stride, w, h, - filter_params_x, filter_params_y, - subpel_x_qn, subpel_y_qn, conv_params); + convolve_2d_sr_12tap_sse2(src, src_stride, dst, dst_stride, w, h, + filter_params_x, filter_params_y, subpel_x_qn, + subpel_y_qn, conv_params); } } else { const int bd = 8; diff --git a/third_party/aom/av1/common/x86/convolve_sse2.c b/third_party/aom/av1/common/x86/convolve_sse2.c index 012e75c1ae..6383567a48 100644 --- a/third_party/aom/av1/common/x86/convolve_sse2.c +++ b/third_party/aom/av1/common/x86/convolve_sse2.c @@ -75,10 +75,10 @@ static INLINE __m128i convolve_hi_y(const __m128i *const s, return convolve(ss, coeffs); } -void av1_convolve_y_sr_12tap_sse2(const uint8_t *src, int src_stride, - uint8_t *dst, int dst_stride, int w, int h, - const InterpFilterParams *filter_params_y, - int subpel_y_qn) { +static void convolve_y_sr_12tap_sse2(const uint8_t *src, int src_stride, + uint8_t *dst, int dst_stride, int w, int h, + const InterpFilterParams *filter_params_y, + int subpel_y_qn) { const int fo_vert = filter_params_y->taps / 2 - 1; const uint8_t *src_ptr = src - fo_vert * src_stride; const __m128i round_const = _mm_set1_epi32((1 << FILTER_BITS) >> 1); @@ -185,8 +185,8 @@ void av1_convolve_y_sr_sse2(const uint8_t *src, int src_stride, uint8_t *dst, av1_convolve_y_sr_c(src, src_stride, dst, dst_stride, w, h, filter_params_y, subpel_y_qn); } else { - av1_convolve_y_sr_12tap_sse2(src, src_stride, dst, dst_stride, w, h, - filter_params_y, subpel_y_qn); + convolve_y_sr_12tap_sse2(src, src_stride, dst, dst_stride, w, h, + filter_params_y, subpel_y_qn); } } else { const int fo_vert = filter_params_y->taps / 2 - 1; @@ -337,11 +337,11 @@ void av1_convolve_y_sr_sse2(const uint8_t *src, int src_stride, uint8_t *dst, } } -void av1_convolve_x_sr_12tap_sse2(const uint8_t *src, int src_stride, - uint8_t *dst, int dst_stride, int w, int h, - const InterpFilterParams *filter_params_x, - int subpel_x_qn, - ConvolveParams *conv_params) { +static void convolve_x_sr_12tap_sse2(const uint8_t *src, int src_stride, + uint8_t *dst, int dst_stride, int w, int h, + const InterpFilterParams *filter_params_x, + int subpel_x_qn, + ConvolveParams *conv_params) { const int fo_horiz = filter_params_x->taps / 2 - 1; const uint8_t *src_ptr = src - fo_horiz; const int bits = FILTER_BITS - conv_params->round_0; @@ -402,8 +402,8 @@ void av1_convolve_x_sr_sse2(const uint8_t *src, int src_stride, uint8_t *dst, av1_convolve_x_sr_c(src, src_stride, dst, dst_stride, w, h, filter_params_x, subpel_x_qn, conv_params); } else { - av1_convolve_x_sr_12tap_sse2(src, src_stride, dst, dst_stride, w, h, - filter_params_x, subpel_x_qn, conv_params); + convolve_x_sr_12tap_sse2(src, src_stride, dst, dst_stride, w, h, + filter_params_x, subpel_x_qn, conv_params); } } else { const int fo_horiz = filter_params_x->taps / 2 - 1; diff --git a/third_party/aom/av1/common/x86/jnt_convolve_sse2.c b/third_party/aom/av1/common/x86/jnt_convolve_sse2.c index 8c5d9918fb..d5d2db7455 100644 --- a/third_party/aom/av1/common/x86/jnt_convolve_sse2.c +++ b/third_party/aom/av1/common/x86/jnt_convolve_sse2.c @@ -375,232 +375,3 @@ void av1_dist_wtd_convolve_y_sse2(const uint8_t *src, int src_stride, } while (j < w); } } - -void av1_dist_wtd_convolve_2d_sse2(const uint8_t *src, int src_stride, - uint8_t *dst0, int dst_stride0, int w, int h, - const InterpFilterParams *filter_params_x, - const InterpFilterParams *filter_params_y, - const int subpel_x_qn, const int subpel_y_qn, - ConvolveParams *conv_params) { - CONV_BUF_TYPE *dst = conv_params->dst; - int dst_stride = conv_params->dst_stride; - const int bd = 8; - - DECLARE_ALIGNED(16, int16_t, - im_block[(MAX_SB_SIZE + MAX_FILTER_TAP - 1) * MAX_SB_SIZE]); - int im_h = h + filter_params_y->taps - 1; - int im_stride = MAX_SB_SIZE; - int i, j; - const int fo_vert = filter_params_y->taps / 2 - 1; - const int fo_horiz = filter_params_x->taps / 2 - 1; - const int do_average = conv_params->do_average; - const int use_dist_wtd_comp_avg = conv_params->use_dist_wtd_comp_avg; - const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; - - const __m128i zero = _mm_setzero_si128(); - - const int w0 = conv_params->fwd_offset; - const int w1 = conv_params->bck_offset; - const __m128i wt0 = _mm_set1_epi16(w0); - const __m128i wt1 = _mm_set1_epi16(w1); - const __m128i wt = _mm_unpacklo_epi16(wt0, wt1); - - const int offset_0 = - bd + 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1; - const int offset = (1 << offset_0) + (1 << (offset_0 - 1)); - const __m128i offset_const = _mm_set1_epi16(offset); - const int rounding_shift = - 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1; - const __m128i rounding_const = _mm_set1_epi16((1 << rounding_shift) >> 1); - - /* Horizontal filter */ - { - const int16_t *x_filter = av1_get_interp_filter_subpel_kernel( - filter_params_x, subpel_x_qn & SUBPEL_MASK); - const __m128i coeffs_x = _mm_loadu_si128((__m128i *)x_filter); - - // coeffs 0 1 0 1 2 3 2 3 - const __m128i tmp_0 = _mm_unpacklo_epi32(coeffs_x, coeffs_x); - // coeffs 4 5 4 5 6 7 6 7 - const __m128i tmp_1 = _mm_unpackhi_epi32(coeffs_x, coeffs_x); - - // coeffs 0 1 0 1 0 1 0 1 - const __m128i coeff_01 = _mm_unpacklo_epi64(tmp_0, tmp_0); - // coeffs 2 3 2 3 2 3 2 3 - const __m128i coeff_23 = _mm_unpackhi_epi64(tmp_0, tmp_0); - // coeffs 4 5 4 5 4 5 4 5 - const __m128i coeff_45 = _mm_unpacklo_epi64(tmp_1, tmp_1); - // coeffs 6 7 6 7 6 7 6 7 - const __m128i coeff_67 = _mm_unpackhi_epi64(tmp_1, tmp_1); - - const __m128i round_const = _mm_set1_epi32( - ((1 << conv_params->round_0) >> 1) + (1 << (bd + FILTER_BITS - 1))); - const __m128i round_shift = _mm_cvtsi32_si128(conv_params->round_0); - - for (i = 0; i < im_h; ++i) { - for (j = 0; j < w; j += 8) { - __m128i temp_lo, temp_hi; - const __m128i data = - _mm_loadu_si128((__m128i *)&src_ptr[i * src_stride + j]); - - const __m128i src_lo = _mm_unpacklo_epi8(data, zero); - const __m128i src_hi = _mm_unpackhi_epi8(data, zero); - - // Filter even-index pixels - const __m128i res_0 = _mm_madd_epi16(src_lo, coeff_01); - temp_lo = _mm_srli_si128(src_lo, 4); - temp_hi = _mm_slli_si128(src_hi, 12); - const __m128i src_2 = _mm_or_si128(temp_hi, temp_lo); - const __m128i res_2 = _mm_madd_epi16(src_2, coeff_23); - temp_lo = _mm_srli_si128(src_lo, 8); - temp_hi = _mm_slli_si128(src_hi, 8); - const __m128i src_4 = _mm_or_si128(temp_hi, temp_lo); - const __m128i res_4 = _mm_madd_epi16(src_4, coeff_45); - temp_lo = _mm_srli_si128(src_lo, 12); - temp_hi = _mm_slli_si128(src_hi, 4); - const __m128i src_6 = _mm_or_si128(temp_hi, temp_lo); - const __m128i res_6 = _mm_madd_epi16(src_6, coeff_67); - - __m128i res_even = _mm_add_epi32(_mm_add_epi32(res_0, res_4), - _mm_add_epi32(res_2, res_6)); - res_even = - _mm_sra_epi32(_mm_add_epi32(res_even, round_const), round_shift); - - // Filter odd-index pixels - temp_lo = _mm_srli_si128(src_lo, 2); - temp_hi = _mm_slli_si128(src_hi, 14); - const __m128i src_1 = _mm_or_si128(temp_hi, temp_lo); - const __m128i res_1 = _mm_madd_epi16(src_1, coeff_01); - temp_lo = _mm_srli_si128(src_lo, 6); - temp_hi = _mm_slli_si128(src_hi, 10); - const __m128i src_3 = _mm_or_si128(temp_hi, temp_lo); - const __m128i res_3 = _mm_madd_epi16(src_3, coeff_23); - temp_lo = _mm_srli_si128(src_lo, 10); - temp_hi = _mm_slli_si128(src_hi, 6); - const __m128i src_5 = _mm_or_si128(temp_hi, temp_lo); - const __m128i res_5 = _mm_madd_epi16(src_5, coeff_45); - temp_lo = _mm_srli_si128(src_lo, 14); - temp_hi = _mm_slli_si128(src_hi, 2); - const __m128i src_7 = _mm_or_si128(temp_hi, temp_lo); - const __m128i res_7 = _mm_madd_epi16(src_7, coeff_67); - - __m128i res_odd = _mm_add_epi32(_mm_add_epi32(res_1, res_5), - _mm_add_epi32(res_3, res_7)); - res_odd = - _mm_sra_epi32(_mm_add_epi32(res_odd, round_const), round_shift); - - // Pack in the column order 0, 2, 4, 6, 1, 3, 5, 7 - __m128i res = _mm_packs_epi32(res_even, res_odd); - _mm_store_si128((__m128i *)&im_block[i * im_stride + j], res); - } - } - } - - /* Vertical filter */ - { - const int16_t *y_filter = av1_get_interp_filter_subpel_kernel( - filter_params_y, subpel_y_qn & SUBPEL_MASK); - const __m128i coeffs_y = _mm_loadu_si128((__m128i *)y_filter); - - // coeffs 0 1 0 1 2 3 2 3 - const __m128i tmp_0 = _mm_unpacklo_epi32(coeffs_y, coeffs_y); - // coeffs 4 5 4 5 6 7 6 7 - const __m128i tmp_1 = _mm_unpackhi_epi32(coeffs_y, coeffs_y); - - // coeffs 0 1 0 1 0 1 0 1 - const __m128i coeff_01 = _mm_unpacklo_epi64(tmp_0, tmp_0); - // coeffs 2 3 2 3 2 3 2 3 - const __m128i coeff_23 = _mm_unpackhi_epi64(tmp_0, tmp_0); - // coeffs 4 5 4 5 4 5 4 5 - const __m128i coeff_45 = _mm_unpacklo_epi64(tmp_1, tmp_1); - // coeffs 6 7 6 7 6 7 6 7 - const __m128i coeff_67 = _mm_unpackhi_epi64(tmp_1, tmp_1); - - const __m128i round_const = _mm_set1_epi32( - ((1 << conv_params->round_1) >> 1) - - (1 << (bd + 2 * FILTER_BITS - conv_params->round_0 - 1))); - const __m128i round_shift = _mm_cvtsi32_si128(conv_params->round_1); - - for (i = 0; i < h; ++i) { - for (j = 0; j < w; j += 8) { - // Filter even-index pixels - const int16_t *data = &im_block[i * im_stride + j]; - const __m128i src_0 = - _mm_unpacklo_epi16(*(__m128i *)(data + 0 * im_stride), - *(__m128i *)(data + 1 * im_stride)); - const __m128i src_2 = - _mm_unpacklo_epi16(*(__m128i *)(data + 2 * im_stride), - *(__m128i *)(data + 3 * im_stride)); - const __m128i src_4 = - _mm_unpacklo_epi16(*(__m128i *)(data + 4 * im_stride), - *(__m128i *)(data + 5 * im_stride)); - const __m128i src_6 = - _mm_unpacklo_epi16(*(__m128i *)(data + 6 * im_stride), - *(__m128i *)(data + 7 * im_stride)); - - const __m128i res_0 = _mm_madd_epi16(src_0, coeff_01); - const __m128i res_2 = _mm_madd_epi16(src_2, coeff_23); - const __m128i res_4 = _mm_madd_epi16(src_4, coeff_45); - const __m128i res_6 = _mm_madd_epi16(src_6, coeff_67); - - const __m128i res_even = _mm_add_epi32(_mm_add_epi32(res_0, res_2), - _mm_add_epi32(res_4, res_6)); - - // Filter odd-index pixels - const __m128i src_1 = - _mm_unpackhi_epi16(*(__m128i *)(data + 0 * im_stride), - *(__m128i *)(data + 1 * im_stride)); - const __m128i src_3 = - _mm_unpackhi_epi16(*(__m128i *)(data + 2 * im_stride), - *(__m128i *)(data + 3 * im_stride)); - const __m128i src_5 = - _mm_unpackhi_epi16(*(__m128i *)(data + 4 * im_stride), - *(__m128i *)(data + 5 * im_stride)); - const __m128i src_7 = - _mm_unpackhi_epi16(*(__m128i *)(data + 6 * im_stride), - *(__m128i *)(data + 7 * im_stride)); - - const __m128i res_1 = _mm_madd_epi16(src_1, coeff_01); - const __m128i res_3 = _mm_madd_epi16(src_3, coeff_23); - const __m128i res_5 = _mm_madd_epi16(src_5, coeff_45); - const __m128i res_7 = _mm_madd_epi16(src_7, coeff_67); - - const __m128i res_odd = _mm_add_epi32(_mm_add_epi32(res_1, res_3), - _mm_add_epi32(res_5, res_7)); - - // Rearrange pixels back into the order 0 ... 7 - const __m128i res_lo = _mm_unpacklo_epi32(res_even, res_odd); - const __m128i res_hi = _mm_unpackhi_epi32(res_even, res_odd); - - const __m128i res_lo_round = - _mm_sra_epi32(_mm_add_epi32(res_lo, round_const), round_shift); - const __m128i res_hi_round = - _mm_sra_epi32(_mm_add_epi32(res_hi, round_const), round_shift); - - const __m128i res_16b = _mm_packs_epi32(res_lo_round, res_hi_round); - const __m128i res_unsigned = _mm_add_epi16(res_16b, offset_const); - - // Accumulate values into the destination buffer - if (do_average) { - const __m128i data_ref_0 = - _mm_loadu_si128((__m128i *)(&dst[i * dst_stride + j])); - - const __m128i comp_avg_res = - comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg); - - const __m128i round_result = convolve_rounding( - &comp_avg_res, &offset_const, &rounding_const, rounding_shift); - - const __m128i res_8 = _mm_packus_epi16(round_result, round_result); - - if (w > 4) - _mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_8); - else - *(int *)(&dst0[i * dst_stride0 + j]) = _mm_cvtsi128_si32(res_8); - } else { - _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_unsigned); - } - } - } - } -} diff --git a/third_party/aom/av1/decoder/decodeframe.c b/third_party/aom/av1/decoder/decodeframe.c index bb09347e1c..c027308ff3 100644 --- a/third_party/aom/av1/decoder/decodeframe.c +++ b/third_party/aom/av1/decoder/decodeframe.c @@ -14,20 +14,23 @@ #include #include "config/aom_config.h" -#include "config/aom_dsp_rtcd.h" #include "config/aom_scale_rtcd.h" -#include "config/av1_rtcd.h" #include "aom/aom_codec.h" +#include "aom/aom_image.h" +#include "aom/internal/aom_codec_internal.h" #include "aom_dsp/aom_dsp_common.h" #include "aom_dsp/binary_codes_reader.h" #include "aom_dsp/bitreader.h" #include "aom_dsp/bitreader_buffer.h" +#include "aom_dsp/txfm_common.h" #include "aom_mem/aom_mem.h" #include "aom_ports/aom_timer.h" #include "aom_ports/mem.h" #include "aom_ports/mem_ops.h" #include "aom_scale/aom_scale.h" +#include "aom_scale/yv12config.h" +#include "aom_util/aom_pthread.h" #include "aom_util/aom_thread.h" #if CONFIG_BITSTREAM_DEBUG || CONFIG_MISMATCH_DEBUG @@ -35,33 +38,41 @@ #endif // CONFIG_BITSTREAM_DEBUG || CONFIG_MISMATCH_DEBUG #include "av1/common/alloccommon.h" +#include "av1/common/av1_common_int.h" +#include "av1/common/blockd.h" #include "av1/common/cdef.h" #include "av1/common/cfl.h" -#if CONFIG_INSPECTION -#include "av1/decoder/inspection.h" -#endif +#include "av1/common/common_data.h" #include "av1/common/common.h" #include "av1/common/entropy.h" #include "av1/common/entropymode.h" #include "av1/common/entropymv.h" +#include "av1/common/enums.h" #include "av1/common/frame_buffers.h" #include "av1/common/idct.h" +#include "av1/common/mv.h" #include "av1/common/mvref_common.h" +#include "av1/common/obmc.h" #include "av1/common/pred_common.h" #include "av1/common/quant_common.h" #include "av1/common/reconinter.h" #include "av1/common/reconintra.h" #include "av1/common/resize.h" +#include "av1/common/restoration.h" +#include "av1/common/scale.h" #include "av1/common/seg_common.h" #include "av1/common/thread_common.h" #include "av1/common/tile_common.h" #include "av1/common/warped_motion.h" -#include "av1/common/obmc.h" + #include "av1/decoder/decodeframe.h" #include "av1/decoder/decodemv.h" #include "av1/decoder/decoder.h" #include "av1/decoder/decodetxb.h" #include "av1/decoder/detokenize.h" +#if CONFIG_INSPECTION +#include "av1/decoder/inspection.h" +#endif #define ACCT_STR __func__ @@ -1935,8 +1946,8 @@ static AOM_INLINE void setup_buffer_pool(AV1_COMMON *cm) { &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, AOM_DEC_BORDER_IN_PIXELS, cm->features.byte_alignment, - &cm->cur_frame->raw_frame_buffer, pool->get_fb_cb, pool->cb_priv, 0, - 0)) { + &cm->cur_frame->raw_frame_buffer, pool->get_fb_cb, pool->cb_priv, + false, 0)) { unlock_buffer_pool(pool); aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate frame buffer"); @@ -2293,7 +2304,11 @@ static const uint8_t *get_ls_tile_buffers( const int tile_col_size_bytes = pbi->tile_col_size_bytes; const int tile_size_bytes = pbi->tile_size_bytes; int tile_width, tile_height; - av1_get_uniform_tile_size(cm, &tile_width, &tile_height); + if (!av1_get_uniform_tile_size(cm, &tile_width, &tile_height)) { + aom_internal_error( + &pbi->error, AOM_CODEC_CORRUPT_FRAME, + "Not all the tiles in the tile list have the same size."); + } const int tile_copy_mode = ((AOMMAX(tile_width, tile_height) << MI_SIZE_LOG2) <= 256) ? 1 : 0; // Read tile column sizes for all columns (we need the last tile buffer) @@ -2302,8 +2317,16 @@ static const uint8_t *get_ls_tile_buffers( size_t tile_col_size; if (!is_last) { + if (tile_col_size_bytes > data_end - data) { + aom_internal_error(&pbi->error, AOM_CODEC_CORRUPT_FRAME, + "Not enough data to read tile_col_size"); + } tile_col_size = mem_get_varsize(data, tile_col_size_bytes); data += tile_col_size_bytes; + if (tile_col_size > (size_t)(data_end - data)) { + aom_internal_error(&pbi->error, AOM_CODEC_CORRUPT_FRAME, + "tile_col_data_end[%d] is out of bound", c); + } tile_col_data_end[c] = data + tile_col_size; } else { tile_col_size = data_end - data; @@ -3871,8 +3894,8 @@ static AOM_INLINE void read_bitdepth( #endif } -void av1_read_film_grain_params(AV1_COMMON *cm, - struct aom_read_bit_buffer *rb) { +static void read_film_grain_params(AV1_COMMON *cm, + struct aom_read_bit_buffer *rb) { aom_film_grain_t *pars = &cm->film_grain_params; const SequenceHeader *const seq_params = cm->seq_params; @@ -4040,7 +4063,7 @@ static AOM_INLINE void read_film_grain(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { if (cm->seq_params->film_grain_params_present && (cm->show_frame || cm->showable_frame)) { - av1_read_film_grain_params(cm, rb); + read_film_grain_params(cm, rb); } else { memset(&cm->film_grain_params, 0, sizeof(cm->film_grain_params)); } @@ -4768,7 +4791,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, seq_params->max_frame_height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, AOM_BORDER_IN_PIXELS, features->byte_alignment, - &buf->raw_frame_buffer, pool->get_fb_cb, pool->cb_priv, 0, + &buf->raw_frame_buffer, pool->get_fb_cb, pool->cb_priv, false, 0)) { decrease_ref_count(buf, pool); unlock_buffer_pool(pool); diff --git a/third_party/aom/av1/decoder/decodemv.h b/third_party/aom/av1/decoder/decodemv.h index 3d8629c9a5..7e77c030f8 100644 --- a/third_party/aom/av1/decoder/decodemv.h +++ b/third_party/aom/av1/decoder/decodemv.h @@ -20,6 +20,8 @@ extern "C" { #endif +int av1_neg_deinterleave(int diff, int ref, int max); + void av1_read_mode_info(AV1Decoder *const pbi, DecoderCodingBlock *dcb, aom_reader *r, int x_mis, int y_mis); diff --git a/third_party/aom/av1/decoder/decoder.c b/third_party/aom/av1/decoder/decoder.c index 32e94840be..a886ed469c 100644 --- a/third_party/aom/av1/decoder/decoder.c +++ b/third_party/aom/av1/decoder/decoder.c @@ -21,6 +21,7 @@ #include "aom_mem/aom_mem.h" #include "aom_ports/aom_timer.h" #include "aom_scale/aom_scale.h" +#include "aom_util/aom_pthread.h" #include "aom_util/aom_thread.h" #include "av1/common/alloccommon.h" diff --git a/third_party/aom/av1/decoder/dthread.h b/third_party/aom/av1/decoder/dthread.h index f82b9d8ccf..b0f6fda829 100644 --- a/third_party/aom/av1/decoder/dthread.h +++ b/third_party/aom/av1/decoder/dthread.h @@ -14,7 +14,6 @@ #include "config/aom_config.h" -#include "aom_util/aom_thread.h" #include "aom/internal/aom_codec_internal.h" #ifdef __cplusplus diff --git a/third_party/aom/av1/decoder/obu.c b/third_party/aom/av1/decoder/obu.c index 0e31ce9404..e0b2d87c32 100644 --- a/third_party/aom/av1/decoder/obu.c +++ b/third_party/aom/av1/decoder/obu.c @@ -367,16 +367,13 @@ static uint32_t read_one_tile_group_obu( return header_size + tg_payload_size; } -static void alloc_tile_list_buffer(AV1Decoder *pbi) { +static void alloc_tile_list_buffer(AV1Decoder *pbi, int tile_width_in_pixels, + int tile_height_in_pixels) { // The resolution of the output frame is read out from the bitstream. The data // are stored in the order of Y plane, U plane and V plane. As an example, for // image format 4:2:0, the output frame of U plane and V plane is 1/4 of the // output frame. AV1_COMMON *const cm = &pbi->common; - int tile_width, tile_height; - av1_get_uniform_tile_size(cm, &tile_width, &tile_height); - const int tile_width_in_pixels = tile_width * MI_SIZE; - const int tile_height_in_pixels = tile_height * MI_SIZE; const int output_frame_width = (pbi->output_frame_width_in_tiles_minus_1 + 1) * tile_width_in_pixels; const int output_frame_height = @@ -396,7 +393,7 @@ static void alloc_tile_list_buffer(AV1Decoder *pbi) { cm->seq_params->subsampling_y, (cm->seq_params->use_highbitdepth && (cm->seq_params->bit_depth > AOM_BITS_8)), - 0, cm->features.byte_alignment, 0, 0)) + 0, cm->features.byte_alignment, false, 0)) aom_internal_error(&pbi->error, AOM_CODEC_MEM_ERROR, "Failed to allocate the tile list output buffer"); } @@ -424,13 +421,10 @@ static void yv12_tile_copy(const YV12_BUFFER_CONFIG *src, int hstart1, return; } -static void copy_decoded_tile_to_tile_list_buffer(AV1Decoder *pbi, - int tile_idx) { +static void copy_decoded_tile_to_tile_list_buffer(AV1Decoder *pbi, int tile_idx, + int tile_width_in_pixels, + int tile_height_in_pixels) { AV1_COMMON *const cm = &pbi->common; - int tile_width, tile_height; - av1_get_uniform_tile_size(cm, &tile_width, &tile_height); - const int tile_width_in_pixels = tile_width * MI_SIZE; - const int tile_height_in_pixels = tile_height * MI_SIZE; const int ssy = cm->seq_params->subsampling_y; const int ssx = cm->seq_params->subsampling_x; const int num_planes = av1_num_planes(cm); @@ -501,13 +495,31 @@ static uint32_t read_and_decode_one_tile_list(AV1Decoder *pbi, pbi->output_frame_width_in_tiles_minus_1 = aom_rb_read_literal(rb, 8); pbi->output_frame_height_in_tiles_minus_1 = aom_rb_read_literal(rb, 8); pbi->tile_count_minus_1 = aom_rb_read_literal(rb, 16); + + // The output frame is used to store the decoded tile list. The decoded tile + // list has to fit into 1 output frame. + if ((pbi->tile_count_minus_1 + 1) > + (pbi->output_frame_width_in_tiles_minus_1 + 1) * + (pbi->output_frame_height_in_tiles_minus_1 + 1)) { + pbi->error.error_code = AOM_CODEC_CORRUPT_FRAME; + return 0; + } + if (pbi->tile_count_minus_1 > MAX_TILES - 1) { pbi->error.error_code = AOM_CODEC_CORRUPT_FRAME; return 0; } + int tile_width, tile_height; + if (!av1_get_uniform_tile_size(cm, &tile_width, &tile_height)) { + pbi->error.error_code = AOM_CODEC_CORRUPT_FRAME; + return 0; + } + const int tile_width_in_pixels = tile_width * MI_SIZE; + const int tile_height_in_pixels = tile_height * MI_SIZE; + // Allocate output frame buffer for the tile list. - alloc_tile_list_buffer(pbi); + alloc_tile_list_buffer(pbi, tile_width_in_pixels, tile_height_in_pixels); uint32_t tile_list_info_bytes = 4; tile_list_payload_size += tile_list_info_bytes; @@ -558,7 +570,8 @@ static uint32_t read_and_decode_one_tile_list(AV1Decoder *pbi, assert(data <= data_end); // Copy the decoded tile to the tile list output buffer. - copy_decoded_tile_to_tile_list_buffer(pbi, tile_idx); + copy_decoded_tile_to_tile_list_buffer(pbi, tile_idx, tile_width_in_pixels, + tile_height_in_pixels); tile_idx++; } diff --git a/third_party/aom/av1/encoder/allintra_vis.c b/third_party/aom/av1/encoder/allintra_vis.c index 8dcef5fc85..87becb80ef 100644 --- a/third_party/aom/av1/encoder/allintra_vis.c +++ b/third_party/aom/av1/encoder/allintra_vis.c @@ -13,6 +13,8 @@ #include "config/aom_config.h" +#include "aom_util/aom_pthread.h" + #if CONFIG_TFLITE #include "tensorflow/lite/c/c_api.h" #include "av1/encoder/deltaq4_model.c" @@ -588,7 +590,7 @@ void av1_set_mb_wiener_variance(AV1_COMP *cpi) { &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL, - NULL, cpi->image_pyramid_levels, 0)) + NULL, cpi->alloc_pyramid, 0)) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate frame buffer"); av1_alloc_mb_wiener_var_pred_buf(&cpi->common, &cpi->td); diff --git a/third_party/aom/av1/encoder/aq_cyclicrefresh.c b/third_party/aom/av1/encoder/aq_cyclicrefresh.c index f48ff11e51..1aa8dde323 100644 --- a/third_party/aom/av1/encoder/aq_cyclicrefresh.c +++ b/third_party/aom/av1/encoder/aq_cyclicrefresh.c @@ -15,6 +15,7 @@ #include "av1/common/pred_common.h" #include "av1/common/seg_common.h" #include "av1/encoder/aq_cyclicrefresh.h" +#include "av1/encoder/encoder_utils.h" #include "av1/encoder/ratectrl.h" #include "av1/encoder/segmentation.h" #include "av1/encoder/tokenize.h" @@ -295,6 +296,7 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { const CommonModeInfoParams *const mi_params = &cm->mi_params; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; unsigned char *const seg_map = cpi->enc_seg.map; + unsigned char *const active_map_4x4 = cpi->active_map.map; int i, block_count, bl_index, sb_rows, sb_cols, sbs_in_frame; int xmis, ymis, x, y; uint64_t sb_sad = 0; @@ -302,7 +304,12 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { uint64_t thresh_sad = INT64_MAX; const int mi_rows = mi_params->mi_rows, mi_cols = mi_params->mi_cols; const int mi_stride = mi_cols; - memset(seg_map, CR_SEGMENT_ID_BASE, mi_rows * mi_cols); + // Don't set seg_map to 0 if active_maps is enabled. Active_maps will set + // seg_map to either 7 or 0 (AM_SEGMENT_ID_INACTIVE/ACTIVE), and cyclic + // refresh set below (segment 1 or 2) will only be set for ACTIVE blocks. + if (!cpi->active_map.enabled) { + memset(seg_map, CR_SEGMENT_ID_BASE, mi_rows * mi_cols); + } sb_cols = (mi_cols + cm->seq_params->mib_size - 1) / cm->seq_params->mib_size; sb_rows = (mi_rows + cm->seq_params->mib_size - 1) / cm->seq_params->mib_size; sbs_in_frame = sb_cols * sb_rows; @@ -357,7 +364,10 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { // for possible boost/refresh (segment 1). The segment id may get // reset to 0 later if block gets coded anything other than low motion. // If the block_sad (sb_sad) is very low label it for refresh anyway. - if (cr->map[bl_index2] == 0 || sb_sad < thresh_sad_low) { + // If active_maps is enabled, only allow for setting on ACTIVE blocks. + if ((cr->map[bl_index2] == 0 || sb_sad < thresh_sad_low) && + (!cpi->active_map.enabled || + active_map_4x4[bl_index2] == AM_SEGMENT_ID_ACTIVE)) { sum_map += 4; } else if (cr->map[bl_index2] < 0) { cr->map[bl_index2]++; @@ -380,7 +390,8 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { cr->sb_index = i; if (cr->target_num_seg_blocks == 0) { // Disable segmentation, seg_map is already set to 0 above. - av1_disable_segmentation(&cm->seg); + // Don't disable if active_map is being used. + if (!cpi->active_map.enabled) av1_disable_segmentation(&cm->seg); } } @@ -423,8 +434,6 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { // function av1_cyclic_reset_segment_skip(). Skipping over // 4x4 will therefore have small bdrate loss (~0.2%), so // we use it only for speed > 9 for now. - // Also if loop-filter deltas is applied via segment, then - // we need to set cr->skip_over4x4 = 1. cr->skip_over4x4 = (cpi->oxcf.speed > 9) ? 1 : 0; // should we enable cyclic refresh on this frame. @@ -450,6 +459,15 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { else cr->percent_refresh = 10 + cr->percent_refresh_adjustment; + if (cpi->active_map.enabled) { + // Scale down the percent_refresh to target the active blocks only. + cr->percent_refresh = + cr->percent_refresh * (100 - cpi->rc.percent_blocks_inactive) / 100; + if (cr->percent_refresh == 0) { + cr->apply_cyclic_refresh = 0; + } + } + cr->max_qdelta_perc = 60; cr->time_for_refresh = 0; cr->use_block_sad_scene_det = @@ -543,10 +561,14 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) { if (resolution_change) av1_cyclic_refresh_reset_resize(cpi); if (!cr->apply_cyclic_refresh) { - // Set segmentation map to 0 and disable. - unsigned char *const seg_map = cpi->enc_seg.map; - memset(seg_map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols); - av1_disable_segmentation(&cm->seg); + // Don't disable and set seg_map to 0 if active_maps is enabled, unless + // whole frame is set as inactive (since we only apply cyclic_refresh to + // active blocks). + if (!cpi->active_map.enabled || cpi->rc.percent_blocks_inactive == 100) { + unsigned char *const seg_map = cpi->enc_seg.map; + memset(seg_map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols); + av1_disable_segmentation(&cm->seg); + } if (frame_is_intra_only(cm) || scene_change_detected || cpi->ppi->rtc_ref.bias_recovery_frame) { cr->sb_index = 0; @@ -574,9 +596,11 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) { cr->thresh_rate_sb = INT64_MAX; } // Set up segmentation. - // Clear down the segment map. av1_enable_segmentation(&cm->seg); - av1_clearall_segfeatures(seg); + if (!cpi->active_map.enabled) { + // Clear down the segment map, only if active_maps is not enabled. + av1_clearall_segfeatures(seg); + } // Note: setting temporal_update has no effect, as the seg-map coding method // (temporal or spatial) is determined in @@ -644,6 +668,10 @@ void av1_cyclic_refresh_reset_resize(AV1_COMP *const cpi) { int av1_cyclic_refresh_disable_lf_cdef(AV1_COMP *const cpi) { CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; const int qindex = cpi->common.quant_params.base_qindex; + if (cpi->active_map.enabled && + cpi->rc.percent_blocks_inactive > + cpi->sf.rt_sf.thresh_active_maps_skip_lf_cdef) + return 1; if (cpi->rc.frames_since_key > 30 && cr->percent_refresh > 0 && cr->counter_encode_maxq_scene_change > 300 / cr->percent_refresh && cpi->rc.frame_source_sad < 1000 && diff --git a/third_party/aom/av1/encoder/arm/neon/av1_error_sve.c b/third_party/aom/av1/encoder/arm/neon/av1_error_sve.c index 63aad0b785..52803a9838 100644 --- a/third_party/aom/av1/encoder/arm/neon/av1_error_sve.c +++ b/third_party/aom/av1/encoder/arm/neon/av1_error_sve.c @@ -14,7 +14,7 @@ #include "config/aom_config.h" #include "aom_dsp/aom_dsp_common.h" -#include "aom_dsp/arm/dot_sve.h" +#include "aom_dsp/arm/aom_neon_sve_bridge.h" #include "aom_dsp/arm/mem_neon.h" int64_t av1_block_error_sve(const tran_low_t *coeff, const tran_low_t *dqcoeff, diff --git a/third_party/aom/av1/encoder/arm/neon/temporal_filter_neon_dotprod.c b/third_party/aom/av1/encoder/arm/neon/temporal_filter_neon_dotprod.c index 5a52e701a2..919521fec7 100644 --- a/third_party/aom/av1/encoder/arm/neon/temporal_filter_neon_dotprod.c +++ b/third_party/aom/av1/encoder/arm/neon/temporal_filter_neon_dotprod.c @@ -23,7 +23,15 @@ #define SSE_STRIDE (BW + 4) // clang-format off +// Table used to pad the first and last columns and apply the sliding window. +DECLARE_ALIGNED(16, static const uint8_t, kLoadPad[4][16]) = { + { 2, 2, 2, 3, 4, 255, 255, 255, 255, 2, 2, 3, 4, 5, 255, 255 }, + { 255, 255, 2, 3, 4, 5, 6, 255, 255, 255, 255, 3, 4, 5, 6, 7 }, + { 0, 1, 2, 3, 4, 255, 255, 255, 255, 1, 2, 3, 4, 5, 255, 255 }, + { 255, 255, 2, 3, 4, 5, 5, 255, 255, 255, 255, 3, 4, 5, 5, 5 } +}; +// For columns that don't need to be padded it's just a simple mask. DECLARE_ALIGNED(16, static const uint8_t, kSlidingWindowMask[]) = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, @@ -56,22 +64,6 @@ static INLINE void get_abs_diff(const uint8_t *frame1, const uint32_t stride1, } while (++i < block_height); } -static INLINE uint8x16_t load_and_pad(const uint8_t *src, const uint32_t col, - const uint32_t block_width) { - uint8x8_t s = vld1_u8(src); - - if (col == 0) { - const uint8_t lane2 = vget_lane_u8(s, 2); - s = vset_lane_u8(lane2, s, 0); - s = vset_lane_u8(lane2, s, 1); - } else if (col >= block_width - 4) { - const uint8_t lane5 = vget_lane_u8(s, 5); - s = vset_lane_u8(lane5, s, 6); - s = vset_lane_u8(lane5, s, 7); - } - return vcombine_u8(s, s); -} - static void apply_temporal_filter( const uint8_t *frame, const unsigned int stride, const uint32_t block_width, const uint32_t block_height, const int *subblock_mses, @@ -84,6 +76,10 @@ static void apply_temporal_filter( uint32_t acc_5x5_neon[BH][BW]; const uint8x16x2_t vmask = vld1q_u8_x2(kSlidingWindowMask); + const uint8x16_t pad_tbl0 = vld1q_u8(kLoadPad[0]); + const uint8x16_t pad_tbl1 = vld1q_u8(kLoadPad[1]); + const uint8x16_t pad_tbl2 = vld1q_u8(kLoadPad[2]); + const uint8x16_t pad_tbl3 = vld1q_u8(kLoadPad[3]); // Traverse 4 columns at a time - first and last two columns need padding. for (uint32_t col = 0; col < block_width; col += 4) { @@ -92,9 +88,18 @@ static void apply_temporal_filter( // Load, pad (for first and last two columns) and mask 3 rows from the top. for (int i = 2; i < 5; i++) { - const uint8x16_t s = load_and_pad(src, col, block_width); - vsrc[i][0] = vandq_u8(s, vmask.val[0]); - vsrc[i][1] = vandq_u8(s, vmask.val[1]); + uint8x8_t s = vld1_u8(src); + uint8x16_t s_dup = vcombine_u8(s, s); + if (col == 0) { + vsrc[i][0] = vqtbl1q_u8(s_dup, pad_tbl0); + vsrc[i][1] = vqtbl1q_u8(s_dup, pad_tbl1); + } else if (col >= block_width - 4) { + vsrc[i][0] = vqtbl1q_u8(s_dup, pad_tbl2); + vsrc[i][1] = vqtbl1q_u8(s_dup, pad_tbl3); + } else { + vsrc[i][0] = vandq_u8(s_dup, vmask.val[0]); + vsrc[i][1] = vandq_u8(s_dup, vmask.val[1]); + } src += SSE_STRIDE; } @@ -130,9 +135,18 @@ static void apply_temporal_filter( if (row <= block_height - 4) { // Load next row into the bottom of the sliding window. - uint8x16_t s = load_and_pad(src, col, block_width); - vsrc[4][0] = vandq_u8(s, vmask.val[0]); - vsrc[4][1] = vandq_u8(s, vmask.val[1]); + uint8x8_t s = vld1_u8(src); + uint8x16_t s_dup = vcombine_u8(s, s); + if (col == 0) { + vsrc[4][0] = vqtbl1q_u8(s_dup, pad_tbl0); + vsrc[4][1] = vqtbl1q_u8(s_dup, pad_tbl1); + } else if (col >= block_width - 4) { + vsrc[4][0] = vqtbl1q_u8(s_dup, pad_tbl2); + vsrc[4][1] = vqtbl1q_u8(s_dup, pad_tbl3); + } else { + vsrc[4][0] = vandq_u8(s_dup, vmask.val[0]); + vsrc[4][1] = vandq_u8(s_dup, vmask.val[1]); + } src += SSE_STRIDE; } else { // Pad the bottom 2 rows. diff --git a/third_party/aom/av1/encoder/arm/neon/wedge_utils_sve.c b/third_party/aom/av1/encoder/arm/neon/wedge_utils_sve.c new file mode 100644 index 0000000000..521601a3f3 --- /dev/null +++ b/third_party/aom/av1/encoder/arm/neon/wedge_utils_sve.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include +#include + +#include "aom_dsp/arm/aom_neon_sve_bridge.h" +#include "aom_dsp/arm/sum_neon.h" +#include "av1/common/reconinter.h" + +uint64_t av1_wedge_sse_from_residuals_sve(const int16_t *r1, const int16_t *d, + const uint8_t *m, int N) { + assert(N % 64 == 0); + + // Predicate pattern with first 8 elements true. + const svbool_t pattern = svptrue_pat_b16(SV_VL8); + int64x2_t sse[2] = { vdupq_n_s64(0), vdupq_n_s64(0) }; + + int i = 0; + do { + int32x4_t sum[4]; + int16x8_t sum_s16[2]; + + const int16x8_t r1_l = vld1q_s16(r1 + i); + const int16x8_t r1_h = vld1q_s16(r1 + i + 8); + const int16x8_t d_l = vld1q_s16(d + i); + const int16x8_t d_h = vld1q_s16(d + i + 8); + + // Use a zero-extending load to widen the vector elements. + const int16x8_t m_l = svget_neonq_s16(svld1ub_s16(pattern, m + i)); + const int16x8_t m_h = svget_neonq_s16(svld1ub_s16(pattern, m + i + 8)); + + sum[0] = vshll_n_s16(vget_low_s16(r1_l), WEDGE_WEIGHT_BITS); + sum[1] = vshll_n_s16(vget_high_s16(r1_l), WEDGE_WEIGHT_BITS); + sum[2] = vshll_n_s16(vget_low_s16(r1_h), WEDGE_WEIGHT_BITS); + sum[3] = vshll_n_s16(vget_high_s16(r1_h), WEDGE_WEIGHT_BITS); + + sum[0] = vmlal_s16(sum[0], vget_low_s16(m_l), vget_low_s16(d_l)); + sum[1] = vmlal_s16(sum[1], vget_high_s16(m_l), vget_high_s16(d_l)); + sum[2] = vmlal_s16(sum[2], vget_low_s16(m_h), vget_low_s16(d_h)); + sum[3] = vmlal_s16(sum[3], vget_high_s16(m_h), vget_high_s16(d_h)); + + sum_s16[0] = vcombine_s16(vqmovn_s32(sum[0]), vqmovn_s32(sum[1])); + sum_s16[1] = vcombine_s16(vqmovn_s32(sum[2]), vqmovn_s32(sum[3])); + + sse[0] = aom_sdotq_s16(sse[0], sum_s16[0], sum_s16[0]); + sse[1] = aom_sdotq_s16(sse[1], sum_s16[1], sum_s16[1]); + + i += 16; + } while (i < N); + + const uint64_t csse = + (uint64_t)horizontal_add_s64x2(vaddq_s64(sse[0], sse[1])); + return ROUND_POWER_OF_TWO(csse, 2 * WEDGE_WEIGHT_BITS); +} + +int8_t av1_wedge_sign_from_residuals_sve(const int16_t *ds, const uint8_t *m, + int N, int64_t limit) { + assert(N % 16 == 0); + + // Predicate pattern with first 8 elements true. + svbool_t pattern = svptrue_pat_b16(SV_VL8); + int64x2_t acc_l = vdupq_n_s64(0); + int64x2_t acc_h = vdupq_n_s64(0); + + do { + const int16x8_t ds_l = vld1q_s16(ds); + const int16x8_t ds_h = vld1q_s16(ds + 8); + + // Use a zero-extending load to widen the vector elements. + const int16x8_t m_l = svget_neonq_s16(svld1ub_s16(pattern, m)); + const int16x8_t m_h = svget_neonq_s16(svld1ub_s16(pattern, m + 8)); + + acc_l = aom_sdotq_s16(acc_l, ds_l, m_l); + acc_h = aom_sdotq_s16(acc_h, ds_h, m_h); + + ds += 16; + m += 16; + N -= 16; + } while (N != 0); + + const int64x2_t sum = vaddq_s64(acc_l, acc_h); + return horizontal_add_s64x2(sum) > limit; +} diff --git a/third_party/aom/av1/encoder/av1_temporal_denoiser.c b/third_party/aom/av1/encoder/av1_temporal_denoiser.c index 3012df6311..d4a1625612 100644 --- a/third_party/aom/av1/encoder/av1_temporal_denoiser.c +++ b/third_party/aom/av1/encoder/av1_temporal_denoiser.c @@ -489,7 +489,7 @@ static int av1_denoiser_realloc_svc_helper(AV1_COMMON *cm, &denoiser->running_avg_y[fb_idx], cm->width, cm->height, cm->seq_params->subsampling_x, cm->seq_params->subsampling_y, cm->seq_params->use_highbitdepth, AOM_BORDER_IN_PIXELS, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); if (fail) { av1_denoiser_free(denoiser); return 1; @@ -577,7 +577,7 @@ int av1_denoiser_alloc(AV1_COMMON *cm, struct SVC *svc, AV1_DENOISER *denoiser, fail = aom_alloc_frame_buffer( &denoiser->running_avg_y[i + denoiser->num_ref_frames * layer], denoise_width, denoise_height, ssx, ssy, use_highbitdepth, border, - legacy_byte_alignment, 0, 0); + legacy_byte_alignment, false, 0); if (fail) { av1_denoiser_free(denoiser); return 1; @@ -589,7 +589,7 @@ int av1_denoiser_alloc(AV1_COMMON *cm, struct SVC *svc, AV1_DENOISER *denoiser, fail = aom_alloc_frame_buffer( &denoiser->mc_running_avg_y[layer], denoise_width, denoise_height, ssx, - ssy, use_highbitdepth, border, legacy_byte_alignment, 0, 0); + ssy, use_highbitdepth, border, legacy_byte_alignment, false, 0); if (fail) { av1_denoiser_free(denoiser); return 1; @@ -600,7 +600,7 @@ int av1_denoiser_alloc(AV1_COMMON *cm, struct SVC *svc, AV1_DENOISER *denoiser, // layer. fail = aom_alloc_frame_buffer(&denoiser->last_source, width, height, ssx, ssy, use_highbitdepth, border, legacy_byte_alignment, - 0, 0); + false, 0); if (fail) { av1_denoiser_free(denoiser); return 1; diff --git a/third_party/aom/av1/encoder/bitstream.c b/third_party/aom/av1/encoder/bitstream.c index 219784fedf..9981871147 100644 --- a/third_party/aom/av1/encoder/bitstream.c +++ b/third_party/aom/av1/encoder/bitstream.c @@ -3391,8 +3391,8 @@ int av1_write_uleb_obu_size(size_t obu_header_size, size_t obu_payload_size, return AOM_CODEC_OK; } -size_t av1_obu_memmove(size_t obu_header_size, size_t obu_payload_size, - uint8_t *data) { +static size_t obu_memmove(size_t obu_header_size, size_t obu_payload_size, + uint8_t *data) { const size_t length_field_size = aom_uleb_size_in_bytes(obu_payload_size); const size_t move_dst_offset = length_field_size + obu_header_size; const size_t move_src_offset = obu_header_size; @@ -3581,7 +3581,7 @@ static void write_large_scale_tile_obu_size( *total_size += lst_obu->tg_hdr_size; const uint32_t obu_payload_size = *total_size - lst_obu->tg_hdr_size; const size_t length_field_size = - av1_obu_memmove(lst_obu->tg_hdr_size, obu_payload_size, dst); + obu_memmove(lst_obu->tg_hdr_size, obu_payload_size, dst); if (av1_write_uleb_obu_size(lst_obu->tg_hdr_size, obu_payload_size, dst) != AOM_CODEC_OK) assert(0); @@ -3806,7 +3806,7 @@ void av1_write_last_tile_info( const uint32_t obu_payload_size = (uint32_t)(*curr_tg_data_size) - obu_header_size; const size_t length_field_size = - av1_obu_memmove(obu_header_size, obu_payload_size, curr_tg_start); + obu_memmove(obu_header_size, obu_payload_size, curr_tg_start); if (av1_write_uleb_obu_size(obu_header_size, obu_payload_size, curr_tg_start) != AOM_CODEC_OK) { assert(0); @@ -4015,8 +4015,8 @@ static void write_tile_obu_size(AV1_COMP *const cpi, uint8_t *const dst, // to pack the smaller bitstream of such frames. This function computes the // number of required number of workers based on setup time overhead and job // dispatch time overhead for given tiles and available workers. -int calc_pack_bs_mt_workers(const TileDataEnc *tile_data, int num_tiles, - int avail_workers, bool pack_bs_mt_enabled) { +static int calc_pack_bs_mt_workers(const TileDataEnc *tile_data, int num_tiles, + int avail_workers, bool pack_bs_mt_enabled) { if (!pack_bs_mt_enabled) return 1; uint64_t frame_abs_sum_level = 0; @@ -4141,8 +4141,7 @@ static size_t av1_write_metadata_array(AV1_COMP *const cpi, uint8_t *dst) { OBU_METADATA, 0, dst); obu_payload_size = av1_write_metadata_obu(current_metadata, dst + obu_header_size); - length_field_size = - av1_obu_memmove(obu_header_size, obu_payload_size, dst); + length_field_size = obu_memmove(obu_header_size, obu_payload_size, dst); if (av1_write_uleb_obu_size(obu_header_size, obu_payload_size, dst) == AOM_CODEC_OK) { const size_t obu_size = obu_header_size + obu_payload_size; @@ -4192,7 +4191,7 @@ int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, obu_payload_size = av1_write_sequence_header_obu(cm->seq_params, data + obu_header_size); const size_t length_field_size = - av1_obu_memmove(obu_header_size, obu_payload_size, data); + obu_memmove(obu_header_size, obu_payload_size, data); if (av1_write_uleb_obu_size(obu_header_size, obu_payload_size, data) != AOM_CODEC_OK) { return AOM_CODEC_ERROR; @@ -4217,7 +4216,7 @@ int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, obu_payload_size = write_frame_header_obu(cpi, &cpi->td.mb.e_mbd, &saved_wb, data + obu_header_size, 1); - length_field = av1_obu_memmove(obu_header_size, obu_payload_size, data); + length_field = obu_memmove(obu_header_size, obu_payload_size, data); if (av1_write_uleb_obu_size(obu_header_size, obu_payload_size, data) != AOM_CODEC_OK) { return AOM_CODEC_ERROR; diff --git a/third_party/aom/av1/encoder/bitstream.h b/third_party/aom/av1/encoder/bitstream.h index 12e8a630db..d037039593 100644 --- a/third_party/aom/av1/encoder/bitstream.h +++ b/third_party/aom/av1/encoder/bitstream.h @@ -21,6 +21,7 @@ extern "C" { #include "av1/common/enums.h" #include "av1/encoder/level.h" #include "aom_dsp/bitwriter.h" +#include "aom_util/aom_pthread.h" struct aom_write_bit_buffer; struct AV1_COMP; diff --git a/third_party/aom/av1/encoder/block.h b/third_party/aom/av1/encoder/block.h index 33d2d8c2a0..1baf3f942e 100644 --- a/third_party/aom/av1/encoder/block.h +++ b/third_party/aom/av1/encoder/block.h @@ -1348,6 +1348,9 @@ typedef struct macroblock { //! Motion vector from superblock MV derived from int_pro_motion() in // the variance_partitioning. int_mv sb_me_mv; + //! Flag to indicate if a fixed partition should be used, only if the + // speed feature rt_sf->use_fast_fixed_part is enabled. + int sb_force_fixed_part; //! SSE of the current predictor. unsigned int pred_sse[REF_FRAMES]; //! Prediction for ML based partition. diff --git a/third_party/aom/av1/encoder/cnn.c b/third_party/aom/av1/encoder/cnn.c index 598b362753..b019ace685 100644 --- a/third_party/aom/av1/encoder/cnn.c +++ b/third_party/aom/av1/encoder/cnn.c @@ -138,14 +138,16 @@ static bool concat_tensor(const TENSOR *src, TENSOR *dst) { return true; } -int check_tensor_equal_dims(TENSOR *t1, TENSOR *t2) { +#ifndef NDEBUG +static int check_tensor_equal_dims(TENSOR *t1, TENSOR *t2) { return (t1->width == t2->width && t1->height == t2->height); } -int check_tensor_equal_size(TENSOR *t1, TENSOR *t2) { +static int check_tensor_equal_size(TENSOR *t1, TENSOR *t2) { return (t1->channels == t2->channels && t1->width == t2->width && t1->height == t2->height); } +#endif // NDEBUG void av1_find_cnn_layer_output_size(int in_width, int in_height, const CNN_LAYER_CONFIG *layer_config, @@ -189,8 +191,8 @@ void av1_find_cnn_layer_output_size(int in_width, int in_height, } } -void find_cnn_out_channels(const CNN_LAYER_CONFIG *layer_config, - int channels_per_branch[]) { +static void find_cnn_out_channels(const CNN_LAYER_CONFIG *layer_config, + int channels_per_branch[]) { int branch = layer_config->branch; const CNN_BRANCH_CONFIG *branch_config = &layer_config->branch_config; for (int b = 0; b < CNN_MAX_BRANCHES; ++b) { diff --git a/third_party/aom/av1/encoder/encode_strategy.c b/third_party/aom/av1/encoder/encode_strategy.c index 35ca83c3f4..db77dc0e3c 100644 --- a/third_party/aom/av1/encoder/encode_strategy.c +++ b/third_party/aom/av1/encoder/encode_strategy.c @@ -712,20 +712,6 @@ int av1_get_refresh_frame_flags( } #if !CONFIG_REALTIME_ONLY -void setup_mi(AV1_COMP *const cpi, YV12_BUFFER_CONFIG *src) { - AV1_COMMON *const cm = &cpi->common; - const int num_planes = av1_num_planes(cm); - MACROBLOCK *const x = &cpi->td.mb; - MACROBLOCKD *const xd = &x->e_mbd; - - av1_setup_src_planes(x, src, 0, 0, num_planes, cm->seq_params->sb_size); - - av1_setup_block_planes(xd, cm->seq_params->subsampling_x, - cm->seq_params->subsampling_y, num_planes); - - set_mi_offsets(&cm->mi_params, xd, 0, 0); -} - // Apply temporal filtering to source frames and encode the filtered frame. // If the current frame does not require filtering, this function is identical // to av1_encode() except that tpl is not performed. @@ -819,7 +805,7 @@ static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest, oxcf->frm_dim_cfg.height, cm->seq_params->subsampling_x, cm->seq_params->subsampling_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL, - NULL, cpi->image_pyramid_levels, 0); + NULL, cpi->alloc_pyramid, 0); if (ret) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate tf_buf_second_arf"); @@ -923,7 +909,7 @@ static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest, if (apply_filtering && is_psnr_calc_enabled(cpi)) { cpi->source = av1_realloc_and_scale_if_required( cm, source_buffer, &cpi->scaled_source, cm->features.interp_filter, 0, - false, true, cpi->oxcf.border_in_pixels, cpi->image_pyramid_levels); + false, true, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid); cpi->unscaled_source = source_buffer; } #if CONFIG_COLLECT_COMPONENT_TIMING @@ -1702,8 +1688,7 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, // This is used in rtc temporal filter case. Use true source in the PSNR // calculation. - if (is_psnr_calc_enabled(cpi) && cpi->sf.rt_sf.use_rtc_tf && - cpi->common.current_frame.frame_type != KEY_FRAME) { + if (is_psnr_calc_enabled(cpi) && cpi->sf.rt_sf.use_rtc_tf) { assert(cpi->orig_source.buffer_alloc_sz > 0); cpi->source = &cpi->orig_source; } @@ -1758,9 +1743,9 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, cpi->svc.temporal_layer_id == 0 && cpi->unscaled_source->y_width == cpi->svc.source_last_TL0.y_width && cpi->unscaled_source->y_height == cpi->svc.source_last_TL0.y_height) { - aom_yv12_copy_y(cpi->unscaled_source, &cpi->svc.source_last_TL0); - aom_yv12_copy_u(cpi->unscaled_source, &cpi->svc.source_last_TL0); - aom_yv12_copy_v(cpi->unscaled_source, &cpi->svc.source_last_TL0); + aom_yv12_copy_y(cpi->unscaled_source, &cpi->svc.source_last_TL0, 1); + aom_yv12_copy_u(cpi->unscaled_source, &cpi->svc.source_last_TL0, 1); + aom_yv12_copy_v(cpi->unscaled_source, &cpi->svc.source_last_TL0, 1); } return AOM_CODEC_OK; diff --git a/third_party/aom/av1/encoder/encodeframe.c b/third_party/aom/av1/encoder/encodeframe.c index e2213a8355..a9214f77c2 100644 --- a/third_party/aom/av1/encoder/encodeframe.c +++ b/third_party/aom/av1/encoder/encodeframe.c @@ -23,7 +23,7 @@ #include "aom_dsp/binary_codes_writer.h" #include "aom_ports/mem.h" #include "aom_ports/aom_timer.h" - +#include "aom_util/aom_pthread.h" #if CONFIG_MISMATCH_DEBUG #include "aom_util/debug_util.h" #endif // CONFIG_MISMATCH_DEBUG @@ -536,8 +536,8 @@ static AOM_INLINE void encode_nonrd_sb(AV1_COMP *cpi, ThreadData *td, #endif // Set the partition if (sf->part_sf.partition_search_type == FIXED_PARTITION || seg_skip || - (sf->rt_sf.use_fast_fixed_part && - x->content_state_sb.source_sad_nonrd < kMedSad)) { + (sf->rt_sf.use_fast_fixed_part && x->sb_force_fixed_part == 1 && + !frame_is_intra_only(cm))) { // set a fixed-size partition av1_set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size); BLOCK_SIZE bsize_select = sf->part_sf.fixed_partition_size; @@ -1054,8 +1054,13 @@ static AOM_INLINE bool is_calc_src_content_needed(AV1_COMP *cpi, // The threshold is determined based on kLowSad and kHighSad threshold and // test results. - const uint64_t thresh_low = 15000; - const uint64_t thresh_high = 40000; + uint64_t thresh_low = 15000; + uint64_t thresh_high = 40000; + + if (cpi->sf.rt_sf.increase_source_sad_thresh) { + thresh_low = thresh_low << 1; + thresh_high = thresh_high << 1; + } if (avg_64x64_blk_sad > thresh_low && avg_64x64_blk_sad < thresh_high) { do_calc_src_content = false; @@ -1203,6 +1208,7 @@ static AOM_INLINE void encode_sb_row(AV1_COMP *cpi, ThreadData *td, x->sb_me_block = 0; x->sb_me_partition = 0; x->sb_me_mv.as_int = 0; + x->sb_force_fixed_part = 1; if (cpi->oxcf.mode == ALLINTRA) { x->intra_sb_rdmult_modifier = 128; @@ -1231,7 +1237,7 @@ static AOM_INLINE void encode_sb_row(AV1_COMP *cpi, ThreadData *td, // Grade the temporal variation of the sb, the grade will be used to decide // fast mode search strategy for coding blocks - grade_source_content_sb(cpi, x, tile_data, mi_row, mi_col); + if (!seg_skip) grade_source_content_sb(cpi, x, tile_data, mi_row, mi_col); // encode the superblock if (use_nonrd_mode) { @@ -2337,7 +2343,7 @@ void av1_encode_frame(AV1_COMP *cpi) { // a source or a ref frame should have an image pyramid allocated. // Check here so that issues can be caught early in debug mode #if !defined(NDEBUG) && !CONFIG_REALTIME_ONLY - if (cpi->image_pyramid_levels > 0) { + if (cpi->alloc_pyramid) { assert(cpi->source->y_pyramid); for (int ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame); diff --git a/third_party/aom/av1/encoder/encodeframe_utils.c b/third_party/aom/av1/encoder/encodeframe_utils.c index 949837184a..a8e4a88396 100644 --- a/third_party/aom/av1/encoder/encodeframe_utils.c +++ b/third_party/aom/av1/encoder/encodeframe_utils.c @@ -15,6 +15,7 @@ #include "av1/encoder/encoder.h" #include "av1/encoder/encodeframe_utils.h" +#include "av1/encoder/encoder_utils.h" #include "av1/encoder/rdopt.h" void av1_set_ssim_rdmult(const AV1_COMP *const cpi, int *errorperbit, @@ -306,6 +307,7 @@ void av1_update_state(const AV1_COMP *const cpi, ThreadData *td, // Else for cyclic refresh mode update the segment map, set the segment id // and then update the quantizer. if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && + mi_addr->segment_id != AM_SEGMENT_ID_INACTIVE && !cpi->rc.rtc_external_ratectrl) { av1_cyclic_refresh_update_segment(cpi, x, mi_row, mi_col, bsize, ctx->rd_stats.rate, ctx->rd_stats.dist, @@ -1431,6 +1433,10 @@ void av1_source_content_sb(AV1_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data, if ((tmp_sse - tmp_variance) < (sum_sq_thresh >> 1)) x->content_state_sb.low_sumdiff = 1; + if (tmp_sse > ((avg_source_sse_threshold_high * 7) >> 3) && + !x->content_state_sb.lighting_change && !x->content_state_sb.low_sumdiff) + x->sb_force_fixed_part = 0; + if (!cpi->sf.rt_sf.use_rtc_tf || cpi->rc.high_source_sad || cpi->rc.frame_source_sad > 20000 || cpi->svc.number_spatial_layers > 1) return; diff --git a/third_party/aom/av1/encoder/encoder.c b/third_party/aom/av1/encoder/encoder.c index fe053af5cc..1ddbfda08b 100644 --- a/third_party/aom/av1/encoder/encoder.c +++ b/third_party/aom/av1/encoder/encoder.c @@ -35,6 +35,7 @@ #include "aom_ports/aom_timer.h" #include "aom_ports/mem.h" #include "aom_scale/aom_scale.h" +#include "aom_util/aom_pthread.h" #if CONFIG_BITSTREAM_DEBUG #include "aom_util/debug_util.h" #endif // CONFIG_BITSTREAM_DEBUG @@ -152,24 +153,33 @@ int av1_set_active_map(AV1_COMP *cpi, unsigned char *new_map_16x16, int rows, unsigned char *const active_map_4x4 = cpi->active_map.map; const int mi_rows = mi_params->mi_rows; const int mi_cols = mi_params->mi_cols; - const int row_scale = mi_size_high_log2[BLOCK_16X16]; - const int col_scale = mi_size_wide_log2[BLOCK_16X16]; cpi->active_map.update = 0; - assert(mi_rows % 2 == 0); - assert(mi_cols % 2 == 0); + cpi->rc.percent_blocks_inactive = 0; + assert(mi_rows % 2 == 0 && mi_rows > 0); + assert(mi_cols % 2 == 0 && mi_cols > 0); if (new_map_16x16) { - for (int r = 0; r < (mi_rows >> row_scale); ++r) { - for (int c = 0; c < (mi_cols >> col_scale); ++c) { - const uint8_t val = new_map_16x16[r * cols + c] + int num_samples = 0; + int num_blocks_inactive = 0; + for (int r = 0; r < mi_rows; r += 4) { + for (int c = 0; c < mi_cols; c += 4) { + const uint8_t val = new_map_16x16[(r >> 2) * cols + (c >> 2)] ? AM_SEGMENT_ID_ACTIVE : AM_SEGMENT_ID_INACTIVE; - active_map_4x4[(2 * r + 0) * mi_cols + (c + 0)] = val; - active_map_4x4[(2 * r + 0) * mi_cols + (c + 1)] = val; - active_map_4x4[(2 * r + 1) * mi_cols + (c + 0)] = val; - active_map_4x4[(2 * r + 1) * mi_cols + (c + 1)] = val; + num_samples++; + if (val == AM_SEGMENT_ID_INACTIVE) num_blocks_inactive++; + const int row_max = AOMMIN(4, mi_rows - r); + const int col_max = AOMMIN(4, mi_cols - c); + for (int x = 0; x < row_max; ++x) { + for (int y = 0; y < col_max; ++y) { + active_map_4x4[(r + x) * mi_cols + (c + y)] = val; + } + } } } cpi->active_map.enabled = 1; + cpi->active_map.update = 1; + cpi->rc.percent_blocks_inactive = + (num_blocks_inactive * 100) / num_samples; } return 0; } @@ -943,14 +953,9 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf, #if CONFIG_REALTIME_ONLY assert(!oxcf->tool_cfg.enable_global_motion); - cpi->image_pyramid_levels = 0; + cpi->alloc_pyramid = false; #else - if (oxcf->tool_cfg.enable_global_motion) { - cpi->image_pyramid_levels = - global_motion_pyr_levels[default_global_motion_method]; - } else { - cpi->image_pyramid_levels = 0; - } + cpi->alloc_pyramid = oxcf->tool_cfg.enable_global_motion; #endif // CONFIG_REALTIME_ONLY } @@ -2208,7 +2213,7 @@ void av1_set_frame_size(AV1_COMP *cpi, int width, int height) { &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL, - NULL, cpi->image_pyramid_levels, 0)) + NULL, cpi->alloc_pyramid, 0)) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate frame buffer"); @@ -2389,7 +2394,10 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { const int use_loopfilter = is_loopfilter_used(cm) && !cpi->mt_info.pipeline_lpf_mt_with_enc; - const int use_cdef = is_cdef_used(cm); + const int use_cdef = + is_cdef_used(cm) && (!cpi->active_map.enabled || + cpi->rc.percent_blocks_inactive <= + cpi->sf.rt_sf.thresh_active_maps_skip_lf_cdef); const int use_superres = av1_superres_scaled(cm); const int use_restoration = is_restoration_used(cm); @@ -2498,7 +2506,8 @@ static int encode_without_recode(AV1_COMP *cpi) { &cpi->svc.source_last_TL0, cpi->oxcf.frm_dim_cfg.width, cpi->oxcf.frm_dim_cfg.height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->features.byte_alignment, 0, 0)) { + cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, + 0)) { aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate buffer for source_last_TL0"); } @@ -2547,7 +2556,7 @@ static int encode_without_recode(AV1_COMP *cpi) { cpi->source = av1_realloc_and_scale_if_required( cm, unscaled, &cpi->scaled_source, filter_scaler, phase_scaler, true, - false, cpi->oxcf.border_in_pixels, cpi->image_pyramid_levels); + false, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid); if (frame_is_intra_only(cm) || resize_pending != 0) { const int current_size = (cm->mi_params.mi_rows * cm->mi_params.mi_cols) >> 2; @@ -2570,7 +2579,7 @@ static int encode_without_recode(AV1_COMP *cpi) { cpi->last_source = av1_realloc_and_scale_if_required( cm, cpi->unscaled_last_source, &cpi->scaled_last_source, filter_scaler, phase_scaler, true, false, cpi->oxcf.border_in_pixels, - cpi->image_pyramid_levels); + cpi->alloc_pyramid); } if (cpi->sf.rt_sf.use_temporal_noise_estimate) { @@ -2647,12 +2656,8 @@ static int encode_without_recode(AV1_COMP *cpi) { av1_setup_frame(cpi); } } - - if (q_cfg->aq_mode == CYCLIC_REFRESH_AQ) { - suppress_active_map(cpi); - av1_cyclic_refresh_setup(cpi); - } av1_apply_active_map(cpi); + if (q_cfg->aq_mode == CYCLIC_REFRESH_AQ) av1_cyclic_refresh_setup(cpi); if (cm->seg.enabled) { if (!cm->seg.update_data && cm->prev_frame) { segfeatures_copy(&cm->seg, &cm->prev_frame->seg); @@ -2667,26 +2672,26 @@ static int encode_without_recode(AV1_COMP *cpi) { cm->cur_frame->seg.enabled = cm->seg.enabled; // This is for rtc temporal filtering case. - if (is_psnr_calc_enabled(cpi) && cpi->sf.rt_sf.use_rtc_tf && - cm->current_frame.frame_type != KEY_FRAME) { + if (is_psnr_calc_enabled(cpi) && cpi->sf.rt_sf.use_rtc_tf) { const SequenceHeader *seq_params = cm->seq_params; if (cpi->orig_source.buffer_alloc_sz == 0 || - cpi->last_source->y_width != cpi->source->y_width || - cpi->last_source->y_height != cpi->source->y_height) { + cpi->rc.prev_coded_width != cpi->oxcf.frm_dim_cfg.width || + cpi->rc.prev_coded_height != cpi->oxcf.frm_dim_cfg.height) { // Allocate a source buffer to store the true source for psnr calculation. if (aom_alloc_frame_buffer( &cpi->orig_source, cpi->oxcf.frm_dim_cfg.width, cpi->oxcf.frm_dim_cfg.height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->features.byte_alignment, 0, 0)) + cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, + 0)) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate scaled buffer"); } - aom_yv12_copy_y(cpi->source, &cpi->orig_source); - aom_yv12_copy_u(cpi->source, &cpi->orig_source); - aom_yv12_copy_v(cpi->source, &cpi->orig_source); + aom_yv12_copy_y(cpi->source, &cpi->orig_source, 1); + aom_yv12_copy_u(cpi->source, &cpi->orig_source, 1); + aom_yv12_copy_v(cpi->source, &cpi->orig_source, 1); } #if CONFIG_COLLECT_COMPONENT_TIMING @@ -2725,9 +2730,9 @@ static int encode_without_recode(AV1_COMP *cpi) { (cm->width != cpi->unscaled_source->y_crop_width || cm->height != cpi->unscaled_source->y_crop_height)) { cpi->scaled_last_source_available = 1; - aom_yv12_copy_y(&cpi->scaled_source, &cpi->scaled_last_source); - aom_yv12_copy_u(&cpi->scaled_source, &cpi->scaled_last_source); - aom_yv12_copy_v(&cpi->scaled_source, &cpi->scaled_last_source); + aom_yv12_copy_y(&cpi->scaled_source, &cpi->scaled_last_source, 1); + aom_yv12_copy_u(&cpi->scaled_source, &cpi->scaled_last_source, 1); + aom_yv12_copy_v(&cpi->scaled_source, &cpi->scaled_last_source, 1); } #if CONFIG_COLLECT_COMPONENT_TIMING @@ -2846,7 +2851,7 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { } cpi->source = av1_realloc_and_scale_if_required( cm, cpi->unscaled_source, &cpi->scaled_source, EIGHTTAP_REGULAR, 0, - false, false, cpi->oxcf.border_in_pixels, cpi->image_pyramid_levels); + false, false, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid); #if CONFIG_TUNE_BUTTERAUGLI if (oxcf->tune_cfg.tuning == AOM_TUNE_BUTTERAUGLI) { @@ -2866,7 +2871,7 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { cpi->last_source = av1_realloc_and_scale_if_required( cm, cpi->unscaled_last_source, &cpi->scaled_last_source, EIGHTTAP_REGULAR, 0, false, false, cpi->oxcf.border_in_pixels, - cpi->image_pyramid_levels); + cpi->alloc_pyramid); } int scale_references = 0; @@ -4042,7 +4047,7 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, } #if CONFIG_DENOISE -static int apply_denoise_2d(AV1_COMP *cpi, YV12_BUFFER_CONFIG *sd, +static int apply_denoise_2d(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *sd, int block_size, float noise_level, int64_t time_stamp, int64_t end_time) { AV1_COMMON *const cm = &cpi->common; @@ -4077,7 +4082,7 @@ static int apply_denoise_2d(AV1_COMP *cpi, YV12_BUFFER_CONFIG *sd, #endif int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags, - YV12_BUFFER_CONFIG *sd, int64_t time_stamp, + const YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time) { AV1_COMMON *const cm = &cpi->common; const SequenceHeader *const seq_params = cm->seq_params; @@ -4139,8 +4144,7 @@ int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags, #endif // CONFIG_DENOISE if (av1_lookahead_push(cpi->ppi->lookahead, sd, time_stamp, end_time, - use_highbitdepth, cpi->image_pyramid_levels, - frame_flags)) { + use_highbitdepth, cpi->alloc_pyramid, frame_flags)) { aom_set_error(cm->error, AOM_CODEC_ERROR, "av1_lookahead_push() failed"); res = -1; } diff --git a/third_party/aom/av1/encoder/encoder.h b/third_party/aom/av1/encoder/encoder.h index e87ab9be1f..4de5d426ce 100644 --- a/third_party/aom/av1/encoder/encoder.h +++ b/third_party/aom/av1/encoder/encoder.h @@ -21,6 +21,7 @@ #include "config/aom_config.h" #include "aom/aomcx.h" +#include "aom_util/aom_pthread.h" #include "av1/common/alloccommon.h" #include "av1/common/av1_common_int.h" @@ -3631,10 +3632,10 @@ typedef struct AV1_COMP { unsigned int zeromv_skip_thresh_exit_part[BLOCK_SIZES_ALL]; /*! - * Number of downsampling pyramid levels to allocate for each frame + * Should we allocate a downsampling pyramid for each frame buffer? * This is currently only used for global motion */ - int image_pyramid_levels; + bool alloc_pyramid; #if CONFIG_SALIENCY_MAP /*! @@ -3808,7 +3809,7 @@ int av1_init_parallel_frame_context(const AV1_COMP_DATA *const first_cpi_data, * copy of the pointer. */ int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags, - YV12_BUFFER_CONFIG *sd, int64_t time_stamp, + const YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time_stamp); /*!\brief Encode a frame @@ -4310,7 +4311,7 @@ static AOM_INLINE int is_psnr_calc_enabled(const AV1_COMP *cpi) { const AV1_COMMON *const cm = &cpi->common; return cpi->ppi->b_calculate_psnr && !is_stat_generation_stage(cpi) && - cm->show_frame; + cm->show_frame && !cpi->is_dropped_frame; } static INLINE int is_frame_resize_pending(const AV1_COMP *const cpi) { diff --git a/third_party/aom/av1/encoder/encoder_alloc.h b/third_party/aom/av1/encoder/encoder_alloc.h index ce48496d48..f24d4b0a10 100644 --- a/third_party/aom/av1/encoder/encoder_alloc.h +++ b/third_party/aom/av1/encoder/encoder_alloc.h @@ -439,8 +439,7 @@ static AOM_INLINE YV12_BUFFER_CONFIG *realloc_and_scale_source( &cpi->scaled_source, scaled_width, scaled_height, cm->seq_params->subsampling_x, cm->seq_params->subsampling_y, cm->seq_params->use_highbitdepth, AOM_BORDER_IN_PIXELS, - cm->features.byte_alignment, NULL, NULL, NULL, - cpi->image_pyramid_levels, 0)) + cm->features.byte_alignment, NULL, NULL, NULL, cpi->alloc_pyramid, 0)) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to reallocate scaled source buffer"); assert(cpi->scaled_source.y_crop_width == scaled_width); diff --git a/third_party/aom/av1/encoder/encoder_utils.c b/third_party/aom/av1/encoder/encoder_utils.c index c35873d207..1f81a530c9 100644 --- a/third_party/aom/av1/encoder/encoder_utils.c +++ b/third_party/aom/av1/encoder/encoder_utils.c @@ -9,8 +9,11 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #include "aom/aomcx.h" +#include "av1/common/av1_common_int.h" #include "av1/encoder/bitstream.h" #include "av1/encoder/encodeframe.h" #include "av1/encoder/encoder.h" @@ -421,11 +424,13 @@ void av1_apply_active_map(AV1_COMP *cpi) { struct segmentation *const seg = &cpi->common.seg; unsigned char *const seg_map = cpi->enc_seg.map; const unsigned char *const active_map = cpi->active_map.map; - int i; assert(AM_SEGMENT_ID_ACTIVE == CR_SEGMENT_ID_BASE); - if (frame_is_intra_only(&cpi->common)) { + // Disable the active_maps on intra_only frames or if the + // input map for the current frame has no inactive blocks. + if (frame_is_intra_only(&cpi->common) || + cpi->rc.percent_blocks_inactive == 0) { cpi->active_map.enabled = 0; cpi->active_map.update = 1; } @@ -434,8 +439,7 @@ void av1_apply_active_map(AV1_COMP *cpi) { if (cpi->active_map.enabled) { const int num_mis = cpi->common.mi_params.mi_rows * cpi->common.mi_params.mi_cols; - for (i = 0; i < num_mis; ++i) - if (seg_map[i] == AM_SEGMENT_ID_ACTIVE) seg_map[i] = active_map[i]; + memcpy(seg_map, active_map, sizeof(active_map[0]) * num_mis); av1_enable_segmentation(seg); av1_enable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_SKIP); av1_enable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_ALT_LF_Y_H); @@ -725,7 +729,7 @@ void av1_scale_references(AV1_COMP *cpi, const InterpFilter filter, RefCntBuffer *ref_fb = get_ref_frame_buf(cm, ref_frame); if (aom_yv12_realloc_with_new_border( &ref_fb->buf, AOM_BORDER_IN_PIXELS, - cm->features.byte_alignment, cpi->image_pyramid_levels, + cm->features.byte_alignment, cpi->alloc_pyramid, num_planes) != 0) { aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate frame buffer"); @@ -749,7 +753,7 @@ void av1_scale_references(AV1_COMP *cpi, const InterpFilter filter, &new_fb->buf, cm->width, cm->height, cm->seq_params->subsampling_x, cm->seq_params->subsampling_y, cm->seq_params->use_highbitdepth, AOM_BORDER_IN_PIXELS, - cm->features.byte_alignment, NULL, NULL, NULL, 0, 0)) { + cm->features.byte_alignment, NULL, NULL, NULL, false, 0)) { if (force_scaling) { // Release the reference acquired in the get_free_fb() call above. --new_fb->ref_count; @@ -1087,12 +1091,12 @@ void av1_determine_sc_tools_with_encoding(AV1_COMP *cpi, const int q_orig) { cpi->source = av1_realloc_and_scale_if_required( cm, cpi->unscaled_source, &cpi->scaled_source, cm->features.interp_filter, - 0, false, false, cpi->oxcf.border_in_pixels, cpi->image_pyramid_levels); + 0, false, false, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid); if (cpi->unscaled_last_source != NULL) { cpi->last_source = av1_realloc_and_scale_if_required( cm, cpi->unscaled_last_source, &cpi->scaled_last_source, cm->features.interp_filter, 0, false, false, cpi->oxcf.border_in_pixels, - cpi->image_pyramid_levels); + cpi->alloc_pyramid); } av1_setup_frame(cpi); diff --git a/third_party/aom/av1/encoder/encodetxb.c b/third_party/aom/av1/encoder/encodetxb.c index 5fe2a497c7..701c5489fe 100644 --- a/third_party/aom/av1/encoder/encodetxb.c +++ b/third_party/aom/av1/encoder/encodetxb.c @@ -134,14 +134,14 @@ int av1_get_eob_pos_token(const int eob, int *const extra) { } #if CONFIG_ENTROPY_STATS -void av1_update_eob_context(int cdf_idx, int eob, TX_SIZE tx_size, - TX_CLASS tx_class, PLANE_TYPE plane, - FRAME_CONTEXT *ec_ctx, FRAME_COUNTS *counts, - uint8_t allow_update_cdf) { +static void update_eob_context(int cdf_idx, int eob, TX_SIZE tx_size, + TX_CLASS tx_class, PLANE_TYPE plane, + FRAME_CONTEXT *ec_ctx, FRAME_COUNTS *counts, + uint8_t allow_update_cdf) { #else -void av1_update_eob_context(int eob, TX_SIZE tx_size, TX_CLASS tx_class, - PLANE_TYPE plane, FRAME_CONTEXT *ec_ctx, - uint8_t allow_update_cdf) { +static void update_eob_context(int eob, TX_SIZE tx_size, TX_CLASS tx_class, + PLANE_TYPE plane, FRAME_CONTEXT *ec_ctx, + uint8_t allow_update_cdf) { #endif int eob_extra; const int eob_pt = av1_get_eob_pos_token(eob, &eob_extra); @@ -623,11 +623,11 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row, td->rd_counts.tx_type_used[tx_size][tx_type]++; #if CONFIG_ENTROPY_STATS - av1_update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx, - td->counts, allow_update_cdf); + update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx, + td->counts, allow_update_cdf); #else - av1_update_eob_context(eob, tx_size, tx_class, plane_type, ec_ctx, - allow_update_cdf); + update_eob_context(eob, tx_size, tx_class, plane_type, ec_ctx, + allow_update_cdf); #endif DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]); @@ -785,8 +785,8 @@ void av1_record_txb_context(int plane, int block, int blk_row, int blk_col, #if CONFIG_ENTROPY_STATS FRAME_CONTEXT *ec_ctx = xd->tile_ctx; - av1_update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx, - td->counts, 0 /*allow_update_cdf*/); + update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx, + td->counts, 0 /*allow_update_cdf*/); DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]); av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class, diff --git a/third_party/aom/av1/encoder/ethread.c b/third_party/aom/av1/encoder/ethread.c index d6a806d504..755535ba51 100644 --- a/third_party/aom/av1/encoder/ethread.c +++ b/third_party/aom/av1/encoder/ethread.c @@ -12,6 +12,8 @@ #include #include +#include "aom_util/aom_pthread.h" + #include "av1/common/warped_motion.h" #include "av1/common/thread_common.h" @@ -1415,7 +1417,7 @@ static AOM_INLINE void sync_fpmt_workers(AV1_PRIMARY *ppi, int num_workers = ppi->p_mt_info.p_num_workers; int had_error = 0; // Points to error in the earliest display order frame in the parallel set. - const struct aom_internal_error_info *error; + const struct aom_internal_error_info *error = NULL; // Encoding ends. for (int i = num_workers - 1; i >= 0; --i) { @@ -2227,8 +2229,8 @@ void av1_tpl_dealloc(AV1TplRowMultiThreadSync *tpl_sync) { } // Allocate memory for tpl row synchronization. -void av1_tpl_alloc(AV1TplRowMultiThreadSync *tpl_sync, AV1_COMMON *cm, - int mb_rows) { +static void av1_tpl_alloc(AV1TplRowMultiThreadSync *tpl_sync, AV1_COMMON *cm, + int mb_rows) { tpl_sync->rows = mb_rows; #if CONFIG_MULTITHREAD { diff --git a/third_party/aom/av1/encoder/firstpass.c b/third_party/aom/av1/encoder/firstpass.c index e20b6c177e..b94a50714a 100644 --- a/third_party/aom/av1/encoder/firstpass.c +++ b/third_party/aom/av1/encoder/firstpass.c @@ -22,6 +22,7 @@ #include "aom_ports/mem.h" #include "aom_scale/aom_scale.h" #include "aom_scale/yv12config.h" +#include "aom_util/aom_pthread.h" #include "av1/common/entropymv.h" #include "av1/common/quant_common.h" diff --git a/third_party/aom/av1/encoder/global_motion.c b/third_party/aom/av1/encoder/global_motion.c index 73910de121..0ae47809c6 100644 --- a/third_party/aom/av1/encoder/global_motion.c +++ b/third_party/aom/av1/encoder/global_motion.c @@ -30,83 +30,6 @@ // Border over which to compute the global motion #define ERRORADV_BORDER 0 -/* clang-format off */ -// Error metric used for global motion evaluation. -// For 8-bit input, the pixel error used to index this table will always -// be between -255 and +255. But for 10- and 12-bit input, we use interpolation -// which means that we need to support indices of -256 and +256 as well. -// Therefore, the table is offset so that logical index 0 corresponds to -// error_measure_lut[256]. -const int error_measure_lut[513] = { - // pow 0.7 - 16384, 16384, 16339, 16294, 16249, 16204, 16158, 16113, - 16068, 16022, 15977, 15932, 15886, 15840, 15795, 15749, - 15703, 15657, 15612, 15566, 15520, 15474, 15427, 15381, - 15335, 15289, 15242, 15196, 15149, 15103, 15056, 15010, - 14963, 14916, 14869, 14822, 14775, 14728, 14681, 14634, - 14587, 14539, 14492, 14445, 14397, 14350, 14302, 14254, - 14206, 14159, 14111, 14063, 14015, 13967, 13918, 13870, - 13822, 13773, 13725, 13676, 13628, 13579, 13530, 13481, - 13432, 13383, 13334, 13285, 13236, 13187, 13137, 13088, - 13038, 12988, 12939, 12889, 12839, 12789, 12739, 12689, - 12639, 12588, 12538, 12487, 12437, 12386, 12335, 12285, - 12234, 12183, 12132, 12080, 12029, 11978, 11926, 11875, - 11823, 11771, 11719, 11667, 11615, 11563, 11511, 11458, - 11406, 11353, 11301, 11248, 11195, 11142, 11089, 11036, - 10982, 10929, 10875, 10822, 10768, 10714, 10660, 10606, - 10552, 10497, 10443, 10388, 10333, 10279, 10224, 10168, - 10113, 10058, 10002, 9947, 9891, 9835, 9779, 9723, - 9666, 9610, 9553, 9497, 9440, 9383, 9326, 9268, - 9211, 9153, 9095, 9037, 8979, 8921, 8862, 8804, - 8745, 8686, 8627, 8568, 8508, 8449, 8389, 8329, - 8269, 8208, 8148, 8087, 8026, 7965, 7903, 7842, - 7780, 7718, 7656, 7593, 7531, 7468, 7405, 7341, - 7278, 7214, 7150, 7086, 7021, 6956, 6891, 6826, - 6760, 6695, 6628, 6562, 6495, 6428, 6361, 6293, - 6225, 6157, 6089, 6020, 5950, 5881, 5811, 5741, - 5670, 5599, 5527, 5456, 5383, 5311, 5237, 5164, - 5090, 5015, 4941, 4865, 4789, 4713, 4636, 4558, - 4480, 4401, 4322, 4242, 4162, 4080, 3998, 3916, - 3832, 3748, 3663, 3577, 3490, 3402, 3314, 3224, - 3133, 3041, 2948, 2854, 2758, 2661, 2562, 2461, - 2359, 2255, 2148, 2040, 1929, 1815, 1698, 1577, - 1452, 1323, 1187, 1045, 894, 731, 550, 339, - 0, 339, 550, 731, 894, 1045, 1187, 1323, - 1452, 1577, 1698, 1815, 1929, 2040, 2148, 2255, - 2359, 2461, 2562, 2661, 2758, 2854, 2948, 3041, - 3133, 3224, 3314, 3402, 3490, 3577, 3663, 3748, - 3832, 3916, 3998, 4080, 4162, 4242, 4322, 4401, - 4480, 4558, 4636, 4713, 4789, 4865, 4941, 5015, - 5090, 5164, 5237, 5311, 5383, 5456, 5527, 5599, - 5670, 5741, 5811, 5881, 5950, 6020, 6089, 6157, - 6225, 6293, 6361, 6428, 6495, 6562, 6628, 6695, - 6760, 6826, 6891, 6956, 7021, 7086, 7150, 7214, - 7278, 7341, 7405, 7468, 7531, 7593, 7656, 7718, - 7780, 7842, 7903, 7965, 8026, 8087, 8148, 8208, - 8269, 8329, 8389, 8449, 8508, 8568, 8627, 8686, - 8745, 8804, 8862, 8921, 8979, 9037, 9095, 9153, - 9211, 9268, 9326, 9383, 9440, 9497, 9553, 9610, - 9666, 9723, 9779, 9835, 9891, 9947, 10002, 10058, - 10113, 10168, 10224, 10279, 10333, 10388, 10443, 10497, - 10552, 10606, 10660, 10714, 10768, 10822, 10875, 10929, - 10982, 11036, 11089, 11142, 11195, 11248, 11301, 11353, - 11406, 11458, 11511, 11563, 11615, 11667, 11719, 11771, - 11823, 11875, 11926, 11978, 12029, 12080, 12132, 12183, - 12234, 12285, 12335, 12386, 12437, 12487, 12538, 12588, - 12639, 12689, 12739, 12789, 12839, 12889, 12939, 12988, - 13038, 13088, 13137, 13187, 13236, 13285, 13334, 13383, - 13432, 13481, 13530, 13579, 13628, 13676, 13725, 13773, - 13822, 13870, 13918, 13967, 14015, 14063, 14111, 14159, - 14206, 14254, 14302, 14350, 14397, 14445, 14492, 14539, - 14587, 14634, 14681, 14728, 14775, 14822, 14869, 14916, - 14963, 15010, 15056, 15103, 15149, 15196, 15242, 15289, - 15335, 15381, 15427, 15474, 15520, 15566, 15612, 15657, - 15703, 15749, 15795, 15840, 15886, 15932, 15977, 16022, - 16068, 16113, 16158, 16204, 16249, 16294, 16339, 16384, - 16384, -}; -/* clang-format on */ - int av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost) { return best_erroradvantage < erroradv_tr && best_erroradvantage * params_cost < erroradv_prod_tr; @@ -541,6 +464,11 @@ int64_t av1_refine_integerized_param( } wm->wmtype = get_wmtype(wm); + // Recompute shear params for the refined model + // This should never fail, because we only ever consider warp-able models + if (!av1_get_shear_params(wm)) { + assert(0); + } return best_error; } diff --git a/third_party/aom/av1/encoder/global_motion.h b/third_party/aom/av1/encoder/global_motion.h index 8c9c60f0f5..de46a0e1f2 100644 --- a/third_party/aom/av1/encoder/global_motion.h +++ b/third_party/aom/av1/encoder/global_motion.h @@ -15,6 +15,7 @@ #include "aom/aom_integer.h" #include "aom_dsp/flow_estimation/flow_estimation.h" #include "aom_scale/yv12config.h" +#include "aom_util/aom_pthread.h" #include "aom_util/aom_thread.h" #ifdef __cplusplus @@ -97,37 +98,6 @@ void av1_compute_feature_segmentation_map(uint8_t *segment_map, int width, int height, int *inliers, int num_inliers); -extern const int error_measure_lut[513]; - -static INLINE int error_measure(int err) { - return error_measure_lut[256 + err]; -} - -#if CONFIG_AV1_HIGHBITDEPTH -static INLINE int highbd_error_measure(int err, int bd) { - const int b = bd - 8; - const int bmask = (1 << b) - 1; - const int v = (1 << b); - - // Split error into two parts and do an interpolated table lookup - // To compute the table index and interpolation value, we want to calculate - // the quotient and remainder of err / 2^b. But it is very important that - // the division must round down, and the remainder must be positive, - // ie. in the range [0, 2^b). - // - // In C, the >> and & operators do what we want, but the / and % operators - // give the wrong results for negative inputs. So we must use >> and & here. - // - // For example, if bd == 10 and err == -5, compare the results: - // (-5) >> 2 = -2, (-5) & 3 = 3 - // vs. (-5) / 4 = -1, (-5) % 4 = -1 - const int e1 = err >> b; - const int e2 = err & bmask; - return error_measure_lut[256 + e1] * (v - e2) + - error_measure_lut[257 + e1] * e2; -} -#endif // CONFIG_AV1_HIGHBITDEPTH - int64_t av1_segmented_frame_error(int use_hbd, int bd, const uint8_t *ref, int ref_stride, uint8_t *dst, int dst_stride, int p_width, int p_height, diff --git a/third_party/aom/av1/encoder/global_motion_facade.c b/third_party/aom/av1/encoder/global_motion_facade.c index 02a4e70ed3..687eeee18a 100644 --- a/third_party/aom/av1/encoder/global_motion_facade.c +++ b/third_party/aom/av1/encoder/global_motion_facade.c @@ -89,6 +89,7 @@ static AOM_INLINE void compute_global_motion_for_ref_frame( assert(ref_buf[frame] != NULL); int bit_depth = cpi->common.seq_params->bit_depth; GlobalMotionMethod global_motion_method = default_global_motion_method; + int downsample_level = cpi->sf.gm_sf.downsample_level; int num_refinements = cpi->sf.gm_sf.num_refinement_steps; bool mem_alloc_failed = false; @@ -99,9 +100,10 @@ static AOM_INLINE void compute_global_motion_for_ref_frame( double best_erroradv = erroradv_tr; for (TransformationType model = FIRST_GLOBAL_TRANS_TYPE; model <= LAST_GLOBAL_TRANS_TYPE; ++model) { - if (!aom_compute_global_motion( - model, cpi->source, ref_buf[frame], bit_depth, global_motion_method, - motion_models, RANSAC_NUM_MOTIONS, &mem_alloc_failed)) { + if (!aom_compute_global_motion(model, cpi->source, ref_buf[frame], + bit_depth, global_motion_method, + downsample_level, motion_models, + RANSAC_NUM_MOTIONS, &mem_alloc_failed)) { if (mem_alloc_failed) { aom_internal_error(error_info, AOM_CODEC_MEM_ERROR, "Failed to allocate global motion buffers"); @@ -115,6 +117,9 @@ static AOM_INLINE void compute_global_motion_for_ref_frame( WarpedMotionParams tmp_wm_params; av1_convert_model_to_params(motion_models[i].params, &tmp_wm_params); + // Check that the generated model is warp-able + if (!av1_get_shear_params(&tmp_wm_params)) continue; + // Skip models that we won't use (IDENTITY or TRANSLATION) // // For IDENTITY type models, we don't need to evaluate anything because @@ -151,6 +156,14 @@ static AOM_INLINE void compute_global_motion_for_ref_frame( double erroradvantage = (double)warp_error / ref_frame_error; + // Check that the model signaling cost is not too high + if (!av1_is_enough_erroradvantage( + erroradvantage, + gm_get_params_cost(&tmp_wm_params, ref_params, + cm->features.allow_high_precision_mv))) { + continue; + } + if (erroradvantage < best_erroradv) { best_erroradv = erroradvantage; // Save the wm_params modified by @@ -161,34 +174,6 @@ static AOM_INLINE void compute_global_motion_for_ref_frame( } } } - - if (!av1_get_shear_params(&cm->global_motion[frame])) - cm->global_motion[frame] = default_warp_params; - -#if 0 - // We never choose translational models, so this code is disabled - if (cm->global_motion[frame].wmtype == TRANSLATION) { - cm->global_motion[frame].wmmat[0] = - convert_to_trans_prec(cm->features.allow_high_precision_mv, - cm->global_motion[frame].wmmat[0]) * - GM_TRANS_ONLY_DECODE_FACTOR; - cm->global_motion[frame].wmmat[1] = - convert_to_trans_prec(cm->features.allow_high_precision_mv, - cm->global_motion[frame].wmmat[1]) * - GM_TRANS_ONLY_DECODE_FACTOR; - } -#endif - - if (cm->global_motion[frame].wmtype == IDENTITY) return; - - // If the best error advantage found doesn't meet the threshold for - // this motion type, revert to IDENTITY. - if (!av1_is_enough_erroradvantage( - best_erroradv, - gm_get_params_cost(&cm->global_motion[frame], ref_params, - cm->features.allow_high_precision_mv))) { - cm->global_motion[frame] = default_warp_params; - } } // Computes global motion for the given reference frame. diff --git a/third_party/aom/av1/encoder/k_means_template.h b/third_party/aom/av1/encoder/k_means_template.h index 4be2038a6f..239029345d 100644 --- a/third_party/aom/av1/encoder/k_means_template.h +++ b/third_party/aom/av1/encoder/k_means_template.h @@ -24,6 +24,9 @@ #define RENAME_(x, y) AV1_K_MEANS_RENAME(x, y) #define RENAME(x) RENAME_(x, AV1_K_MEANS_DIM) +#define K_MEANS_RENAME_C(x, y) x##_dim##y##_c +#define RENAME_C_(x, y) K_MEANS_RENAME_C(x, y) +#define RENAME_C(x) RENAME_C_(x, AV1_K_MEANS_DIM) // Though we want to compute the smallest L2 norm, in 1 dimension, // it is equivalent to find the smallest L1 norm and then square it. @@ -41,8 +44,8 @@ static int RENAME(calc_dist)(const int16_t *p1, const int16_t *p2) { #endif } -void RENAME(av1_calc_indices)(const int16_t *data, const int16_t *centroids, - uint8_t *indices, int64_t *dist, int n, int k) { +void RENAME_C(av1_calc_indices)(const int16_t *data, const int16_t *centroids, + uint8_t *indices, int64_t *dist, int n, int k) { if (dist) { *dist = 0; } @@ -149,3 +152,6 @@ void RENAME(av1_k_means)(const int16_t *data, int16_t *centroids, } #undef RENAME_ #undef RENAME +#undef K_MEANS_RENAME_C +#undef RENAME_C_ +#undef RENAME_C diff --git a/third_party/aom/av1/encoder/lookahead.c b/third_party/aom/av1/encoder/lookahead.c index 9ef9b88675..476c91ab95 100644 --- a/third_party/aom/av1/encoder/lookahead.c +++ b/third_party/aom/av1/encoder/lookahead.c @@ -46,7 +46,7 @@ struct lookahead_ctx *av1_lookahead_init( unsigned int width, unsigned int height, unsigned int subsampling_x, unsigned int subsampling_y, int use_highbitdepth, unsigned int depth, const int border_in_pixels, int byte_alignment, int num_lap_buffers, - bool is_all_intra, int num_pyramid_levels) { + bool is_all_intra, bool alloc_pyramid) { int lag_in_frames = AOMMAX(1, depth); // For all-intra frame encoding, previous source frames are not required. @@ -82,7 +82,7 @@ struct lookahead_ctx *av1_lookahead_init( if (aom_realloc_frame_buffer( &ctx->buf[i].img, width, height, subsampling_x, subsampling_y, use_highbitdepth, border_in_pixels, byte_alignment, NULL, NULL, - NULL, num_pyramid_levels, 0)) { + NULL, alloc_pyramid, 0)) { goto fail; } } @@ -100,7 +100,7 @@ int av1_lookahead_full(const struct lookahead_ctx *ctx) { int av1_lookahead_push(struct lookahead_ctx *ctx, const YV12_BUFFER_CONFIG *src, int64_t ts_start, int64_t ts_end, int use_highbitdepth, - int num_pyramid_levels, aom_enc_frame_flags_t flags) { + bool alloc_pyramid, aom_enc_frame_flags_t flags) { int width = src->y_crop_width; int height = src->y_crop_height; int uv_width = src->uv_crop_width; @@ -124,9 +124,9 @@ int av1_lookahead_push(struct lookahead_ctx *ctx, const YV12_BUFFER_CONFIG *src, height != buf->img.y_crop_height || uv_width != buf->img.uv_crop_width || uv_height != buf->img.uv_crop_height; - larger_dimensions = width > buf->img.y_width || height > buf->img.y_height || - uv_width > buf->img.uv_width || - uv_height > buf->img.uv_height; + larger_dimensions = + width > buf->img.y_crop_width || height > buf->img.y_crop_height || + uv_width > buf->img.uv_crop_width || uv_height > buf->img.uv_crop_height; assert(!larger_dimensions || new_dimensions); if (larger_dimensions) { @@ -134,11 +134,15 @@ int av1_lookahead_push(struct lookahead_ctx *ctx, const YV12_BUFFER_CONFIG *src, memset(&new_img, 0, sizeof(new_img)); if (aom_alloc_frame_buffer(&new_img, width, height, subsampling_x, subsampling_y, use_highbitdepth, - AOM_BORDER_IN_PIXELS, 0, num_pyramid_levels, 0)) + AOM_BORDER_IN_PIXELS, 0, alloc_pyramid, 0)) return 1; aom_free_frame_buffer(&buf->img); buf->img = new_img; } else if (new_dimensions) { + buf->img.y_width = src->y_width; + buf->img.y_height = src->y_height; + buf->img.uv_width = src->uv_width; + buf->img.uv_height = src->uv_height; buf->img.y_crop_width = src->y_crop_width; buf->img.y_crop_height = src->y_crop_height; buf->img.uv_crop_width = src->uv_crop_width; @@ -146,7 +150,6 @@ int av1_lookahead_push(struct lookahead_ctx *ctx, const YV12_BUFFER_CONFIG *src, buf->img.subsampling_x = src->subsampling_x; buf->img.subsampling_y = src->subsampling_y; } - // Partial copy not implemented yet av1_copy_and_extend_frame(src, &buf->img); buf->ts_start = ts_start; diff --git a/third_party/aom/av1/encoder/lookahead.h b/third_party/aom/av1/encoder/lookahead.h index c0e6d222f5..41eca87fa3 100644 --- a/third_party/aom/av1/encoder/lookahead.h +++ b/third_party/aom/av1/encoder/lookahead.h @@ -70,7 +70,7 @@ struct lookahead_ctx *av1_lookahead_init( unsigned int width, unsigned int height, unsigned int subsampling_x, unsigned int subsampling_y, int use_highbitdepth, unsigned int depth, const int border_in_pixels, int byte_alignment, int num_lap_buffers, - bool is_all_intra, int num_pyramid_levels); + bool is_all_intra, bool alloc_pyramid); /**\brief Destroys the lookahead stage */ @@ -85,18 +85,18 @@ int av1_lookahead_full(const struct lookahead_ctx *ctx); * This function will copy the source image into a new framebuffer with * the expected stride/border. * - * \param[in] ctx Pointer to the lookahead context - * \param[in] src Pointer to the image to enqueue - * \param[in] ts_start Timestamp for the start of this frame - * \param[in] ts_end Timestamp for the end of this frame - * \param[in] use_highbitdepth Tell if HBD is used - * \param[in] num_pyramid_levels Number of pyramid levels to allocate - for each frame buffer - * \param[in] flags Flags set on this frame + * \param[in] ctx Pointer to the lookahead context + * \param[in] src Pointer to the image to enqueue + * \param[in] ts_start Timestamp for the start of this frame + * \param[in] ts_end Timestamp for the end of this frame + * \param[in] use_highbitdepth Tell if HBD is used + * \param[in] alloc_pyramid Whether to allocate a downsampling pyramid + * for each frame buffer + * \param[in] flags Flags set on this frame */ int av1_lookahead_push(struct lookahead_ctx *ctx, const YV12_BUFFER_CONFIG *src, int64_t ts_start, int64_t ts_end, int use_highbitdepth, - int num_pyramid_levels, aom_enc_frame_flags_t flags); + bool alloc_pyramid, aom_enc_frame_flags_t flags); /**\brief Get the next source buffer to encode * diff --git a/third_party/aom/av1/encoder/nonrd_pickmode.c b/third_party/aom/av1/encoder/nonrd_pickmode.c index f939b6d1fa..57c74f66d5 100644 --- a/third_party/aom/av1/encoder/nonrd_pickmode.c +++ b/third_party/aom/av1/encoder/nonrd_pickmode.c @@ -2357,6 +2357,10 @@ static AOM_FORCE_INLINE bool skip_inter_mode_nonrd( *ref_frame2 = NONE_FRAME; } + if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP) && + (*this_mode != GLOBALMV || *ref_frame != LAST_FRAME)) + return true; + if (x->sb_me_block && *ref_frame == LAST_FRAME) { // We want to make sure to test the superblock MV: // so don't skip (return false) for NEAREST_LAST or NEAR_LAST if they @@ -3241,7 +3245,8 @@ void av1_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, inter_pred_params_sr.conv_params = get_conv_params(/*do_average=*/0, AOM_PLANE_Y, xd->bd); - x->block_is_zero_sad = x->content_state_sb.source_sad_nonrd == kZeroSad; + x->block_is_zero_sad = x->content_state_sb.source_sad_nonrd == kZeroSad || + segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP); if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN && !x->force_zeromv_skip_for_blk && x->content_state_sb.source_sad_nonrd != kZeroSad && diff --git a/third_party/aom/av1/encoder/palette.c b/third_party/aom/av1/encoder/palette.c index 7f79e9596e..45b56199c6 100644 --- a/third_party/aom/av1/encoder/palette.c +++ b/third_party/aom/av1/encoder/palette.c @@ -480,7 +480,7 @@ struct ColorCount { int count; }; -int color_count_comp(const void *c1, const void *c2) { +static int color_count_comp(const void *c1, const void *c2) { const struct ColorCount *color_count1 = (const struct ColorCount *)c1; const struct ColorCount *color_count2 = (const struct ColorCount *)c2; if (color_count1->count > color_count2->count) return -1; diff --git a/third_party/aom/av1/encoder/palette.h b/third_party/aom/av1/encoder/palette.h index 7da863a0cc..30886d37ae 100644 --- a/third_party/aom/av1/encoder/palette.h +++ b/third_party/aom/av1/encoder/palette.h @@ -26,7 +26,7 @@ struct PICK_MODE_CONTEXT; struct macroblock; /*!\cond */ -#define AV1_K_MEANS_RENAME(func, dim) func##_dim##dim##_c +#define AV1_K_MEANS_RENAME(func, dim) func##_dim##dim void AV1_K_MEANS_RENAME(av1_k_means, 1)(const int16_t *data, int16_t *centroids, uint8_t *indices, int n, int k, diff --git a/third_party/aom/av1/encoder/partition_search.c b/third_party/aom/av1/encoder/partition_search.c index 1c17b09ee1..61d49a23f2 100644 --- a/third_party/aom/av1/encoder/partition_search.c +++ b/third_party/aom/av1/encoder/partition_search.c @@ -2144,8 +2144,9 @@ static void encode_b_nonrd(const AV1_COMP *const cpi, TileDataEnc *tile_data, } if (tile_data->allow_update_cdf) update_stats(&cpi->common, td); } - if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && mbmi->skip_txfm && - !cpi->rc.rtc_external_ratectrl && cm->seg.enabled) + if ((cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ || + cpi->active_map.enabled) && + mbmi->skip_txfm && !cpi->rc.rtc_external_ratectrl && cm->seg.enabled) av1_cyclic_reset_segment_skip(cpi, x, mi_row, mi_col, bsize, dry_run); // TODO(Ravi/Remya): Move this copy function to a better logical place // This function will copy the best mode information from block @@ -2254,6 +2255,8 @@ static void pick_sb_modes_nonrd(AV1_COMP *const cpi, TileDataEnc *tile_data, const AQ_MODE aq_mode = cpi->oxcf.q_cfg.aq_mode; TxfmSearchInfo *txfm_info = &x->txfm_search_info; int i; + const int seg_skip = + segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP); // This is only needed for real time/allintra row-mt enabled multi-threaded // encoding with cost update frequency set to COST_UPD_TILE/COST_UPD_OFF. @@ -2276,15 +2279,17 @@ static void pick_sb_modes_nonrd(AV1_COMP *const cpi, TileDataEnc *tile_data, } for (i = 0; i < 2; ++i) pd[i].color_index_map = ctx->color_index_map[i]; - x->force_zeromv_skip_for_blk = - get_force_zeromv_skip_flag_for_blk(cpi, x, bsize); + if (!seg_skip) { + x->force_zeromv_skip_for_blk = + get_force_zeromv_skip_flag_for_blk(cpi, x, bsize); - // Source variance may be already compute at superblock level, so no need - // to recompute, unless bsize < sb_size or source_variance is not yet set. - if (!x->force_zeromv_skip_for_blk && - (x->source_variance == UINT_MAX || bsize < cm->seq_params->sb_size)) - x->source_variance = av1_get_perpixel_variance_facade( - cpi, xd, &x->plane[0].src, bsize, AOM_PLANE_Y); + // Source variance may be already compute at superblock level, so no need + // to recompute, unless bsize < sb_size or source_variance is not yet set. + if (!x->force_zeromv_skip_for_blk && + (x->source_variance == UINT_MAX || bsize < cm->seq_params->sb_size)) + x->source_variance = av1_get_perpixel_variance_facade( + cpi, xd, &x->plane[0].src, bsize, AOM_PLANE_Y); + } // Save rdmult before it might be changed, so it can be restored later. const int orig_rdmult = x->rdmult; @@ -2305,16 +2310,13 @@ static void pick_sb_modes_nonrd(AV1_COMP *const cpi, TileDataEnc *tile_data, #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, nonrd_pick_inter_mode_sb_time); #endif - if (segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { - RD_STATS invalid_rd; - av1_invalid_rd_stats(&invalid_rd); - // TODO(kyslov): add av1_nonrd_pick_inter_mode_sb_seg_skip - av1_rd_pick_inter_mode_sb_seg_skip(cpi, tile_data, x, mi_row, mi_col, - rd_cost, bsize, ctx, - invalid_rd.rdcost); - } else { - av1_nonrd_pick_inter_mode_sb(cpi, tile_data, x, rd_cost, bsize, ctx); + if (seg_skip) { + x->force_zeromv_skip_for_blk = 1; + // TODO(marpan): Consider adding a function for nonrd: + // av1_nonrd_pick_inter_mode_sb_seg_skip(), instead of setting + // x->force_zeromv_skip flag and entering av1_nonrd_pick_inter_mode_sb(). } + av1_nonrd_pick_inter_mode_sb(cpi, tile_data, x, rd_cost, bsize, ctx); #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, nonrd_pick_inter_mode_sb_time); #endif @@ -2322,10 +2324,12 @@ static void pick_sb_modes_nonrd(AV1_COMP *const cpi, TileDataEnc *tile_data, if (cpi->sf.rt_sf.skip_cdef_sb) { // cdef_strength is initialized to 1 which means skip_cdef, and is updated // here. Check to see is skipping cdef is allowed. + // Always allow cdef_skip for seg_skip = 1. const int allow_cdef_skipping = - cpi->rc.frames_since_key > 10 && !cpi->rc.high_source_sad && - !(x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] || - x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)]); + seg_skip || + (cpi->rc.frames_since_key > 10 && !cpi->rc.high_source_sad && + !(x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] || + x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)])); // Find the corresponding 64x64 block. It'll be the 128x128 block if that's // the block size. diff --git a/third_party/aom/av1/encoder/partition_strategy.c b/third_party/aom/av1/encoder/partition_strategy.c index ce06313579..1d62f128c7 100644 --- a/third_party/aom/av1/encoder/partition_strategy.c +++ b/third_party/aom/av1/encoder/partition_strategy.c @@ -1761,7 +1761,7 @@ void av1_prune_partitions_by_max_min_bsize(SuperBlockEnc *sb_enc, // Decide whether to evaluate the AB partition specified by part_type based on // split and HORZ/VERT info -int evaluate_ab_partition_based_on_split( +static int evaluate_ab_partition_based_on_split( const PC_TREE *pc_tree, PARTITION_TYPE rect_part, const RD_RECT_PART_WIN_INFO *rect_part_win_info, int qindex, int split_idx1, int split_idx2) { diff --git a/third_party/aom/av1/encoder/pass2_strategy.c b/third_party/aom/av1/encoder/pass2_strategy.c index a9442ffc1a..bd8620c2be 100644 --- a/third_party/aom/av1/encoder/pass2_strategy.c +++ b/third_party/aom/av1/encoder/pass2_strategy.c @@ -158,28 +158,12 @@ static int frame_max_bits(const RATE_CONTROL *rc, return (int)max_bits; } -static const double q_pow_term[(QINDEX_RANGE >> 5) + 1] = { 0.65, 0.70, 0.75, - 0.80, 0.85, 0.90, - 0.95, 0.95, 0.95 }; -#define ERR_DIVISOR 96.0 -static double calc_correction_factor(double err_per_mb, int q) { - const double error_term = err_per_mb / ERR_DIVISOR; - const int index = q >> 5; - // Adjustment to power term based on qindex - const double power_term = - q_pow_term[index] + - (((q_pow_term[index + 1] - q_pow_term[index]) * (q % 32)) / 32.0); - assert(error_term >= 0.0); - return fclamp(pow(error_term, power_term), 0.05, 5.0); -} - // Based on history adjust expectations of bits per macroblock. static void twopass_update_bpm_factor(AV1_COMP *cpi, int rate_err_tol) { TWO_PASS *const twopass = &cpi->ppi->twopass; const PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc; // Based on recent history adjust expectations of bits per macroblock. - double damp_fac = AOMMAX(5.0, rate_err_tol / 10.0); double rate_err_factor = 1.0; const double adj_limit = AOMMAX(0.2, (double)(100 - rate_err_tol) / 200.0); const double min_fac = 1.0 - adj_limit; @@ -214,9 +198,7 @@ static void twopass_update_bpm_factor(AV1_COMP *cpi, int rate_err_tol) { } int err_estimate = p_rc->rate_error_estimate; - int64_t bits_left = twopass->bits_left; int64_t total_actual_bits = p_rc->total_actual_bits; - int64_t bits_off_target = p_rc->vbr_bits_off_target; double rolling_arf_group_actual_bits = (double)twopass->rolling_arf_group_actual_bits; double rolling_arf_group_target_bits = @@ -231,10 +213,6 @@ static void twopass_update_bpm_factor(AV1_COMP *cpi, int rate_err_tol) { : 0; total_actual_bits = simulate_parallel_frame ? p_rc->temp_total_actual_bits : p_rc->total_actual_bits; - bits_off_target = simulate_parallel_frame ? p_rc->temp_vbr_bits_off_target - : p_rc->vbr_bits_off_target; - bits_left = - simulate_parallel_frame ? p_rc->temp_bits_left : twopass->bits_left; rolling_arf_group_target_bits = (double)(simulate_parallel_frame ? p_rc->temp_rolling_arf_group_target_bits @@ -247,21 +225,21 @@ static void twopass_update_bpm_factor(AV1_COMP *cpi, int rate_err_tol) { : p_rc->rate_error_estimate; #endif - if (p_rc->bits_off_target && total_actual_bits > 0) { - if (cpi->ppi->lap_enabled) { - rate_err_factor = rolling_arf_group_actual_bits / - DOUBLE_DIVIDE_CHECK(rolling_arf_group_target_bits); + if ((p_rc->bits_off_target && total_actual_bits > 0) && + (rolling_arf_group_target_bits >= 1.0)) { + if (rolling_arf_group_actual_bits > rolling_arf_group_target_bits) { + double error_fraction = + (rolling_arf_group_actual_bits - rolling_arf_group_target_bits) / + rolling_arf_group_target_bits; + error_fraction = (error_fraction > 1.0) ? 1.0 : error_fraction; + rate_err_factor = 1.0 + error_fraction; } else { - rate_err_factor = 1.0 - ((double)(bits_off_target) / - AOMMAX(total_actual_bits, bits_left)); + double error_fraction = + (rolling_arf_group_target_bits - rolling_arf_group_actual_bits) / + rolling_arf_group_target_bits; + rate_err_factor = 1.0 - error_fraction; } - // Adjustment is damped if this is 1 pass with look ahead processing - // (as there are only ever a few frames of data) and for all but the first - // GOP in normal two pass. - if ((twopass->bpm_factor != 1.0) || cpi->ppi->lap_enabled) { - rate_err_factor = 1.0 + ((rate_err_factor - 1.0) / damp_fac); - } rate_err_factor = AOMMAX(min_fac, AOMMIN(max_fac, rate_err_factor)); } @@ -270,36 +248,38 @@ static void twopass_update_bpm_factor(AV1_COMP *cpi, int rate_err_tol) { if ((rate_err_factor < 1.0 && err_estimate >= 0) || (rate_err_factor > 1.0 && err_estimate <= 0)) { twopass->bpm_factor *= rate_err_factor; - if (rate_err_tol >= 100) { - twopass->bpm_factor = - AOMMAX(min_fac, AOMMIN(max_fac, twopass->bpm_factor)); - } else { - twopass->bpm_factor = AOMMAX(0.1, AOMMIN(10.0, twopass->bpm_factor)); - } + twopass->bpm_factor = AOMMAX(min_fac, AOMMIN(max_fac, twopass->bpm_factor)); } } -static int qbpm_enumerator(int rate_err_tol) { - return 1200000 + ((300000 * AOMMIN(75, AOMMAX(rate_err_tol - 25, 0))) / 75); +static const double q_div_term[(QINDEX_RANGE >> 5) + 1] = { 32.0, 40.0, 46.0, + 52.0, 56.0, 60.0, + 64.0, 68.0, 72.0 }; +#define EPMB_SCALER 1250000 +static double calc_correction_factor(double err_per_mb, int q) { + double power_term = 0.90; + const int index = q >> 5; + const double divisor = + q_div_term[index] + + (((q_div_term[index + 1] - q_div_term[index]) * (q % 32)) / 32.0); + double error_term = EPMB_SCALER * pow(err_per_mb, power_term); + return error_term / divisor; } // Similar to find_qindex_by_rate() function in ratectrl.c, but includes // calculation of a correction_factor. static int find_qindex_by_rate_with_correction( int desired_bits_per_mb, aom_bit_depth_t bit_depth, double error_per_mb, - double group_weight_factor, int rate_err_tol, int best_qindex, - int worst_qindex) { + double group_weight_factor, int best_qindex, int worst_qindex) { assert(best_qindex <= worst_qindex); int low = best_qindex; int high = worst_qindex; while (low < high) { const int mid = (low + high) >> 1; - const double mid_factor = calc_correction_factor(error_per_mb, mid); + const double q_factor = calc_correction_factor(error_per_mb, mid); const double q = av1_convert_qindex_to_q(mid, bit_depth); - const int enumerator = qbpm_enumerator(rate_err_tol); - const int mid_bits_per_mb = - (int)((enumerator * mid_factor * group_weight_factor) / q); + const int mid_bits_per_mb = (int)((q_factor * group_weight_factor) / q); if (mid_bits_per_mb > desired_bits_per_mb) { low = mid + 1; @@ -359,8 +339,8 @@ static int get_twopass_worst_quality(AV1_COMP *cpi, const double av_frame_err, // content at the given rate. int q = find_qindex_by_rate_with_correction( target_norm_bits_per_mb, cpi->common.seq_params->bit_depth, - av_err_per_mb, cpi->ppi->twopass.bpm_factor, rate_err_tol, - rc->best_quality, rc->worst_quality); + av_err_per_mb, cpi->ppi->twopass.bpm_factor, rc->best_quality, + rc->worst_quality); // Restriction on active max q for constrained quality mode. if (rc_cfg->mode == AOM_CQ) q = AOMMAX(q, rc_cfg->cq_level); @@ -4235,12 +4215,13 @@ void av1_twopass_postencode_update(AV1_COMP *cpi) { twopass->kf_group_bits = AOMMAX(twopass->kf_group_bits, 0); // If the rate control is drifting consider adjustment to min or maxq. - if ((rc_cfg->mode != AOM_Q) && !cpi->rc.is_src_frame_alt_ref) { + if ((rc_cfg->mode != AOM_Q) && !cpi->rc.is_src_frame_alt_ref && + (p_rc->rolling_target_bits > 0)) { int minq_adj_limit; int maxq_adj_limit; minq_adj_limit = (rc_cfg->mode == AOM_CQ ? MINQ_ADJ_LIMIT_CQ : MINQ_ADJ_LIMIT); - maxq_adj_limit = rc->worst_quality - rc->active_worst_quality; + maxq_adj_limit = (rc->worst_quality - rc->active_worst_quality); // Undershoot if ((rc_cfg->under_shoot_pct < 100) && @@ -4252,8 +4233,9 @@ void av1_twopass_postencode_update(AV1_COMP *cpi) { if ((pct_error >= rc_cfg->under_shoot_pct) && (p_rc->rate_error_estimate > 0)) { twopass->extend_minq += 1; + twopass->extend_maxq -= 1; } - twopass->extend_maxq -= 1; + // Overshoot } else if ((rc_cfg->over_shoot_pct < 100) && (p_rc->rolling_actual_bits > p_rc->rolling_target_bits)) { @@ -4265,18 +4247,8 @@ void av1_twopass_postencode_update(AV1_COMP *cpi) { if ((pct_error >= rc_cfg->over_shoot_pct) && (p_rc->rate_error_estimate < 0)) { twopass->extend_maxq += 1; + twopass->extend_minq -= 1; } - twopass->extend_minq -= 1; - } else { - // Adjustment for extreme local overshoot. - // Only applies when normal adjustment above is not used (e.g. - // when threshold is set to 100). - if (rc->projected_frame_size > (2 * rc->base_frame_target) && - rc->projected_frame_size > (2 * rc->avg_frame_bandwidth)) - ++twopass->extend_maxq; - // Unwind extreme overshoot adjustment. - else if (p_rc->rolling_target_bits > p_rc->rolling_actual_bits) - --twopass->extend_maxq; } twopass->extend_minq = clamp(twopass->extend_minq, -minq_adj_limit, minq_adj_limit); diff --git a/third_party/aom/av1/encoder/pickcdef.c b/third_party/aom/av1/encoder/pickcdef.c index 232a2f9edb..ed5fa55f17 100644 --- a/third_party/aom/av1/encoder/pickcdef.c +++ b/third_party/aom/av1/encoder/pickcdef.c @@ -894,7 +894,7 @@ void av1_cdef_search(AV1_COMP *cpi) { int rdmult = cpi->td.mb.rdmult; for (int i = 0; i <= 3; i++) { if (i > max_signaling_bits) break; - int best_lev0[CDEF_MAX_STRENGTHS]; + int best_lev0[CDEF_MAX_STRENGTHS] = { 0 }; int best_lev1[CDEF_MAX_STRENGTHS] = { 0 }; const int nb_strengths = 1 << i; uint64_t tot_mse; diff --git a/third_party/aom/av1/encoder/picklpf.c b/third_party/aom/av1/encoder/picklpf.c index 9084d3f13a..a504535028 100644 --- a/third_party/aom/av1/encoder/picklpf.c +++ b/third_party/aom/av1/encoder/picklpf.c @@ -27,12 +27,25 @@ #include "av1/encoder/encoder.h" #include "av1/encoder/picklpf.h" +// AV1 loop filter applies to the whole frame according to mi_rows and mi_cols, +// which are calculated based on aligned width and aligned height, +// In addition, if super res is enabled, it copies the whole frame +// according to the aligned width and height (av1_superres_upscale()). +// So we need to copy the whole filtered region, instead of the cropped region. +// For example, input image size is: 160x90. +// Then src->y_crop_width = 160, src->y_crop_height = 90. +// The aligned frame size is: src->y_width = 160, src->y_height = 96. +// AV1 aligns frame size to a multiple of 8, if there is +// chroma subsampling, it is able to ensure the chroma is also +// an integer number of mi units. mi unit is 4x4, 8 = 4 * 2, and 2 luma mi +// units correspond to 1 chroma mi unit if there is subsampling. +// See: aom_realloc_frame_buffer() in yv12config.c. static void yv12_copy_plane(const YV12_BUFFER_CONFIG *src_bc, YV12_BUFFER_CONFIG *dst_bc, int plane) { switch (plane) { - case 0: aom_yv12_copy_y(src_bc, dst_bc); break; - case 1: aom_yv12_copy_u(src_bc, dst_bc); break; - case 2: aom_yv12_copy_v(src_bc, dst_bc); break; + case 0: aom_yv12_copy_y(src_bc, dst_bc, 0); break; + case 1: aom_yv12_copy_u(src_bc, dst_bc, 0); break; + case 2: aom_yv12_copy_v(src_bc, dst_bc, 0); break; default: assert(plane >= 0 && plane <= 2); break; } } @@ -311,7 +324,7 @@ void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi, &cpi->last_frame_uf, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, NULL, NULL, NULL, 0, 0)) + cm->features.byte_alignment, NULL, NULL, NULL, false, 0)) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate last frame buffer"); diff --git a/third_party/aom/av1/encoder/pickrst.c b/third_party/aom/av1/encoder/pickrst.c index 6429064175..b0d0d0bb78 100644 --- a/third_party/aom/av1/encoder/pickrst.c +++ b/third_party/aom/av1/encoder/pickrst.c @@ -1103,6 +1103,39 @@ static INLINE int wrap_index(int i, int wiener_win) { return (i >= wiener_halfwin1 ? wiener_win - 1 - i : i); } +// Splits each w[i] into smaller components w1[i] and w2[i] such that +// w[i] = w1[i] * WIENER_TAP_SCALE_FACTOR + w2[i]. +static INLINE void split_wiener_filter_coefficients(int wiener_win, + const int32_t *w, + int32_t *w1, int32_t *w2) { + for (int i = 0; i < wiener_win; i++) { + w1[i] = w[i] / WIENER_TAP_SCALE_FACTOR; + w2[i] = w[i] - w1[i] * WIENER_TAP_SCALE_FACTOR; + assert(w[i] == w1[i] * WIENER_TAP_SCALE_FACTOR + w2[i]); + } +} + +// Calculates x * w / WIENER_TAP_SCALE_FACTOR, where +// w = w1 * WIENER_TAP_SCALE_FACTOR + w2. +// +// The multiplication x * w may overflow, so we multiply x by the components of +// w (w1 and w2) and combine the multiplication with the division. +static INLINE int64_t multiply_and_scale(int64_t x, int32_t w1, int32_t w2) { + // Let y = x * w / WIENER_TAP_SCALE_FACTOR + // = x * (w1 * WIENER_TAP_SCALE_FACTOR + w2) / WIENER_TAP_SCALE_FACTOR + const int64_t y = x * w1 + x * w2 / WIENER_TAP_SCALE_FACTOR; + // Double-check the calculation using __int128. + // TODO(wtc): Remove after 2024-04-30. +#if !defined(NDEBUG) && defined(__GNUC__) && defined(__LP64__) + const int32_t w = w1 * WIENER_TAP_SCALE_FACTOR + w2; + const __int128 z = (__int128)x * w / WIENER_TAP_SCALE_FACTOR; + assert(z >= INT64_MIN); + assert(z <= INT64_MAX); + assert(y == (int64_t)z); +#endif + return y; +} + // Solve linear equations to find Wiener filter tap values // Taps are output scaled by WIENER_FILT_STEP static int linsolve_wiener(int n, int64_t *A, int stride, int64_t *b, @@ -1175,10 +1208,12 @@ static int linsolve_wiener(int n, int64_t *A, int stride, int64_t *b, // Fix vector b, update vector a static AOM_INLINE void update_a_sep_sym(int wiener_win, int64_t **Mc, - int64_t **Hc, int32_t *a, int32_t *b) { + int64_t **Hc, int32_t *a, + const int32_t *b) { int i, j; int64_t S[WIENER_WIN]; int64_t A[WIENER_HALFWIN1], B[WIENER_HALFWIN1 * WIENER_HALFWIN1]; + int32_t b1[WIENER_WIN], b2[WIENER_WIN]; const int wiener_win2 = wiener_win * wiener_win; const int wiener_halfwin1 = (wiener_win >> 1) + 1; memset(A, 0, sizeof(A)); @@ -1189,16 +1224,7 @@ static AOM_INLINE void update_a_sep_sym(int wiener_win, int64_t **Mc, A[jj] += Mc[i][j] * b[i] / WIENER_TAP_SCALE_FACTOR; } } - - // b/274668506: This is the dual branch for the issue in b/272139363. The fix - // is similar. See comments in update_b_sep_sym() below. - int32_t max_b_l = 0; - for (int l = 0; l < wiener_win; ++l) { - const int32_t abs_b_l = abs(b[l]); - if (abs_b_l > max_b_l) max_b_l = abs_b_l; - } - const int scale_threshold = 128 * WIENER_TAP_SCALE_FACTOR; - const int scaler = max_b_l < scale_threshold ? 1 : 4; + split_wiener_filter_coefficients(wiener_win, b, b1, b2); for (i = 0; i < wiener_win; i++) { for (j = 0; j < wiener_win; j++) { @@ -1207,10 +1233,17 @@ static AOM_INLINE void update_a_sep_sym(int wiener_win, int64_t **Mc, const int kk = wrap_index(k, wiener_win); for (l = 0; l < wiener_win; ++l) { const int ll = wrap_index(l, wiener_win); - B[ll * wiener_halfwin1 + kk] += - Hc[j * wiener_win + i][k * wiener_win2 + l] * b[i] / - (scaler * WIENER_TAP_SCALE_FACTOR) * b[j] / - (WIENER_TAP_SCALE_FACTOR / scaler); + // Calculate + // B[ll * wiener_halfwin1 + kk] += + // Hc[j * wiener_win + i][k * wiener_win2 + l] * b[i] / + // WIENER_TAP_SCALE_FACTOR * b[j] / WIENER_TAP_SCALE_FACTOR; + // + // The last multiplication may overflow, so we combine the last + // multiplication with the last division. + const int64_t x = Hc[j * wiener_win + i][k * wiener_win2 + l] * b[i] / + WIENER_TAP_SCALE_FACTOR; + // b[j] = b1[j] * WIENER_TAP_SCALE_FACTOR + b2[j] + B[ll * wiener_halfwin1 + kk] += multiply_and_scale(x, b1[j], b2[j]); } } } @@ -1246,10 +1279,12 @@ static AOM_INLINE void update_a_sep_sym(int wiener_win, int64_t **Mc, // Fix vector a, update vector b static AOM_INLINE void update_b_sep_sym(int wiener_win, int64_t **Mc, - int64_t **Hc, int32_t *a, int32_t *b) { + int64_t **Hc, const int32_t *a, + int32_t *b) { int i, j; int64_t S[WIENER_WIN]; int64_t A[WIENER_HALFWIN1], B[WIENER_HALFWIN1 * WIENER_HALFWIN1]; + int32_t a1[WIENER_WIN], a2[WIENER_WIN]; const int wiener_win2 = wiener_win * wiener_win; const int wiener_halfwin1 = (wiener_win >> 1) + 1; memset(A, 0, sizeof(A)); @@ -1260,32 +1295,7 @@ static AOM_INLINE void update_b_sep_sym(int wiener_win, int64_t **Mc, A[ii] += Mc[i][j] * a[j] / WIENER_TAP_SCALE_FACTOR; } } - - // b/272139363: The computation, - // Hc[i * wiener_win + j][k * wiener_win2 + l] * a[k] / - // WIENER_TAP_SCALE_FACTOR * a[l] / WIENER_TAP_SCALE_FACTOR; - // may generate a signed-integer-overflow. Conditionally scale the terms to - // avoid a potential overflow. - // - // Hc contains accumulated correlation statistics and it is desired to leave - // as much room as possible for Hc. It was experimentally observed that the - // primary issue manifests itself with the second, a[l], multiply. For - // max_a_l < WIENER_TAP_SCALE_FACTOR the first multiply with a[k] should not - // increase dynamic range and the second multiply should hence be safe. - // Thereafter a safe scale_threshold depends on the actual operational range - // of Hc. The largest scale_threshold is expected to depend on bit-depth - // (av1_compute_stats_highbd_c() scales highbd to 8-bit) and maximum - // restoration-unit size (256), leading up to 32-bit positive numbers in Hc. - // Noting that the caller, wiener_decompose_sep_sym(), initializes a[...] - // to a range smaller than 16 bits, the scale_threshold is set as below for - // convenience. - int32_t max_a_l = 0; - for (int l = 0; l < wiener_win; ++l) { - const int32_t abs_a_l = abs(a[l]); - if (abs_a_l > max_a_l) max_a_l = abs_a_l; - } - const int scale_threshold = 128 * WIENER_TAP_SCALE_FACTOR; - const int scaler = max_a_l < scale_threshold ? 1 : 4; + split_wiener_filter_coefficients(wiener_win, a, a1, a2); for (i = 0; i < wiener_win; i++) { const int ii = wrap_index(i, wiener_win); @@ -1294,10 +1304,17 @@ static AOM_INLINE void update_b_sep_sym(int wiener_win, int64_t **Mc, int k, l; for (k = 0; k < wiener_win; ++k) { for (l = 0; l < wiener_win; ++l) { - B[jj * wiener_halfwin1 + ii] += - Hc[i * wiener_win + j][k * wiener_win2 + l] * a[k] / - (scaler * WIENER_TAP_SCALE_FACTOR) * a[l] / - (WIENER_TAP_SCALE_FACTOR / scaler); + // Calculate + // B[jj * wiener_halfwin1 + ii] += + // Hc[i * wiener_win + j][k * wiener_win2 + l] * a[k] / + // WIENER_TAP_SCALE_FACTOR * a[l] / WIENER_TAP_SCALE_FACTOR; + // + // The last multiplication may overflow, so we combine the last + // multiplication with the last division. + const int64_t x = Hc[i * wiener_win + j][k * wiener_win2 + l] * a[k] / + WIENER_TAP_SCALE_FACTOR; + // a[l] = a1[l] * WIENER_TAP_SCALE_FACTOR + a2[l] + B[jj * wiener_halfwin1 + ii] += multiply_and_scale(x, a1[l], a2[l]); } } } @@ -2050,7 +2067,7 @@ void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi) { &cpi->trial_frame_rst, cm->superres_upscaled_width, cm->superres_upscaled_height, seq_params->subsampling_x, seq_params->subsampling_y, highbd, AOM_RESTORATION_FRAME_BORDER, - cm->features.byte_alignment, NULL, NULL, NULL, 0, 0)) + cm->features.byte_alignment, NULL, NULL, NULL, false, 0)) aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate trial restored frame buffer"); diff --git a/third_party/aom/av1/encoder/ratectrl.c b/third_party/aom/av1/encoder/ratectrl.c index df86380272..7639484df5 100644 --- a/third_party/aom/av1/encoder/ratectrl.c +++ b/third_party/aom/av1/encoder/ratectrl.c @@ -30,6 +30,7 @@ #include "av1/common/seg_common.h" #include "av1/encoder/encodemv.h" +#include "av1/encoder/encoder_utils.h" #include "av1/encoder/encode_strategy.h" #include "av1/encoder/gop_structure.h" #include "av1/encoder/random.h" @@ -405,10 +406,10 @@ void av1_primary_rc_init(const AV1EncoderConfig *oxcf, p_rc->rate_correction_factors[KF_STD] = 1.0; p_rc->bits_off_target = p_rc->starting_buffer_level; - p_rc->rolling_target_bits = - (int)(oxcf->rc_cfg.target_bandwidth / oxcf->input_cfg.init_framerate); - p_rc->rolling_actual_bits = - (int)(oxcf->rc_cfg.target_bandwidth / oxcf->input_cfg.init_framerate); + p_rc->rolling_target_bits = AOMMAX( + 1, (int)(oxcf->rc_cfg.target_bandwidth / oxcf->input_cfg.init_framerate)); + p_rc->rolling_actual_bits = AOMMAX( + 1, (int)(oxcf->rc_cfg.target_bandwidth / oxcf->input_cfg.init_framerate)); } void av1_rc_init(const AV1EncoderConfig *oxcf, RATE_CONTROL *rc) { @@ -439,6 +440,7 @@ void av1_rc_init(const AV1EncoderConfig *oxcf, RATE_CONTROL *rc) { rc->rtc_external_ratectrl = 0; rc->frame_level_fast_extra_bits = 0; rc->use_external_qp_one_pass = 0; + rc->percent_blocks_inactive = 0; } static bool check_buffer_below_thresh(AV1_COMP *cpi, int64_t buffer_level, @@ -1719,41 +1721,39 @@ static void adjust_active_best_and_worst_quality(const AV1_COMP *cpi, const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; const PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc; - const RefreshFrameInfo *const refresh_frame = &cpi->refresh_frame; int active_best_quality = *active_best; int active_worst_quality = *active_worst; #if CONFIG_FPMT_TEST - const int simulate_parallel_frame = - cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && - cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; - int extend_minq = simulate_parallel_frame ? p_rc->temp_extend_minq - : cpi->ppi->twopass.extend_minq; - int extend_maxq = simulate_parallel_frame ? p_rc->temp_extend_maxq - : cpi->ppi->twopass.extend_maxq; #endif // Extension to max or min Q if undershoot or overshoot is outside // the permitted range. if (cpi->oxcf.rc_cfg.mode != AOM_Q) { +#if CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + const int extend_minq = simulate_parallel_frame + ? p_rc->temp_extend_minq + : cpi->ppi->twopass.extend_minq; + const int extend_maxq = simulate_parallel_frame + ? p_rc->temp_extend_maxq + : cpi->ppi->twopass.extend_maxq; + const RefreshFrameInfo *const refresh_frame = &cpi->refresh_frame; if (frame_is_intra_only(cm) || (!rc->is_src_frame_alt_ref && (refresh_frame->golden_frame || is_intrl_arf_boost || refresh_frame->alt_ref_frame))) { -#if CONFIG_FPMT_TEST active_best_quality -= extend_minq; active_worst_quality += (extend_maxq / 2); -#else - active_best_quality -= cpi->ppi->twopass.extend_minq / 4; - active_worst_quality += (cpi->ppi->twopass.extend_maxq / 2); -#endif } else { -#if CONFIG_FPMT_TEST active_best_quality -= extend_minq / 2; active_worst_quality += extend_maxq; + } #else - active_best_quality -= cpi->ppi->twopass.extend_minq / 4; - active_worst_quality += cpi->ppi->twopass.extend_maxq; + (void)is_intrl_arf_boost; + active_best_quality -= cpi->ppi->twopass.extend_minq / 8; + active_worst_quality += cpi->ppi->twopass.extend_maxq / 4; #endif - } } #ifndef STRICT_RC @@ -2991,6 +2991,24 @@ void av1_set_rtc_reference_structure_one_layer(AV1_COMP *cpi, int gf_update) { cpi->rt_reduce_num_ref_buffers &= (rtc_ref->ref_idx[2] < 7); } +static int set_block_is_active(unsigned char *const active_map_4x4, int mi_cols, + int mi_rows, int sbi_col, int sbi_row, int sh, + int num_4x4) { + int r = sbi_row << sh; + int c = sbi_col << sh; + const int row_max = AOMMIN(num_4x4, mi_rows - r); + const int col_max = AOMMIN(num_4x4, mi_cols - c); + // Active map is set for 16x16 blocks, so only need to + // check over16x16, + for (int x = 0; x < row_max; x += 4) { + for (int y = 0; y < col_max; y += 4) { + if (active_map_4x4[(r + x) * mi_cols + (c + y)] == AM_SEGMENT_ID_ACTIVE) + return 1; + } + } + return 0; +} + /*!\brief Check for scene detection, for 1 pass real-time mode. * * Compute average source sad (temporal sad: between current source and @@ -3093,11 +3111,26 @@ static void rc_scene_detection_onepass_rt(AV1_COMP *cpi, sizeof(*cpi->src_sad_blk_64x64))); } } + const CommonModeInfoParams *const mi_params = &cpi->common.mi_params; + const int mi_cols = mi_params->mi_cols; + const int mi_rows = mi_params->mi_rows; + int sh = (cm->seq_params->sb_size == BLOCK_128X128) ? 5 : 4; + int num_4x4 = (cm->seq_params->sb_size == BLOCK_128X128) ? 32 : 16; + unsigned char *const active_map_4x4 = cpi->active_map.map; // Avoid bottom and right border. for (int sbi_row = 0; sbi_row < sb_rows - border; ++sbi_row) { for (int sbi_col = 0; sbi_col < sb_cols; ++sbi_col) { - tmp_sad = cpi->ppi->fn_ptr[bsize].sdf(src_y, src_ystride, last_src_y, - last_src_ystride); + int block_is_active = 1; + if (cpi->active_map.enabled && rc->percent_blocks_inactive > 0) { + block_is_active = set_block_is_active(active_map_4x4, mi_cols, mi_rows, + sbi_col, sbi_row, sh, num_4x4); + } + if (block_is_active) { + tmp_sad = cpi->ppi->fn_ptr[bsize].sdf(src_y, src_ystride, last_src_y, + last_src_ystride); + } else { + tmp_sad = 0; + } if (cpi->src_sad_blk_64x64 != NULL) cpi->src_sad_blk_64x64[sbi_col + sbi_row * sb_cols] = tmp_sad; if (check_light_change) { @@ -3456,8 +3489,13 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, FRAME_TYPE *const frame_type, } } } - // Check for scene change: for SVC check on base spatial layer only. - if (cpi->sf.rt_sf.check_scene_detection && svc->spatial_layer_id == 0) { + if (cpi->active_map.enabled && cpi->rc.percent_blocks_inactive == 100) { + rc->frame_source_sad = 0; + rc->avg_source_sad = (3 * rc->avg_source_sad + rc->frame_source_sad) >> 2; + rc->percent_blocks_with_motion = 0; + rc->high_source_sad = 0; + } else if (cpi->sf.rt_sf.check_scene_detection && + svc->spatial_layer_id == 0) { if (rc->prev_coded_width == cm->width && rc->prev_coded_height == cm->height) { rc_scene_detection_onepass_rt(cpi, frame_input); @@ -3522,6 +3560,10 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, FRAME_TYPE *const frame_type, } } +#define CHECK_INTER_LAYER_PRED(ref_frame) \ + ((cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) && \ + (av1_check_ref_is_low_spatial_res_super_frame(cpi, ref_frame))) + int av1_encodedframe_overshoot_cbr(AV1_COMP *cpi, int *q) { AV1_COMMON *const cm = &cpi->common; PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc; @@ -3532,12 +3574,26 @@ int av1_encodedframe_overshoot_cbr(AV1_COMP *cpi, int *q) { int target_bits_per_mb; double q2; int enumerator; + int inter_layer_pred_on = 0; int is_screen_content = (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN); - *q = (3 * cpi->rc.worst_quality + *q) >> 2; - // For screen content use the max-q set by the user to allow for less - // overshoot on slide changes. - if (is_screen_content) *q = cpi->rc.worst_quality; cpi->cyclic_refresh->counter_encode_maxq_scene_change = 0; + if (cpi->svc.spatial_layer_id > 0) { + // For spatial layers: check if inter-layer (spatial) prediction is used + // (check if any reference is being used that is the lower spatial layer), + inter_layer_pred_on = CHECK_INTER_LAYER_PRED(LAST_FRAME) || + CHECK_INTER_LAYER_PRED(GOLDEN_FRAME) || + CHECK_INTER_LAYER_PRED(ALTREF_FRAME); + } + // If inter-layer prediction is on: we expect to pull up the quality from + // the lower spatial layer, so we can use a lower q. + if (cpi->svc.spatial_layer_id > 0 && inter_layer_pred_on) { + *q = (cpi->rc.worst_quality + *q) >> 1; + } else { + *q = (3 * cpi->rc.worst_quality + *q) >> 2; + // For screen content use the max-q set by the user to allow for less + // overshoot on slide changes. + if (is_screen_content) *q = cpi->rc.worst_quality; + } // Adjust avg_frame_qindex, buffer_level, and rate correction factors, as // these parameters will affect QP selection for subsequent frames. If they // have settled down to a very different (low QP) state, then not adjusting @@ -3566,8 +3622,10 @@ int av1_encodedframe_overshoot_cbr(AV1_COMP *cpi, int *q) { rate_correction_factor; } // For temporal layers: reset the rate control parameters across all - // temporal layers. - if (cpi->svc.number_temporal_layers > 1) { + // temporal layers. Only do it for spatial enhancement layers when + // inter_layer_pred_on is not set (off). + if (cpi->svc.number_temporal_layers > 1 && + (cpi->svc.spatial_layer_id == 0 || inter_layer_pred_on == 0)) { SVC *svc = &cpi->svc; for (int tl = 0; tl < svc->number_temporal_layers; ++tl) { int sl = svc->spatial_layer_id; diff --git a/third_party/aom/av1/encoder/ratectrl.h b/third_party/aom/av1/encoder/ratectrl.h index 6802ad42d0..5121a909f4 100644 --- a/third_party/aom/av1/encoder/ratectrl.h +++ b/third_party/aom/av1/encoder/ratectrl.h @@ -249,6 +249,9 @@ typedef struct { // signals if number of blocks with motion is high int percent_blocks_with_motion; + // signals percentage of 16x16 blocks that are inactive, via active_maps + int percent_blocks_inactive; + // Maximum value of source sad across all blocks of frame. uint64_t max_block_source_sad; diff --git a/third_party/aom/av1/encoder/speed_features.c b/third_party/aom/av1/encoder/speed_features.c index 63d69cadc5..256b6fc9eb 100644 --- a/third_party/aom/av1/encoder/speed_features.c +++ b/third_party/aom/av1/encoder/speed_features.c @@ -1177,6 +1177,7 @@ static void set_good_speed_features_framesize_independent( sf->mv_sf.subpel_search_method = SUBPEL_TREE_PRUNED_MORE; sf->gm_sf.prune_zero_mv_with_sse = 2; + sf->gm_sf.downsample_level = 1; sf->part_sf.simple_motion_search_prune_agg = allow_screen_content_tools ? SIMPLE_AGG_LVL0 : SIMPLE_AGG_LVL2; @@ -1282,6 +1283,8 @@ static void set_good_speed_features_framesize_independent( sf->hl_sf.disable_extra_sc_testing = 1; sf->hl_sf.second_alt_ref_filtering = 0; + sf->gm_sf.downsample_level = 2; + sf->inter_sf.prune_inter_modes_based_on_tpl = boosted ? 0 : 3; sf->inter_sf.selective_ref_frame = 6; sf->inter_sf.prune_single_ref = is_boosted_arf2_bwd_type ? 0 : 2; @@ -1465,6 +1468,7 @@ static void set_rt_speed_feature_framesize_dependent(const AV1_COMP *const cpi, if (is_360p_or_larger) { sf->part_sf.fixed_partition_size = BLOCK_32X32; sf->rt_sf.use_fast_fixed_part = 1; + sf->mv_sf.subpel_force_stop = HALF_PEL; } sf->rt_sf.increase_source_sad_thresh = 1; sf->rt_sf.part_early_exit_zeromv = 2; @@ -1472,6 +1476,7 @@ static void set_rt_speed_feature_framesize_dependent(const AV1_COMP *const cpi, for (int i = 0; i < BLOCK_SIZES; ++i) { sf->rt_sf.intra_y_mode_bsize_mask_nrd[i] = INTRA_DC; } + sf->rt_sf.hybrid_intra_pickmode = 0; } // Setting for SVC, or when the ref_frame_config control is // used to set the reference structure. @@ -1572,13 +1577,13 @@ static void set_rt_speed_feature_framesize_dependent(const AV1_COMP *const cpi, sf->rt_sf.screen_content_cdef_filter_qindex_thresh = 80; sf->rt_sf.part_early_exit_zeromv = 1; sf->rt_sf.nonrd_aggressive_skip = 1; + sf->rt_sf.thresh_active_maps_skip_lf_cdef = 90; } if (speed >= 11) { sf->rt_sf.skip_lf_screen = 2; sf->rt_sf.skip_cdef_sb = 2; sf->rt_sf.part_early_exit_zeromv = 2; sf->rt_sf.prune_palette_nonrd = 1; - sf->rt_sf.set_zeromv_skip_based_on_source_sad = 2; sf->rt_sf.increase_color_thresh_palette = 0; } sf->rt_sf.use_nonrd_altref_frame = 0; @@ -1974,6 +1979,7 @@ static AOM_INLINE void init_gm_sf(GLOBAL_MOTION_SPEED_FEATURES *gm_sf) { gm_sf->prune_ref_frame_for_gm_search = 0; gm_sf->prune_zero_mv_with_sse = 0; gm_sf->disable_gm_search_based_on_stats = 0; + gm_sf->downsample_level = 0; gm_sf->num_refinement_steps = GM_MAX_REFINEMENT_STEPS; } @@ -2270,6 +2276,7 @@ static AOM_INLINE void init_rt_sf(REAL_TIME_SPEED_FEATURES *rt_sf) { rt_sf->part_early_exit_zeromv = 0; rt_sf->sse_early_term_inter_search = EARLY_TERM_DISABLED; rt_sf->skip_lf_screen = 0; + rt_sf->thresh_active_maps_skip_lf_cdef = 100; rt_sf->sad_based_adp_altref_lag = 0; rt_sf->partition_direct_merging = 0; rt_sf->var_part_based_on_qidx = 0; diff --git a/third_party/aom/av1/encoder/speed_features.h b/third_party/aom/av1/encoder/speed_features.h index 60c000e4f4..d59cb38a71 100644 --- a/third_party/aom/av1/encoder/speed_features.h +++ b/third_party/aom/av1/encoder/speed_features.h @@ -587,6 +587,9 @@ typedef struct GLOBAL_MOTION_SPEED_FEATURES { // GF group int disable_gm_search_based_on_stats; + // Downsampling pyramid level to use for global motion estimation + int downsample_level; + // Number of refinement steps to apply after initial model generation int num_refinement_steps; } GLOBAL_MOTION_SPEED_FEATURES; @@ -1771,6 +1774,10 @@ typedef struct REAL_TIME_SPEED_FEATURES { // where rc->high_source_sad = 0 (no slide-changes). int skip_lf_screen; + // Threshold on the active/inactive region percent to disable + // the loopfilter and cdef. Setting to 100 disables this feature. + int thresh_active_maps_skip_lf_cdef; + // For nonrd: early exit out of variance partition that sets the // block size to superblock size, and sets mode to zeromv-last skip. // 0: disabled diff --git a/third_party/aom/av1/encoder/superres_scale.c b/third_party/aom/av1/encoder/superres_scale.c index 3b47909b15..41225d55ae 100644 --- a/third_party/aom/av1/encoder/superres_scale.c +++ b/third_party/aom/av1/encoder/superres_scale.c @@ -404,7 +404,7 @@ void av1_superres_post_encode(AV1_COMP *cpi) { assert(!is_lossless_requested(&cpi->oxcf.rc_cfg)); assert(!cm->features.all_lossless); - av1_superres_upscale(cm, NULL, cpi->image_pyramid_levels); + av1_superres_upscale(cm, NULL, cpi->alloc_pyramid); // If regular resizing is occurring the source will need to be downscaled to // match the upscaled superres resolution. Otherwise the original source is diff --git a/third_party/aom/av1/encoder/svc_layercontext.c b/third_party/aom/av1/encoder/svc_layercontext.c index 2c99cb89b8..33da3afbd3 100644 --- a/third_party/aom/av1/encoder/svc_layercontext.c +++ b/third_party/aom/av1/encoder/svc_layercontext.c @@ -203,8 +203,10 @@ void av1_update_temporal_layer_framerate(AV1_COMP *const cpi) { } } -static AOM_INLINE bool check_ref_is_low_spatial_res_super_frame( - int ref_frame, const SVC *svc, const RTC_REF *rtc_ref) { +bool av1_check_ref_is_low_spatial_res_super_frame(AV1_COMP *const cpi, + int ref_frame) { + SVC *svc = &cpi->svc; + RTC_REF *const rtc_ref = &cpi->ppi->rtc_ref; int ref_frame_idx = rtc_ref->ref_idx[ref_frame - 1]; return rtc_ref->buffer_time_index[ref_frame_idx] == svc->current_superframe && rtc_ref->buffer_spatial_layer[ref_frame_idx] <= @@ -253,13 +255,13 @@ void av1_restore_layer_context(AV1_COMP *const cpi) { // previous spatial layer(s) at the same time (current_superframe). if (rtc_ref->set_ref_frame_config && svc->force_zero_mode_spatial_ref && cpi->sf.rt_sf.use_nonrd_pick_mode) { - if (check_ref_is_low_spatial_res_super_frame(LAST_FRAME, svc, rtc_ref)) { + if (av1_check_ref_is_low_spatial_res_super_frame(cpi, LAST_FRAME)) { svc->skip_mvsearch_last = 1; } - if (check_ref_is_low_spatial_res_super_frame(GOLDEN_FRAME, svc, rtc_ref)) { + if (av1_check_ref_is_low_spatial_res_super_frame(cpi, GOLDEN_FRAME)) { svc->skip_mvsearch_gf = 1; } - if (check_ref_is_low_spatial_res_super_frame(ALTREF_FRAME, svc, rtc_ref)) { + if (av1_check_ref_is_low_spatial_res_super_frame(cpi, ALTREF_FRAME)) { svc->skip_mvsearch_altref = 1; } } diff --git a/third_party/aom/av1/encoder/svc_layercontext.h b/third_party/aom/av1/encoder/svc_layercontext.h index 93118be2d4..d56ea77791 100644 --- a/third_party/aom/av1/encoder/svc_layercontext.h +++ b/third_party/aom/av1/encoder/svc_layercontext.h @@ -223,6 +223,21 @@ void av1_update_layer_context_change_config(struct AV1_COMP *const cpi, */ void av1_update_temporal_layer_framerate(struct AV1_COMP *const cpi); +/*!\brief Prior to check if reference is lower spatial layer at the same + * timestamp/superframe. + * + * \ingroup SVC + * \callgraph + * \callergraph + * + * \param[in] cpi Top level encoder structure + * \param[in] ref_frame Reference frame + * + * \return True if the ref_frame if lower spatial layer, otherwise false. + */ +bool av1_check_ref_is_low_spatial_res_super_frame(struct AV1_COMP *const cpi, + int ref_frame); + /*!\brief Prior to encoding the frame, set the layer context, for the current layer to be encoded, to the cpi struct. * diff --git a/third_party/aom/av1/encoder/temporal_filter.c b/third_party/aom/av1/encoder/temporal_filter.c index 7d4d25de6a..e8cc145030 100644 --- a/third_party/aom/av1/encoder/temporal_filter.c +++ b/third_party/aom/av1/encoder/temporal_filter.c @@ -463,12 +463,12 @@ static void tf_build_predictor(const YV12_BUFFER_CONFIG *ref_frame, // Returns: // Nothing will be returned. But the content to which `accum` and `pred` // point will be modified. -void tf_apply_temporal_filter_self(const YV12_BUFFER_CONFIG *ref_frame, - const MACROBLOCKD *mbd, - const BLOCK_SIZE block_size, - const int mb_row, const int mb_col, - const int num_planes, uint32_t *accum, - uint16_t *count) { +static void tf_apply_temporal_filter_self(const YV12_BUFFER_CONFIG *ref_frame, + const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, + const int mb_row, const int mb_col, + const int num_planes, uint32_t *accum, + uint16_t *count) { // Block information. const int mb_height = block_size_high[block_size]; const int mb_width = block_size_wide[block_size]; @@ -564,9 +564,10 @@ static INLINE void compute_square_diff(const uint8_t *ref, const int ref_offset, // Returns: // Nothing will be returned. But the content to which `luma_sse_sum` points // will be modified. -void compute_luma_sq_error_sum(uint32_t *square_diff, uint32_t *luma_sse_sum, - int block_height, int block_width, - int ss_x_shift, int ss_y_shift) { +static void compute_luma_sq_error_sum(uint32_t *square_diff, + uint32_t *luma_sse_sum, int block_height, + int block_width, int ss_x_shift, + int ss_y_shift) { for (int i = 0; i < block_height; ++i) { for (int j = 0; j < block_width; ++j) { for (int ii = 0; ii < (1 << ss_y_shift); ++ii) { @@ -1456,7 +1457,7 @@ bool av1_tf_info_alloc(TEMPORAL_FILTER_INFO *tf_info, const AV1_COMP *cpi) { oxcf->frm_dim_cfg.height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL, - NULL, cpi->image_pyramid_levels, 0)) { + NULL, cpi->alloc_pyramid, 0)) { return false; } } diff --git a/third_party/aom/av1/encoder/temporal_filter.h b/third_party/aom/av1/encoder/temporal_filter.h index 6504b91b66..a40fb039b9 100644 --- a/third_party/aom/av1/encoder/temporal_filter.h +++ b/third_party/aom/av1/encoder/temporal_filter.h @@ -14,6 +14,8 @@ #include +#include "aom_util/aom_pthread.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/third_party/aom/av1/encoder/tpl_model.c b/third_party/aom/av1/encoder/tpl_model.c index ca60e4981e..86f5485a26 100644 --- a/third_party/aom/av1/encoder/tpl_model.c +++ b/third_party/aom/av1/encoder/tpl_model.c @@ -19,6 +19,7 @@ #include "config/aom_scale_rtcd.h" #include "aom/aom_codec.h" +#include "aom_util/aom_pthread.h" #include "av1/common/av1_common_int.h" #include "av1/common/enums.h" @@ -193,7 +194,7 @@ void av1_setup_tpl_buffers(AV1_PRIMARY *const ppi, &tpl_data->tpl_rec_pool[frame], width, height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, tpl_data->border_in_pixels, - byte_alignment, 0, alloc_y_plane_only)) + byte_alignment, false, alloc_y_plane_only)) aom_internal_error(&ppi->error, AOM_CODEC_MEM_ERROR, "Failed to allocate frame buffer"); } diff --git a/third_party/aom/av1/encoder/tpl_model.h b/third_party/aom/av1/encoder/tpl_model.h index bcd58216c5..0150c702f9 100644 --- a/third_party/aom/av1/encoder/tpl_model.h +++ b/third_party/aom/av1/encoder/tpl_model.h @@ -30,6 +30,7 @@ struct TPL_INFO; #include "config/aom_config.h" #include "aom_scale/yv12config.h" +#include "aom_util/aom_pthread.h" #include "av1/common/mv.h" #include "av1/common/scale.h" diff --git a/third_party/aom/av1/encoder/tune_butteraugli.c b/third_party/aom/av1/encoder/tune_butteraugli.c index 92fc4b2a92..4381af6a8b 100644 --- a/third_party/aom/av1/encoder/tune_butteraugli.c +++ b/third_party/aom/av1/encoder/tune_butteraugli.c @@ -209,7 +209,7 @@ void av1_setup_butteraugli_source(AV1_COMP *cpi) { if (dst->buffer_alloc_sz == 0) { aom_alloc_frame_buffer( dst, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->features.byte_alignment, 0, 0); + cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, 0); } av1_copy_and_extend_frame(cpi->source, dst); @@ -218,7 +218,7 @@ void av1_setup_butteraugli_source(AV1_COMP *cpi) { aom_alloc_frame_buffer( resized_dst, width / resize_factor, height / resize_factor, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); } if (!av1_resize_and_extend_frame_nonnormative( cpi->source, resized_dst, bit_depth, av1_num_planes(cm))) { @@ -244,7 +244,7 @@ void av1_setup_butteraugli_rdmult_and_restore_source(AV1_COMP *cpi, double K) { aom_alloc_frame_buffer( &resized_recon, width / resize_factor, height / resize_factor, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); copy_img(&cpi->common.cur_frame->buf, &resized_recon, width / resize_factor, height / resize_factor); @@ -267,12 +267,12 @@ void av1_setup_butteraugli_rdmult(AV1_COMP *cpi) { cpi->source = av1_realloc_and_scale_if_required( cm, cpi->unscaled_source, &cpi->scaled_source, cm->features.interp_filter, - 0, false, false, cpi->oxcf.border_in_pixels, cpi->image_pyramid_levels); + 0, false, false, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid); if (cpi->unscaled_last_source != NULL) { cpi->last_source = av1_realloc_and_scale_if_required( cm, cpi->unscaled_last_source, &cpi->scaled_last_source, cm->features.interp_filter, 0, false, false, cpi->oxcf.border_in_pixels, - cpi->image_pyramid_levels); + cpi->alloc_pyramid); } av1_setup_butteraugli_source(cpi); diff --git a/third_party/aom/av1/encoder/tune_vmaf.c b/third_party/aom/av1/encoder/tune_vmaf.c index 4e5ffa387c..91db3db726 100644 --- a/third_party/aom/av1/encoder/tune_vmaf.c +++ b/third_party/aom/av1/encoder/tune_vmaf.c @@ -288,10 +288,10 @@ static AOM_INLINE void gaussian_blur(const int bit_depth, } } -static AOM_INLINE double cal_approx_vmaf(const AV1_COMP *const cpi, - double source_variance, - YV12_BUFFER_CONFIG *const source, - YV12_BUFFER_CONFIG *const sharpened) { +static AOM_INLINE double cal_approx_vmaf( + const AV1_COMP *const cpi, double source_variance, + const YV12_BUFFER_CONFIG *const source, + const YV12_BUFFER_CONFIG *const sharpened) { const int bit_depth = cpi->td.mb.e_mbd.bd; const bool cal_vmaf_neg = cpi->oxcf.tune_cfg.tuning == AOM_TUNE_VMAF_NEG_MAX_GAIN; @@ -305,11 +305,11 @@ static AOM_INLINE double cal_approx_vmaf(const AV1_COMP *const cpi, } static double find_best_frame_unsharp_amount_loop( - const AV1_COMP *const cpi, YV12_BUFFER_CONFIG *const source, - YV12_BUFFER_CONFIG *const blurred, YV12_BUFFER_CONFIG *const sharpened, - double best_vmaf, const double baseline_variance, - const double unsharp_amount_start, const double step_size, - const int max_loop_count, const double max_amount) { + const AV1_COMP *const cpi, const YV12_BUFFER_CONFIG *const source, + const YV12_BUFFER_CONFIG *const blurred, + const YV12_BUFFER_CONFIG *const sharpened, double best_vmaf, + const double baseline_variance, const double unsharp_amount_start, + const double step_size, const int max_loop_count, const double max_amount) { const double min_amount = 0.0; int loop_count = 0; double approx_vmaf = best_vmaf; @@ -328,13 +328,11 @@ static double find_best_frame_unsharp_amount_loop( return AOMMIN(max_amount, AOMMAX(unsharp_amount, min_amount)); } -static double find_best_frame_unsharp_amount(const AV1_COMP *const cpi, - YV12_BUFFER_CONFIG *const source, - YV12_BUFFER_CONFIG *const blurred, - const double unsharp_amount_start, - const double step_size, - const int max_loop_count, - const double max_filter_amount) { +static double find_best_frame_unsharp_amount( + const AV1_COMP *const cpi, const YV12_BUFFER_CONFIG *const source, + const YV12_BUFFER_CONFIG *const blurred, const double unsharp_amount_start, + const double step_size, const int max_loop_count, + const double max_filter_amount) { const AV1_COMMON *const cm = &cpi->common; const int width = source->y_width; const int height = source->y_height; @@ -343,7 +341,7 @@ static double find_best_frame_unsharp_amount(const AV1_COMP *const cpi, aom_alloc_frame_buffer( &sharpened, width, height, source->subsampling_x, source->subsampling_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); const double baseline_variance = frame_average_variance(cpi, source); double unsharp_amount; @@ -376,7 +374,7 @@ static double find_best_frame_unsharp_amount(const AV1_COMP *const cpi, } void av1_vmaf_neg_preprocessing(AV1_COMP *const cpi, - YV12_BUFFER_CONFIG *const source) { + const YV12_BUFFER_CONFIG *const source) { const AV1_COMMON *const cm = &cpi->common; const int bit_depth = cpi->td.mb.e_mbd.bd; const int width = source->y_width; @@ -395,7 +393,7 @@ void av1_vmaf_neg_preprocessing(AV1_COMP *const cpi, aom_alloc_frame_buffer( &blurred, width, height, source->subsampling_x, source->subsampling_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); gaussian_blur(bit_depth, source, &blurred); unsharp(cpi, source, &blurred, source, best_frame_unsharp_amount); @@ -403,7 +401,7 @@ void av1_vmaf_neg_preprocessing(AV1_COMP *const cpi, } void av1_vmaf_frame_preprocessing(AV1_COMP *const cpi, - YV12_BUFFER_CONFIG *const source) { + const YV12_BUFFER_CONFIG *const source) { const AV1_COMMON *const cm = &cpi->common; const int bit_depth = cpi->td.mb.e_mbd.bd; const int width = source->y_width; @@ -415,11 +413,11 @@ void av1_vmaf_frame_preprocessing(AV1_COMP *const cpi, aom_alloc_frame_buffer( &source_extended, width, height, source->subsampling_x, source->subsampling_y, cm->seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->features.byte_alignment, 0, 0); + cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, 0); aom_alloc_frame_buffer( &blurred, width, height, source->subsampling_x, source->subsampling_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); av1_copy_and_extend_frame(source, &source_extended); gaussian_blur(bit_depth, &source_extended, &blurred); @@ -442,7 +440,7 @@ void av1_vmaf_frame_preprocessing(AV1_COMP *const cpi, } void av1_vmaf_blk_preprocessing(AV1_COMP *const cpi, - YV12_BUFFER_CONFIG *const source) { + const YV12_BUFFER_CONFIG *const source) { const AV1_COMMON *const cm = &cpi->common; const int width = source->y_width; const int height = source->y_height; @@ -455,11 +453,11 @@ void av1_vmaf_blk_preprocessing(AV1_COMP *const cpi, memset(&source_extended, 0, sizeof(source_extended)); aom_alloc_frame_buffer( &blurred, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->features.byte_alignment, 0, 0); + cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, 0); aom_alloc_frame_buffer(&source_extended, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); av1_copy_and_extend_frame(source, &source_extended); gaussian_blur(bit_depth, &source_extended, &blurred); @@ -495,11 +493,11 @@ void av1_vmaf_blk_preprocessing(AV1_COMP *const cpi, aom_alloc_frame_buffer(&source_block, block_w, block_h, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); aom_alloc_frame_buffer(&blurred_block, block_w, block_h, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); for (int row = 0; row < num_rows; ++row) { for (int col = 0; col < num_cols; ++col) { @@ -622,7 +620,7 @@ void av1_set_mb_vmaf_rdmult_scaling(AV1_COMP *cpi) { aom_alloc_frame_buffer( &resized_source, y_width / resize_factor, y_height / resize_factor, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); if (!av1_resize_and_extend_frame_nonnormative( cpi->source, &resized_source, bit_depth, av1_num_planes(cm))) { aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, @@ -643,7 +641,7 @@ void av1_set_mb_vmaf_rdmult_scaling(AV1_COMP *cpi) { aom_alloc_frame_buffer(&blurred, resized_y_width, resized_y_height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); gaussian_blur(bit_depth, &resized_source, &blurred); YV12_BUFFER_CONFIG recon; @@ -651,7 +649,7 @@ void av1_set_mb_vmaf_rdmult_scaling(AV1_COMP *cpi) { aom_alloc_frame_buffer(&recon, resized_y_width, resized_y_height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); aom_yv12_copy_frame(&resized_source, &recon, 1); VmafContext *vmaf_context; @@ -830,15 +828,15 @@ static double calc_vmaf_motion_score(const AV1_COMP *const cpi, aom_alloc_frame_buffer(&blurred_cur, y_width, y_height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); aom_alloc_frame_buffer(&blurred_last, y_width, y_height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); aom_alloc_frame_buffer(&blurred_next, y_width, y_height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); gaussian_blur(bit_depth, cur, &blurred_cur); gaussian_blur(bit_depth, last, &blurred_last); @@ -881,8 +879,8 @@ static double calc_vmaf_motion_score(const AV1_COMP *const cpi, } static AOM_INLINE void get_neighbor_frames(const AV1_COMP *const cpi, - YV12_BUFFER_CONFIG **last, - YV12_BUFFER_CONFIG **next) { + const YV12_BUFFER_CONFIG **last, + const YV12_BUFFER_CONFIG **next) { const AV1_COMMON *const cm = &cpi->common; const GF_GROUP *gf_group = &cpi->ppi->gf_group; const int src_index = @@ -920,7 +918,7 @@ int av1_get_vmaf_base_qindex(const AV1_COMP *const cpi, int current_qindex) { if (approx_sse < sse_threshold || approx_dvmaf < vmaf_threshold) { return current_qindex; } - YV12_BUFFER_CONFIG *cur_buf = cpi->source; + const YV12_BUFFER_CONFIG *cur_buf = cpi->source; if (cm->show_frame == 0) { const int src_index = gf_group->arf_src_offset[cpi->gf_frame_index]; struct lookahead_entry *cur_entry = av1_lookahead_peek( @@ -929,7 +927,7 @@ int av1_get_vmaf_base_qindex(const AV1_COMP *const cpi, int current_qindex) { } assert(cur_buf); - YV12_BUFFER_CONFIG *next_buf, *last_buf; + const YV12_BUFFER_CONFIG *next_buf, *last_buf; get_neighbor_frames(cpi, &last_buf, &next_buf); assert(last_buf); @@ -954,8 +952,8 @@ int av1_get_vmaf_base_qindex(const AV1_COMP *const cpi, int current_qindex) { static AOM_INLINE double cal_approx_score( AV1_COMP *const cpi, double src_variance, double new_variance, - double src_score, YV12_BUFFER_CONFIG *const src, - YV12_BUFFER_CONFIG *const recon_sharpened) { + double src_score, const YV12_BUFFER_CONFIG *const src, + const YV12_BUFFER_CONFIG *const recon_sharpened) { double score; const uint32_t bit_depth = cpi->td.mb.e_mbd.bd; const bool cal_vmaf_neg = @@ -967,11 +965,12 @@ static AOM_INLINE double cal_approx_score( static double find_best_frame_unsharp_amount_loop_neg( AV1_COMP *const cpi, double src_variance, double base_score, - YV12_BUFFER_CONFIG *const src, YV12_BUFFER_CONFIG *const recon, - YV12_BUFFER_CONFIG *const ref, YV12_BUFFER_CONFIG *const src_blurred, - YV12_BUFFER_CONFIG *const recon_blurred, - YV12_BUFFER_CONFIG *const src_sharpened, - YV12_BUFFER_CONFIG *const recon_sharpened, FULLPEL_MV *mvs, + const YV12_BUFFER_CONFIG *const src, const YV12_BUFFER_CONFIG *const recon, + const YV12_BUFFER_CONFIG *const ref, + const YV12_BUFFER_CONFIG *const src_blurred, + const YV12_BUFFER_CONFIG *const recon_blurred, + const YV12_BUFFER_CONFIG *const src_sharpened, + const YV12_BUFFER_CONFIG *const recon_sharpened, FULLPEL_MV *mvs, double best_score, const double unsharp_amount_start, const double step_size, const int max_loop_count, const double max_amount) { const double min_amount = 0.0; @@ -999,8 +998,8 @@ static double find_best_frame_unsharp_amount_loop_neg( } static double find_best_frame_unsharp_amount_neg( - AV1_COMP *const cpi, YV12_BUFFER_CONFIG *const src, - YV12_BUFFER_CONFIG *const recon, YV12_BUFFER_CONFIG *const ref, + AV1_COMP *const cpi, const YV12_BUFFER_CONFIG *const src, + const YV12_BUFFER_CONFIG *const recon, const YV12_BUFFER_CONFIG *const ref, double base_score, const double unsharp_amount_start, const double step_size, const int max_loop_count, const double max_filter_amount) { @@ -1023,18 +1022,18 @@ static double find_best_frame_unsharp_amount_neg( aom_alloc_frame_buffer(&recon_sharpened, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); aom_alloc_frame_buffer(&src_sharpened, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); aom_alloc_frame_buffer(&recon_blurred, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->features.byte_alignment, 0, 0); + cm->features.byte_alignment, false, 0); aom_alloc_frame_buffer( &src_blurred, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->features.byte_alignment, 0, 0); + cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, 0); gaussian_blur(bit_depth, recon, &recon_blurred); gaussian_blur(bit_depth, src, &src_blurred); @@ -1076,8 +1075,8 @@ static double find_best_frame_unsharp_amount_neg( } void av1_update_vmaf_curve(AV1_COMP *cpi) { - YV12_BUFFER_CONFIG *source = cpi->source; - YV12_BUFFER_CONFIG *recon = &cpi->common.cur_frame->buf; + const YV12_BUFFER_CONFIG *source = cpi->source; + const YV12_BUFFER_CONFIG *recon = &cpi->common.cur_frame->buf; const int bit_depth = cpi->td.mb.e_mbd.bd; const GF_GROUP *const gf_group = &cpi->ppi->gf_group; const int layer_depth = @@ -1099,7 +1098,7 @@ void av1_update_vmaf_curve(AV1_COMP *cpi) { } if (cpi->oxcf.tune_cfg.tuning == AOM_TUNE_VMAF_NEG_MAX_GAIN) { - YV12_BUFFER_CONFIG *last, *next; + const YV12_BUFFER_CONFIG *last, *next; get_neighbor_frames(cpi, &last, &next); double best_unsharp_amount_start = get_layer_value(cpi->vmaf_info.last_frame_unsharp_amount, layer_depth); diff --git a/third_party/aom/av1/encoder/tune_vmaf.h b/third_party/aom/av1/encoder/tune_vmaf.h index a04a29e6fe..404fd1029a 100644 --- a/third_party/aom/av1/encoder/tune_vmaf.h +++ b/third_party/aom/av1/encoder/tune_vmaf.h @@ -43,13 +43,13 @@ typedef struct { struct AV1_COMP; void av1_vmaf_blk_preprocessing(struct AV1_COMP *cpi, - YV12_BUFFER_CONFIG *source); + const YV12_BUFFER_CONFIG *source); void av1_vmaf_frame_preprocessing(struct AV1_COMP *cpi, - YV12_BUFFER_CONFIG *source); + const YV12_BUFFER_CONFIG *source); void av1_vmaf_neg_preprocessing(struct AV1_COMP *cpi, - YV12_BUFFER_CONFIG *source); + const YV12_BUFFER_CONFIG *source); void av1_set_mb_vmaf_rdmult_scaling(struct AV1_COMP *cpi); diff --git a/third_party/aom/av1/encoder/tx_search.c b/third_party/aom/av1/encoder/tx_search.c index 7292c01191..5dcc08c0ff 100644 --- a/third_party/aom/av1/encoder/tx_search.c +++ b/third_party/aom/av1/encoder/tx_search.c @@ -1109,13 +1109,11 @@ static INLINE void dist_block_tx_domain(MACROBLOCK *x, int plane, int block, *out_sse = RIGHT_SIGNED_SHIFT(this_sse, shift); } -uint16_t prune_txk_type_separ(const AV1_COMP *cpi, MACROBLOCK *x, int plane, - int block, TX_SIZE tx_size, int blk_row, - int blk_col, BLOCK_SIZE plane_bsize, int *txk_map, - int16_t allowed_tx_mask, int prune_factor, - const TXB_CTX *const txb_ctx, - int reduced_tx_set_used, int64_t ref_best_rd, - int num_sel) { +static uint16_t prune_txk_type_separ( + const AV1_COMP *cpi, MACROBLOCK *x, int plane, int block, TX_SIZE tx_size, + int blk_row, int blk_col, BLOCK_SIZE plane_bsize, int *txk_map, + int16_t allowed_tx_mask, int prune_factor, const TXB_CTX *const txb_ctx, + int reduced_tx_set_used, int64_t ref_best_rd, int num_sel) { const AV1_COMMON *cm = &cpi->common; MACROBLOCKD *xd = &x->e_mbd; @@ -1255,11 +1253,12 @@ uint16_t prune_txk_type_separ(const AV1_COMP *cpi, MACROBLOCK *x, int plane, return prune; } -uint16_t prune_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, - int block, TX_SIZE tx_size, int blk_row, int blk_col, - BLOCK_SIZE plane_bsize, int *txk_map, - uint16_t allowed_tx_mask, int prune_factor, - const TXB_CTX *const txb_ctx, int reduced_tx_set_used) { +static uint16_t prune_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, + int block, TX_SIZE tx_size, int blk_row, + int blk_col, BLOCK_SIZE plane_bsize, + int *txk_map, uint16_t allowed_tx_mask, + int prune_factor, const TXB_CTX *const txb_ctx, + int reduced_tx_set_used) { const AV1_COMMON *cm = &cpi->common; MACROBLOCKD *xd = &x->e_mbd; int tx_type; diff --git a/third_party/aom/av1/encoder/x86/av1_fwd_txfm_sse2.c b/third_party/aom/av1/encoder/x86/av1_fwd_txfm_sse2.c index a4def754b0..31cc37db7a 100644 --- a/third_party/aom/av1/encoder/x86/av1_fwd_txfm_sse2.c +++ b/third_party/aom/av1/encoder/x86/av1_fwd_txfm_sse2.c @@ -2638,6 +2638,11 @@ void av1_lowbd_fwd_txfm2d_16x64_sse2(const int16_t *input, int32_t *output, } } +// Include top-level function only for 32-bit x86, to support Valgrind. +// For normal use, we require SSE4.1, so av1_lowbd_fwd_txfm_sse4_1 will be used +// instead of this function. However, 32-bit Valgrind does not support SSE4.1, +// so we include a fallback to SSE2 to improve performance +#if AOM_ARCH_X86 static FwdTxfm2dFunc fwd_txfm2d_func_ls[TX_SIZES_ALL] = { av1_lowbd_fwd_txfm2d_4x4_sse2, // 4x4 transform av1_lowbd_fwd_txfm2d_8x8_sse2, // 8x8 transform @@ -2671,3 +2676,4 @@ void av1_lowbd_fwd_txfm_sse2(const int16_t *src_diff, tran_low_t *coeff, fwd_txfm2d_func(src_diff, coeff, diff_stride, txfm_param->tx_type, txfm_param->bd); } +#endif // AOM_ARCH_X86 diff --git a/third_party/aom/av1/encoder/x86/cnn_avx2.c b/third_party/aom/av1/encoder/x86/cnn_avx2.c index ee93b3d5a0..9c26a56641 100644 --- a/third_party/aom/av1/encoder/x86/cnn_avx2.c +++ b/third_party/aom/av1/encoder/x86/cnn_avx2.c @@ -466,7 +466,7 @@ static INLINE void cnn_convolve_no_maxpool_padding_valid_layer2_avx2( // As per the layer config set by av1_intra_mode_cnn_partition_cnn_config, // the filter_width and filter_height are equal to 2 for layer >= 1. So // convolution happens at 2x2 for layer >= 1. -void cnn_convolve_no_maxpool_padding_valid_2x2_avx2( +static void cnn_convolve_no_maxpool_padding_valid_2x2_avx2( const float **input, int in_width, int in_height, int in_stride, const CNN_LAYER_CONFIG *const layer_config, float **output, int out_stride, int start_idx, const int cstep, const int channel_step) { diff --git a/third_party/aom/build/cmake/aom_config_defaults.cmake b/third_party/aom/build/cmake/aom_config_defaults.cmake index da7de4b0f4..980dfb9327 100644 --- a/third_party/aom/build/cmake/aom_config_defaults.cmake +++ b/third_party/aom/build/cmake/aom_config_defaults.cmake @@ -37,6 +37,7 @@ set_aom_detect_var(HAVE_NEON_DOTPROD 0 set_aom_detect_var(HAVE_NEON_I8MM 0 "Enables Armv8.2-A Neon i8mm intrinsics optimizations.") set_aom_detect_var(HAVE_SVE 0 "Enables Armv8.2-A SVE intrinsics optimizations.") +set_aom_detect_var(HAVE_SVE2 0 "Enables Armv9-A SVE2 intrinsics optimizations.") # PPC feature flags. set_aom_detect_var(HAVE_VSX 0 "Enables VSX optimizations.") @@ -84,6 +85,9 @@ set_aom_config_var(CONFIG_AV1_TEMPORAL_DENOISING 0 set_aom_config_var(CONFIG_MULTITHREAD 1 "Multithread support.") set_aom_config_var(CONFIG_OS_SUPPORT 0 "Internal flag.") set_aom_config_var(CONFIG_PIC 0 "Build with PIC enabled.") +set_aom_config_var(CONFIG_QUANT_MATRIX 1 + "Build with quantization matrices for AV1 encoder." + "AV1 decoder is always built with quantization matrices.") set_aom_config_var(CONFIG_REALTIME_ONLY 0 "Build for RTC-only. See aomcx.h for all disabled features.") set_aom_config_var(CONFIG_RUNTIME_CPU_DETECT 1 "Runtime CPU detection support.") @@ -209,6 +213,8 @@ set_aom_option_var( "Enables Armv8.2-A Neon i8mm optimizations on AArch64 targets." ON) set_aom_option_var(ENABLE_SVE "Enables Armv8.2-A SVE optimizations on AArch64 targets." ON) +set_aom_option_var(ENABLE_SVE2 + "Enables Armv9-A SVE2 optimizations on AArch64 targets." ON) # VSX intrinsics flags. set_aom_option_var(ENABLE_VSX "Enables VSX optimizations on PowerPC targets." diff --git a/third_party/aom/build/cmake/aom_configure.cmake b/third_party/aom/build/cmake/aom_configure.cmake index 917e7cac5d..304d90d1e1 100644 --- a/third_party/aom/build/cmake/aom_configure.cmake +++ b/third_party/aom/build/cmake/aom_configure.cmake @@ -320,6 +320,10 @@ else() # minimum supported C++ version. If Clang is using this Standard Library # implementation, it cannot target C++11. require_cxx_flag_nomsvc("-std=c++14" YES) + elseif(CYGWIN AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # The GNU C++ compiler in Cygwin needs the -std=gnu++11 flag to make the + # POSIX function declarations visible in the Standard C Library headers. + require_cxx_flag_nomsvc("-std=gnu++11" YES) else() require_cxx_flag_nomsvc("-std=c++11" YES) endif() @@ -393,6 +397,13 @@ else() endif() add_compiler_flag_if_supported("-D_LARGEFILE_SOURCE") add_compiler_flag_if_supported("-D_FILE_OFFSET_BITS=64") + + # Do not allow implicit vector type conversions on Clang builds (this is + # already the default on GCC builds). + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + # Clang 8.0.1 (in Cygwin) doesn't support -flax-vector-conversions=none. + add_compiler_flag_if_supported("-flax-vector-conversions=none") + endif() endif() # Prior to r23, or with ANDROID_USE_LEGACY_TOOLCHAIN_FILE set, diff --git a/third_party/aom/build/cmake/compiler_flags.cmake b/third_party/aom/build/cmake/compiler_flags.cmake index f008b964f5..3afcd50b5c 100644 --- a/third_party/aom/build/cmake/compiler_flags.cmake +++ b/third_party/aom/build/cmake/compiler_flags.cmake @@ -176,11 +176,11 @@ function(require_cxx_flag cxx_flag update_cxx_flags) endif() unset(HAVE_CXX_FLAG CACHE) - message("Checking C compiler flag support for: " ${cxx_flag}) + message("Checking C++ compiler flag support for: " ${cxx_flag}) check_cxx_compiler_flag("${cxx_flag}" HAVE_CXX_FLAG) if(NOT HAVE_CXX_FLAG) message( - FATAL_ERROR "${PROJECT_NAME} requires support for C flag: ${cxx_flag}.") + FATAL_ERROR "${PROJECT_NAME} requires support for C++ flag: ${cxx_flag}.") endif() if(NOT "${AOM_EXE_LINKER_FLAGS}" STREQUAL "") diff --git a/third_party/aom/build/cmake/cpu.cmake b/third_party/aom/build/cmake/cpu.cmake index a9b7a67070..489dbcbf44 100644 --- a/third_party/aom/build/cmake/cpu.cmake +++ b/third_party/aom/build/cmake/cpu.cmake @@ -14,11 +14,12 @@ if("${AOM_TARGET_CPU}" STREQUAL "arm64") set(AOM_ARCH_AARCH64 1) set(RTCD_ARCH_ARM "yes") - set(ARM64_FLAVORS "NEON;ARM_CRC32;NEON_DOTPROD;NEON_I8MM;SVE") + set(ARM64_FLAVORS "NEON;ARM_CRC32;NEON_DOTPROD;NEON_I8MM;SVE;SVE2") set(AOM_ARM_CRC32_DEFAULT_FLAG "-march=armv8-a+crc") set(AOM_NEON_DOTPROD_DEFAULT_FLAG "-march=armv8.2-a+dotprod") set(AOM_NEON_I8MM_DEFAULT_FLAG "-march=armv8.2-a+dotprod+i8mm") set(AOM_SVE_DEFAULT_FLAG "-march=armv8.2-a+dotprod+i8mm+sve") + set(AOM_SVE2_DEFAULT_FLAG "-march=armv9-a+sve2") # SVE2 is a v9-only feature # Check that the compiler flag to enable each flavor is supported by the # compiler. This may not be the case for new architecture features on old @@ -26,16 +27,27 @@ if("${AOM_TARGET_CPU}" STREQUAL "arm64") foreach(flavor ${ARM64_FLAVORS}) if(ENABLE_${flavor} AND NOT DEFINED AOM_${flavor}_FLAG) set(AOM_${flavor}_FLAG "${AOM_${flavor}_DEFAULT_FLAG}") + string(TOLOWER "${flavor}" flavor_lower) + + # Do not use check_c_compiler_flag here since the regex used to match + # against stderr does not recognise the "invalid feature modifier" error + # produced by certain versions of GCC, leading to the feature being + # incorrectly marked as available. + set(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${AOM_${flavor}_FLAG}") unset(FLAG_SUPPORTED) - check_c_compiler_flag("${AOM_${flavor}_FLAG}" FLAG_SUPPORTED) + aom_check_source_compiles("arm_feature_flag_${flavor_lower}_available" + "static void function(void) {}" FLAG_SUPPORTED) + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS}) + if(NOT ${FLAG_SUPPORTED}) set(ENABLE_${flavor} 0) endif() endif() endforeach() - # SVE requires that the Neon-SVE bridge header is also available. - if(ENABLE_SVE) + # SVE and SVE2 require that the Neon-SVE bridge header is also available. + if(ENABLE_SVE OR ENABLE_SVE2) set(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS}) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${AOM_SVE_FLAG}") aom_check_source_compiles("arm_neon_sve_bridge_available" " @@ -47,6 +59,7 @@ if("${AOM_TARGET_CPU}" STREQUAL "arm64") set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS}) if(HAVE_SVE_HEADERS EQUAL 0) set(ENABLE_SVE 0) + set(ENABLE_SVE2 0) endif() endif() diff --git a/third_party/aom/build/cmake/rtcd.pl b/third_party/aom/build/cmake/rtcd.pl index 1cf52f076c..f4a70842d0 100755 --- a/third_party/aom/build/cmake/rtcd.pl +++ b/third_party/aom/build/cmake/rtcd.pl @@ -392,7 +392,7 @@ if ($opts{arch} eq 'x86') { @ALL_ARCHS = filter(qw/neon/); arm; } elsif ($opts{arch} eq 'arm64' ) { - @ALL_ARCHS = filter(qw/neon arm_crc32 neon_dotprod neon_i8mm sve/); + @ALL_ARCHS = filter(qw/neon arm_crc32 neon_dotprod neon_i8mm sve sve2/); @REQUIRES = filter(qw/neon/); &require(@REQUIRES); arm; diff --git a/third_party/aom/doc/dev_guide/av1_encoder.dox b/third_party/aom/doc/dev_guide/av1_encoder.dox index 0f7e8f87e2..a40b58933b 100644 --- a/third_party/aom/doc/dev_guide/av1_encoder.dox +++ b/third_party/aom/doc/dev_guide/av1_encoder.dox @@ -1313,6 +1313,34 @@ Related functions: All the related functions are listed in \ref coefficient_coding. +\section architecture_simd SIMD usage + +In order to efficiently encode video on modern platforms, it is necessary to +implement optimized versions of many core encoding and decoding functions using +architecture-specific SIMD instructions. + +Functions which have optimized implementations will have multiple variants +in the code, each suffixed with the name of the appropriate instruction set. +There will additionally be an `_c` version, which acts as a reference +implementation which the SIMD variants can be tested against. + +As different machines with the same nominal architecture may support different +subsets of SIMD instructions, we have dynamic CPU detection logic which chooses +the appropriate functions to use at run time. This process is handled by +`build/cmake/rtcd.pl`, with function definitions in the files +`*_rtcd_defs.pl` elsewhere in the codebase. + +Currently SIMD is supported on the following platforms: + +- x86: Requires SSE4.1 or above + +- Arm: Requires Neon (Armv7-A and above) + +We aim to provide implementations of all performance-critical functions which +are compatible with the instruction sets listed above. Additional SIMD +extensions (e.g. AVX on x86, SVE on Arm) are also used to provide even +greater performance where available. + */ /*!\defgroup encoder_algo Encoder Algorithm diff --git a/third_party/aom/examples/av1_dec_fuzzer.cc b/third_party/aom/examples/av1_dec_fuzzer.cc index 9b9a0b9cb6..e9388b7062 100644 --- a/third_party/aom/examples/av1_dec_fuzzer.cc +++ b/third_party/aom/examples/av1_dec_fuzzer.cc @@ -34,6 +34,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { return 0; } + // Abusing the four unused bytes at the end of the IVF file header as a source + // of random bits. + unsigned int tile_mode = (data[IVF_FILE_HDR_SZ - 1] & 2) != 0; + unsigned int ext_tile_debug = (data[IVF_FILE_HDR_SZ - 1] & 4) != 0; + unsigned int is_annexb = (data[IVF_FILE_HDR_SZ - 1] & 8) != 0; + int output_all_layers = (data[IVF_FILE_HDR_SZ - 1] & 0x10) != 0; + int operating_point = data[IVF_FILE_HDR_SZ - 2] & 0x1F; + aom_codec_iface_t *codec_interface = aom_codec_av1_dx(); aom_codec_ctx_t codec; // Set thread count in the range [1, 64]. @@ -42,6 +50,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (aom_codec_dec_init(&codec, codec_interface, &cfg, 0)) { return 0; } + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_TILE_MODE, tile_mode); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_EXT_TILE_DEBUG, ext_tile_debug); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_SET_IS_ANNEXB, is_annexb); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_SET_OUTPUT_ALL_LAYERS, + output_all_layers); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_SET_OPERATING_POINT, + operating_point); data += IVF_FILE_HDR_SZ; size -= IVF_FILE_HDR_SZ; diff --git a/third_party/aom/examples/svc_encoder_rtc.cc b/third_party/aom/examples/svc_encoder_rtc.cc index 2c041081e5..c751e9868c 100644 --- a/third_party/aom/examples/svc_encoder_rtc.cc +++ b/third_party/aom/examples/svc_encoder_rtc.cc @@ -1442,6 +1442,35 @@ static int qindex_to_quantizer(int qindex) { return 63; } +static void set_active_map(const aom_codec_enc_cfg_t *cfg, + aom_codec_ctx_t *codec, int frame_cnt) { + aom_active_map_t map = { 0, 0, 0 }; + + map.rows = (cfg->g_h + 15) / 16; + map.cols = (cfg->g_w + 15) / 16; + + map.active_map = (uint8_t *)malloc(map.rows * map.cols); + if (!map.active_map) die("Failed to allocate active map"); + + // Example map for testing. + for (unsigned int i = 0; i < map.rows; ++i) { + for (unsigned int j = 0; j < map.cols; ++j) { + int index = map.cols * i + j; + map.active_map[index] = 1; + if (frame_cnt < 300) { + if (i < map.rows / 2 && j < map.cols / 2) map.active_map[index] = 0; + } else if (frame_cnt >= 300) { + if (i < map.rows / 2 && j >= map.cols / 2) map.active_map[index] = 0; + } + } + } + + if (aom_codec_control(codec, AOME_SET_ACTIVEMAP, &map)) + die_codec(codec, "Failed to set active map"); + + free(map.active_map); +} + int main(int argc, const char **argv) { AppInput app_input; AvxVideoWriter *outfile[AOM_MAX_LAYERS] = { NULL }; @@ -1494,6 +1523,9 @@ int main(int argc, const char **argv) { // Flag to test setting speed per layer. const int test_speed_per_layer = 0; + // Flag for testing active maps. + const int test_active_maps = 0; + /* Setup default input stream settings */ app_input.input_ctx.framerate.numerator = 30; app_input.input_ctx.framerate.denominator = 1; @@ -1874,6 +1906,8 @@ int main(int argc, const char **argv) { } } + if (test_active_maps) set_active_map(&cfg, &codec, frame_cnt); + // Do the layer encode. aom_usec_timer_start(&timer); if (aom_codec_encode(&codec, frame_avail ? &raw : NULL, pts, 1, flags)) diff --git a/third_party/aom/libs.doxy_template b/third_party/aom/libs.doxy_template index ba77751a50..01da81ac0c 100644 --- a/third_party/aom/libs.doxy_template +++ b/third_party/aom/libs.doxy_template @@ -1219,15 +1219,6 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via Javascript. If disabled, the navigation index will @@ -1509,17 +1500,6 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX @@ -1820,14 +1800,6 @@ LATEX_HIDE_INDICES = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2167,23 +2139,6 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_FONTNAME = Helvetica - -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_FONTSIZE = 10 - # By default doxygen will tell dot to use the default font as specified with # DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # the path where dot can find it using this tag. @@ -2401,18 +2356,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support diff --git a/third_party/aom/test/active_map_test.cc b/third_party/aom/test/active_map_test.cc index 979ee6b8b3..de16541281 100644 --- a/third_party/aom/test/active_map_test.cc +++ b/third_party/aom/test/active_map_test.cc @@ -19,8 +19,10 @@ namespace { +// Params: test mode, speed, aq_mode and screen_content mode. class ActiveMapTest - : public ::libaom_test::CodecTestWith2Params, + : public ::libaom_test::CodecTestWith4Params, public ::libaom_test::EncoderTest { protected: static const int kWidth = 208; @@ -32,6 +34,8 @@ class ActiveMapTest void SetUp() override { InitializeConfig(GET_PARAM(1)); cpu_used_ = GET_PARAM(2); + aq_mode_ = GET_PARAM(3); + screen_mode_ = GET_PARAM(4); } void PreEncodeFrameHook(::libaom_test::VideoSource *video, @@ -41,6 +45,9 @@ class ActiveMapTest encoder->Control(AV1E_SET_ALLOW_WARPED_MOTION, 0); encoder->Control(AV1E_SET_ENABLE_GLOBAL_MOTION, 0); encoder->Control(AV1E_SET_ENABLE_OBMC, 0); + encoder->Control(AV1E_SET_AQ_MODE, aq_mode_); + encoder->Control(AV1E_SET_TUNE_CONTENT, screen_mode_); + if (screen_mode_) encoder->Control(AV1E_SET_ENABLE_PALETTE, 1); } else if (video->frame() == 3) { aom_active_map_t map = aom_active_map_t(); /* clang-format off */ @@ -79,19 +86,22 @@ class ActiveMapTest cfg_.g_pass = AOM_RC_ONE_PASS; cfg_.rc_end_usage = AOM_CBR; cfg_.kf_max_dist = 90000; - ::libaom_test::I420VideoSource video("hantro_odd.yuv", kWidth, kHeight, 30, - 1, 0, 20); + ::libaom_test::I420VideoSource video("hantro_odd.yuv", kWidth, kHeight, 100, + 1, 0, 100); ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); } int cpu_used_; + int aq_mode_; + int screen_mode_; }; TEST_P(ActiveMapTest, Test) { DoTest(); } AV1_INSTANTIATE_TEST_SUITE(ActiveMapTest, ::testing::Values(::libaom_test::kRealTime), - ::testing::Range(5, 9)); + ::testing::Range(5, 12), ::testing::Values(0, 3), + ::testing::Values(0, 1)); } // namespace diff --git a/third_party/aom/test/aom_image_test.cc b/third_party/aom/test/aom_image_test.cc index ad48e73e3d..03f4373f35 100644 --- a/third_party/aom/test/aom_image_test.cc +++ b/third_party/aom/test/aom_image_test.cc @@ -47,6 +47,16 @@ TEST(AomImageTest, AomImgSetRectOverflow) { 0); } +TEST(AomImageTest, AomImgAllocNone) { + const int kWidth = 128; + const int kHeight = 128; + + aom_image_t img; + aom_img_fmt_t format = AOM_IMG_FMT_NONE; + unsigned int align = 32; + ASSERT_EQ(aom_img_alloc(&img, format, kWidth, kHeight, align), nullptr); +} + TEST(AomImageTest, AomImgAllocNv12) { const int kWidth = 128; const int kHeight = 128; @@ -54,7 +64,7 @@ TEST(AomImageTest, AomImgAllocNv12) { aom_image_t img; aom_img_fmt_t format = AOM_IMG_FMT_NV12; unsigned int align = 32; - EXPECT_NE(aom_img_alloc(&img, format, kWidth, kHeight, align), nullptr); + EXPECT_EQ(aom_img_alloc(&img, format, kWidth, kHeight, align), &img); EXPECT_EQ(img.stride[AOM_PLANE_U], img.stride[AOM_PLANE_Y]); EXPECT_EQ(img.stride[AOM_PLANE_V], 0); EXPECT_EQ(img.planes[AOM_PLANE_V], nullptr); diff --git a/third_party/aom/test/av1_convolve_test.cc b/third_party/aom/test/av1_convolve_test.cc index 5bbac21803..b2392276cc 100644 --- a/third_party/aom/test/av1_convolve_test.cc +++ b/third_party/aom/test/av1_convolve_test.cc @@ -631,6 +631,11 @@ INSTANTIATE_TEST_SUITE_P(NEON, AV1ConvolveXHighbdTest, BuildHighbdParams(av1_highbd_convolve_x_sr_neon)); #endif +#if HAVE_SVE2 +INSTANTIATE_TEST_SUITE_P(SVE2, AV1ConvolveXHighbdTest, + BuildHighbdParams(av1_highbd_convolve_x_sr_sve2)); +#endif + ///////////////////////////////////////////////////////////////// // Single reference convolve-x IntraBC functions (high bit-depth) ///////////////////////////////////////////////////////////////// @@ -998,6 +1003,11 @@ INSTANTIATE_TEST_SUITE_P(NEON, AV1ConvolveYHighbdTest, BuildHighbdParams(av1_highbd_convolve_y_sr_neon)); #endif +#if HAVE_SVE2 +INSTANTIATE_TEST_SUITE_P(SVE2, AV1ConvolveYHighbdTest, + BuildHighbdParams(av1_highbd_convolve_y_sr_sve2)); +#endif + ///////////////////////////////////////////////////////////////// // Single reference convolve-y IntraBC functions (high bit-depth) ///////////////////////////////////////////////////////////////// @@ -1523,6 +1533,11 @@ INSTANTIATE_TEST_SUITE_P(NEON, AV1Convolve2DHighbdTest, BuildHighbdParams(av1_highbd_convolve_2d_sr_neon)); #endif +#if HAVE_SVE2 +INSTANTIATE_TEST_SUITE_P(SVE2, AV1Convolve2DHighbdTest, + BuildHighbdParams(av1_highbd_convolve_2d_sr_sve2)); +#endif + ////////////////////////////////////////////////////////////////// // Single reference convolve-2d IntraBC functions (high bit-depth) ////////////////////////////////////////////////////////////////// @@ -1943,6 +1958,12 @@ INSTANTIATE_TEST_SUITE_P( BuildHighbdLumaParams(av1_highbd_dist_wtd_convolve_x_neon)); #endif +#if HAVE_SVE2 +INSTANTIATE_TEST_SUITE_P( + SVE2, AV1ConvolveXHighbdCompoundTest, + BuildHighbdLumaParams(av1_highbd_dist_wtd_convolve_x_sve2)); +#endif + #endif // CONFIG_AV1_HIGHBITDEPTH //////////////////////////////////////////////// @@ -2023,6 +2044,12 @@ INSTANTIATE_TEST_SUITE_P( BuildHighbdLumaParams(av1_highbd_dist_wtd_convolve_y_neon)); #endif +#if HAVE_SVE2 +INSTANTIATE_TEST_SUITE_P( + SVE2, AV1ConvolveYHighbdCompoundTest, + BuildHighbdLumaParams(av1_highbd_dist_wtd_convolve_y_sve2)); +#endif + #endif // CONFIG_AV1_HIGHBITDEPTH ////////////////////////////////////////////////////// @@ -2312,11 +2339,6 @@ TEST_P(AV1Convolve2DCompoundTest, RunTest) { RunTest(); } INSTANTIATE_TEST_SUITE_P(C, AV1Convolve2DCompoundTest, BuildLowbdLumaParams(av1_dist_wtd_convolve_2d_c)); -#if HAVE_SSE2 -INSTANTIATE_TEST_SUITE_P(SSE2, AV1Convolve2DCompoundTest, - BuildLowbdLumaParams(av1_dist_wtd_convolve_2d_sse2)); -#endif - #if HAVE_SSSE3 INSTANTIATE_TEST_SUITE_P(SSSE3, AV1Convolve2DCompoundTest, BuildLowbdLumaParams(av1_dist_wtd_convolve_2d_ssse3)); @@ -2442,6 +2464,12 @@ INSTANTIATE_TEST_SUITE_P( BuildHighbdLumaParams(av1_highbd_dist_wtd_convolve_2d_neon)); #endif +#if HAVE_SVE2 +INSTANTIATE_TEST_SUITE_P( + SVE2, AV1Convolve2DHighbdCompoundTest, + BuildHighbdLumaParams(av1_highbd_dist_wtd_convolve_2d_sve2)); +#endif + #endif // CONFIG_AV1_HIGHBITDEPTH } // namespace diff --git a/third_party/aom/test/av1_fwd_txfm2d_test.cc b/third_party/aom/test/av1_fwd_txfm2d_test.cc index 2ed5d94db3..4a5a634545 100644 --- a/third_party/aom/test/av1_fwd_txfm2d_test.cc +++ b/third_party/aom/test/av1_fwd_txfm2d_test.cc @@ -443,7 +443,7 @@ using ::testing::Combine; using ::testing::Values; using ::testing::ValuesIn; -#if HAVE_SSE2 +#if AOM_ARCH_X86 && HAVE_SSE2 static TX_SIZE fwd_txfm_for_sse2[] = { TX_4X4, TX_8X8, @@ -469,15 +469,14 @@ static TX_SIZE fwd_txfm_for_sse2[] = { INSTANTIATE_TEST_SUITE_P(SSE2, AV1FwdTxfm2dTest, Combine(ValuesIn(fwd_txfm_for_sse2), Values(av1_lowbd_fwd_txfm_sse2))); -#endif // HAVE_SSE2 +#endif // AOM_ARCH_X86 && HAVE_SSE2 #if HAVE_SSE4_1 -static TX_SIZE fwd_txfm_for_sse41[] = { - TX_4X4, - TX_64X64, - TX_32X64, - TX_64X32, -}; +static TX_SIZE fwd_txfm_for_sse41[] = { TX_4X4, TX_8X8, TX_16X16, TX_32X32, + TX_64X64, TX_4X8, TX_8X4, TX_8X16, + TX_16X8, TX_16X32, TX_32X16, TX_32X64, + TX_64X32, TX_4X16, TX_16X4, TX_8X32, + TX_32X8, TX_16X64, TX_64X16 }; INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1FwdTxfm2dTest, Combine(ValuesIn(fwd_txfm_for_sse41), diff --git a/third_party/aom/test/av1_wedge_utils_test.cc b/third_party/aom/test/av1_wedge_utils_test.cc index 1055ff35b2..2234561b7d 100644 --- a/third_party/aom/test/av1_wedge_utils_test.cc +++ b/third_party/aom/test/av1_wedge_utils_test.cc @@ -408,4 +408,16 @@ INSTANTIATE_TEST_SUITE_P( av1_wedge_compute_delta_squares_avx2))); #endif // HAVE_AVX2 +#if HAVE_SVE +INSTANTIATE_TEST_SUITE_P( + SVE, WedgeUtilsSSEOptTest, + ::testing::Values(TestFuncsFSSE(av1_wedge_sse_from_residuals_c, + av1_wedge_sse_from_residuals_sve))); + +INSTANTIATE_TEST_SUITE_P( + SVE, WedgeUtilsSignOptTest, + ::testing::Values(TestFuncsFSign(av1_wedge_sign_from_residuals_c, + av1_wedge_sign_from_residuals_sve))); +#endif // HAVE_SVE + } // namespace diff --git a/third_party/aom/test/cdef_test.cc b/third_party/aom/test/cdef_test.cc index ad54407ca7..ac0591f6a8 100644 --- a/third_party/aom/test/cdef_test.cc +++ b/third_party/aom/test/cdef_test.cc @@ -614,7 +614,7 @@ TEST_P(CDEFCopyRect16to16Test, TestSIMDNoMismatch) { using std::make_tuple; -#if (HAVE_SSE2 || HAVE_SSSE3 || HAVE_SSE4_1 || HAVE_AVX2 || HAVE_NEON) +#if ((AOM_ARCH_X86 && HAVE_SSSE3) || HAVE_SSE4_1 || HAVE_AVX2 || HAVE_NEON) static const CdefFilterBlockFunctions kCdefFilterFuncC[] = { { &cdef_filter_8_0_c, &cdef_filter_8_1_c, &cdef_filter_8_2_c, &cdef_filter_8_3_c } @@ -626,50 +626,7 @@ static const CdefFilterBlockFunctions kCdefFilterHighbdFuncC[] = { }; #endif -#if HAVE_SSE2 -static const CdefFilterBlockFunctions kCdefFilterFuncSse2[] = { - { &cdef_filter_8_0_sse2, &cdef_filter_8_1_sse2, &cdef_filter_8_2_sse2, - &cdef_filter_8_3_sse2 } -}; - -static const CdefFilterBlockFunctions kCdefFilterHighbdFuncSse2[] = { - { &cdef_filter_16_0_sse2, &cdef_filter_16_1_sse2, &cdef_filter_16_2_sse2, - &cdef_filter_16_3_sse2 } -}; - -INSTANTIATE_TEST_SUITE_P( - SSE2, CDEFBlockTest, - ::testing::Combine(::testing::ValuesIn(kCdefFilterFuncSse2), - ::testing::ValuesIn(kCdefFilterFuncC), - ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, - BLOCK_8X8), - ::testing::Range(0, 16), ::testing::Values(8))); -INSTANTIATE_TEST_SUITE_P( - SSE2, CDEFBlockHighbdTest, - ::testing::Combine(::testing::ValuesIn(kCdefFilterHighbdFuncSse2), - ::testing::ValuesIn(kCdefFilterHighbdFuncC), - ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, - BLOCK_8X8), - ::testing::Range(0, 16), ::testing::Range(10, 13, 2))); -INSTANTIATE_TEST_SUITE_P(SSE2, CDEFFindDirTest, - ::testing::Values(make_tuple(&cdef_find_dir_sse2, - &cdef_find_dir_c))); -INSTANTIATE_TEST_SUITE_P(SSE2, CDEFFindDirDualTest, - ::testing::Values(make_tuple(&cdef_find_dir_dual_sse2, - &cdef_find_dir_dual_c))); - -INSTANTIATE_TEST_SUITE_P( - SSE2, CDEFCopyRect8to16Test, - ::testing::Values(make_tuple(&cdef_copy_rect8_8bit_to_16bit_c, - &cdef_copy_rect8_8bit_to_16bit_sse2))); - -INSTANTIATE_TEST_SUITE_P( - SSE2, CDEFCopyRect16to16Test, - ::testing::Values(make_tuple(&cdef_copy_rect8_16bit_to_16bit_c, - &cdef_copy_rect8_16bit_to_16bit_sse2))); -#endif - -#if HAVE_SSSE3 +#if AOM_ARCH_X86 && HAVE_SSSE3 static const CdefFilterBlockFunctions kCdefFilterFuncSsse3[] = { { &cdef_filter_8_0_ssse3, &cdef_filter_8_1_ssse3, &cdef_filter_8_2_ssse3, &cdef_filter_8_3_ssse3 } @@ -843,30 +800,7 @@ INSTANTIATE_TEST_SUITE_P( #endif // Test speed for all supported architectures -#if HAVE_SSE2 -INSTANTIATE_TEST_SUITE_P( - SSE2, CDEFSpeedTest, - ::testing::Combine(::testing::ValuesIn(kCdefFilterFuncSse2), - ::testing::ValuesIn(kCdefFilterFuncC), - ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, - BLOCK_8X8), - ::testing::Range(0, 16), ::testing::Values(8))); -INSTANTIATE_TEST_SUITE_P( - SSE2, CDEFSpeedHighbdTest, - ::testing::Combine(::testing::ValuesIn(kCdefFilterHighbdFuncSse2), - ::testing::ValuesIn(kCdefFilterHighbdFuncC), - ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, - BLOCK_8X8), - ::testing::Range(0, 16), ::testing::Values(10))); -INSTANTIATE_TEST_SUITE_P(SSE2, CDEFFindDirSpeedTest, - ::testing::Values(make_tuple(&cdef_find_dir_sse2, - &cdef_find_dir_c))); -INSTANTIATE_TEST_SUITE_P(SSE2, CDEFFindDirDualSpeedTest, - ::testing::Values(make_tuple(&cdef_find_dir_dual_sse2, - &cdef_find_dir_dual_c))); -#endif - -#if HAVE_SSSE3 +#if AOM_ARCH_X86 && HAVE_SSSE3 INSTANTIATE_TEST_SUITE_P( SSSE3, CDEFSpeedTest, ::testing::Combine(::testing::ValuesIn(kCdefFilterFuncSsse3), diff --git a/third_party/aom/test/convolve_test.cc b/third_party/aom/test/convolve_test.cc index c97f814057..cab590927b 100644 --- a/third_party/aom/test/convolve_test.cc +++ b/third_party/aom/test/convolve_test.cc @@ -773,6 +773,17 @@ WRAP(convolve8_vert_neon, 10) WRAP(convolve8_horiz_neon, 12) WRAP(convolve8_vert_neon, 12) #endif // HAVE_NEON + +#if HAVE_SVE +WRAP(convolve8_horiz_sve, 8) +WRAP(convolve8_vert_sve, 8) + +WRAP(convolve8_horiz_sve, 10) +WRAP(convolve8_vert_sve, 10) + +WRAP(convolve8_horiz_sve, 12) +WRAP(convolve8_vert_sve, 12) +#endif // HAVE_SVE #endif // CONFIG_AV1_HIGHBITDEPTH #undef WRAP @@ -832,12 +843,6 @@ const ConvolveParam kArrayHighbdConvolve_sse2[] = { INSTANTIATE_TEST_SUITE_P(SSE2, HighbdConvolveTest, ::testing::ValuesIn(kArrayHighbdConvolve_sse2)); #endif -const ConvolveFunctions convolve8_sse2(aom_convolve8_horiz_sse2, - aom_convolve8_vert_sse2, 0); -const ConvolveParam kArrayConvolve_sse2[] = { ALL_SIZES(convolve8_sse2) }; - -INSTANTIATE_TEST_SUITE_P(SSE2, LowbdConvolveTest, - ::testing::ValuesIn(kArrayConvolve_sse2)); #endif #if HAVE_SSSE3 @@ -919,4 +924,22 @@ INSTANTIATE_TEST_SUITE_P(NEON_I8MM, LowbdConvolveTest, ::testing::ValuesIn(kArray_Convolve8_neon_i8mm)); #endif // HAVE_NEON_I8MM +#if HAVE_SVE +#if CONFIG_AV1_HIGHBITDEPTH +const ConvolveFunctions wrap_convolve8_sve(wrap_convolve8_horiz_sve_8, + wrap_convolve8_vert_sve_8, 8); +const ConvolveFunctions wrap_convolve10_sve(wrap_convolve8_horiz_sve_10, + wrap_convolve8_vert_sve_10, 10); +const ConvolveFunctions wrap_convolve12_sve(wrap_convolve8_horiz_sve_12, + wrap_convolve8_vert_sve_12, 12); +const ConvolveParam kArray_HighbdConvolve8_sve[] = { + ALL_SIZES_64(wrap_convolve8_sve), ALL_SIZES_64(wrap_convolve10_sve), + ALL_SIZES_64(wrap_convolve12_sve) +}; + +INSTANTIATE_TEST_SUITE_P(SVE, HighbdConvolveTest, + ::testing::ValuesIn(kArray_HighbdConvolve8_sve)); +#endif +#endif // HAVE_SVE + } // namespace diff --git a/third_party/aom/test/corner_match_test.cc b/third_party/aom/test/corner_match_test.cc index 9733732180..895c8ad7d3 100644 --- a/third_party/aom/test/corner_match_test.cc +++ b/third_party/aom/test/corner_match_test.cc @@ -27,13 +27,19 @@ namespace AV1CornerMatch { using libaom_test::ACMRandom; -typedef double (*ComputeCrossCorrFunc)(const unsigned char *im1, int stride1, - int x1, int y1, const unsigned char *im2, - int stride2, int x2, int y2); +typedef bool (*ComputeMeanStddevFunc)(const unsigned char *frame, int stride, + int x, int y, double *mean, + double *one_over_stddev); +typedef double (*ComputeCorrFunc)(const unsigned char *frame1, int stride1, + int x1, int y1, double mean1, + double one_over_stddev1, + const unsigned char *frame2, int stride2, + int x2, int y2, double mean2, + double one_over_stddev2); using std::make_tuple; using std::tuple; -typedef tuple CornerMatchParam; +typedef tuple CornerMatchParam; class AV1CornerMatchTest : public ::testing::TestWithParam { public: @@ -41,8 +47,11 @@ class AV1CornerMatchTest : public ::testing::TestWithParam { void SetUp() override; protected: - void RunCheckOutput(int run_times); - ComputeCrossCorrFunc target_func; + void GenerateInput(uint8_t *input1, uint8_t *input2, int w, int h, int mode); + void RunCheckOutput(); + void RunSpeedTest(); + ComputeMeanStddevFunc target_compute_mean_stddev_func; + ComputeCorrFunc target_compute_corr_func; libaom_test::ACMRandom rnd_; }; @@ -51,14 +60,31 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1CornerMatchTest); AV1CornerMatchTest::~AV1CornerMatchTest() = default; void AV1CornerMatchTest::SetUp() { rnd_.Reset(ACMRandom::DeterministicSeed()); - target_func = GET_PARAM(1); + target_compute_mean_stddev_func = GET_PARAM(1); + target_compute_corr_func = GET_PARAM(2); } -void AV1CornerMatchTest::RunCheckOutput(int run_times) { +void AV1CornerMatchTest::GenerateInput(uint8_t *input1, uint8_t *input2, int w, + int h, int mode) { + if (mode == 0) { + for (int i = 0; i < h; ++i) + for (int j = 0; j < w; ++j) { + input1[i * w + j] = rnd_.Rand8(); + input2[i * w + j] = rnd_.Rand8(); + } + } else if (mode == 1) { + for (int i = 0; i < h; ++i) + for (int j = 0; j < w; ++j) { + int v = rnd_.Rand8(); + input1[i * w + j] = v; + input2[i * w + j] = (v / 2) + (rnd_.Rand8() & 15); + } + } +} + +void AV1CornerMatchTest::RunCheckOutput() { const int w = 128, h = 128; - const int num_iters = 10000; - int i, j; - aom_usec_timer ref_timer, test_timer; + const int num_iters = 1000; std::unique_ptr input1(new (std::nothrow) uint8_t[w * h]); std::unique_ptr input2(new (std::nothrow) uint8_t[w * h]); @@ -69,76 +95,139 @@ void AV1CornerMatchTest::RunCheckOutput(int run_times) { // i) Random data, should have correlation close to 0 // ii) Linearly related data + noise, should have correlation close to 1 int mode = GET_PARAM(0); - if (mode == 0) { - for (i = 0; i < h; ++i) - for (j = 0; j < w; ++j) { - input1[i * w + j] = rnd_.Rand8(); - input2[i * w + j] = rnd_.Rand8(); - } - } else if (mode == 1) { - for (i = 0; i < h; ++i) - for (j = 0; j < w; ++j) { - int v = rnd_.Rand8(); - input1[i * w + j] = v; - input2[i * w + j] = (v / 2) + (rnd_.Rand8() & 15); - } + GenerateInput(&input1[0], &input2[0], w, h, mode); + + for (int i = 0; i < num_iters; ++i) { + int x1 = MATCH_SZ_BY2 + rnd_.PseudoUniform(w + 1 - MATCH_SZ); + int y1 = MATCH_SZ_BY2 + rnd_.PseudoUniform(h + 1 - MATCH_SZ); + int x2 = MATCH_SZ_BY2 + rnd_.PseudoUniform(w + 1 - MATCH_SZ); + int y2 = MATCH_SZ_BY2 + rnd_.PseudoUniform(h + 1 - MATCH_SZ); + + double c_mean1, c_one_over_stddev1, c_mean2, c_one_over_stddev2; + bool c_valid1 = aom_compute_mean_stddev_c(input1.get(), w, x1, y1, &c_mean1, + &c_one_over_stddev1); + bool c_valid2 = aom_compute_mean_stddev_c(input2.get(), w, x2, y2, &c_mean2, + &c_one_over_stddev2); + + double simd_mean1, simd_one_over_stddev1, simd_mean2, simd_one_over_stddev2; + bool simd_valid1 = target_compute_mean_stddev_func( + input1.get(), w, x1, y1, &simd_mean1, &simd_one_over_stddev1); + bool simd_valid2 = target_compute_mean_stddev_func( + input2.get(), w, x2, y2, &simd_mean2, &simd_one_over_stddev2); + + // Run the correlation calculation even if one of the "valid" flags is + // false, i.e. if one of the patches doesn't have enough variance. This is + // safe because any potential division by 0 is caught in + // aom_compute_mean_stddev(), and one_over_stddev is set to 0 instead. + // This causes aom_compute_correlation() to return 0, without causing a + // division by 0. + const double c_corr = aom_compute_correlation_c( + input1.get(), w, x1, y1, c_mean1, c_one_over_stddev1, input2.get(), w, + x2, y2, c_mean2, c_one_over_stddev2); + const double simd_corr = target_compute_corr_func( + input1.get(), w, x1, y1, c_mean1, c_one_over_stddev1, input2.get(), w, + x2, y2, c_mean2, c_one_over_stddev2); + + ASSERT_EQ(simd_valid1, c_valid1); + ASSERT_EQ(simd_valid2, c_valid2); + ASSERT_EQ(simd_mean1, c_mean1); + ASSERT_EQ(simd_one_over_stddev1, c_one_over_stddev1); + ASSERT_EQ(simd_mean2, c_mean2); + ASSERT_EQ(simd_one_over_stddev2, c_one_over_stddev2); + ASSERT_EQ(simd_corr, c_corr); } +} - for (i = 0; i < num_iters; ++i) { - int x1 = MATCH_SZ_BY2 + rnd_.PseudoUniform(w - 2 * MATCH_SZ_BY2); - int y1 = MATCH_SZ_BY2 + rnd_.PseudoUniform(h - 2 * MATCH_SZ_BY2); - int x2 = MATCH_SZ_BY2 + rnd_.PseudoUniform(w - 2 * MATCH_SZ_BY2); - int y2 = MATCH_SZ_BY2 + rnd_.PseudoUniform(h - 2 * MATCH_SZ_BY2); - - double res_c = av1_compute_cross_correlation_c(input1.get(), w, x1, y1, - input2.get(), w, x2, y2); - double res_simd = - target_func(input1.get(), w, x1, y1, input2.get(), w, x2, y2); - - if (run_times > 1) { - aom_usec_timer_start(&ref_timer); - for (j = 0; j < run_times; j++) { - av1_compute_cross_correlation_c(input1.get(), w, x1, y1, input2.get(), - w, x2, y2); - } - aom_usec_timer_mark(&ref_timer); - const int elapsed_time_c = - static_cast(aom_usec_timer_elapsed(&ref_timer)); +void AV1CornerMatchTest::RunSpeedTest() { + const int w = 16, h = 16; + const int num_iters = 1000000; + aom_usec_timer ref_timer, test_timer; - aom_usec_timer_start(&test_timer); - for (j = 0; j < run_times; j++) { - target_func(input1.get(), w, x1, y1, input2.get(), w, x2, y2); - } - aom_usec_timer_mark(&test_timer); - const int elapsed_time_simd = - static_cast(aom_usec_timer_elapsed(&test_timer)); - - printf( - "c_time=%d \t simd_time=%d \t " - "gain=%d\n", - elapsed_time_c, elapsed_time_simd, - (elapsed_time_c / elapsed_time_simd)); - } else { - ASSERT_EQ(res_simd, res_c); - } + std::unique_ptr input1(new (std::nothrow) uint8_t[w * h]); + std::unique_ptr input2(new (std::nothrow) uint8_t[w * h]); + ASSERT_NE(input1, nullptr); + ASSERT_NE(input2, nullptr); + + // Test the two extreme cases: + // i) Random data, should have correlation close to 0 + // ii) Linearly related data + noise, should have correlation close to 1 + int mode = GET_PARAM(0); + GenerateInput(&input1[0], &input2[0], w, h, mode); + + // Time aom_compute_mean_stddev() + double c_mean1, c_one_over_stddev1, c_mean2, c_one_over_stddev2; + aom_usec_timer_start(&ref_timer); + for (int i = 0; i < num_iters; i++) { + aom_compute_mean_stddev_c(input1.get(), w, 0, 0, &c_mean1, + &c_one_over_stddev1); + aom_compute_mean_stddev_c(input2.get(), w, 0, 0, &c_mean2, + &c_one_over_stddev2); + } + aom_usec_timer_mark(&ref_timer); + int elapsed_time_c = static_cast(aom_usec_timer_elapsed(&ref_timer)); + + double simd_mean1, simd_one_over_stddev1, simd_mean2, simd_one_over_stddev2; + aom_usec_timer_start(&test_timer); + for (int i = 0; i < num_iters; i++) { + target_compute_mean_stddev_func(input1.get(), w, 0, 0, &simd_mean1, + &simd_one_over_stddev1); + target_compute_mean_stddev_func(input2.get(), w, 0, 0, &simd_mean2, + &simd_one_over_stddev2); + } + aom_usec_timer_mark(&test_timer); + int elapsed_time_simd = static_cast(aom_usec_timer_elapsed(&test_timer)); + + printf( + "aom_compute_mean_stddev(): c_time=%6d simd_time=%6d " + "gain=%.3f\n", + elapsed_time_c, elapsed_time_simd, + (elapsed_time_c / (double)elapsed_time_simd)); + + // Time aom_compute_correlation + aom_usec_timer_start(&ref_timer); + for (int i = 0; i < num_iters; i++) { + aom_compute_correlation_c(input1.get(), w, 0, 0, c_mean1, + c_one_over_stddev1, input2.get(), w, 0, 0, + c_mean2, c_one_over_stddev2); + } + aom_usec_timer_mark(&ref_timer); + elapsed_time_c = static_cast(aom_usec_timer_elapsed(&ref_timer)); + + aom_usec_timer_start(&test_timer); + for (int i = 0; i < num_iters; i++) { + target_compute_corr_func(input1.get(), w, 0, 0, c_mean1, c_one_over_stddev1, + input2.get(), w, 0, 0, c_mean2, + c_one_over_stddev2); } + aom_usec_timer_mark(&test_timer); + elapsed_time_simd = static_cast(aom_usec_timer_elapsed(&test_timer)); + + printf( + "aom_compute_correlation(): c_time=%6d simd_time=%6d " + "gain=%.3f\n", + elapsed_time_c, elapsed_time_simd, + (elapsed_time_c / (double)elapsed_time_simd)); } -TEST_P(AV1CornerMatchTest, CheckOutput) { RunCheckOutput(1); } -TEST_P(AV1CornerMatchTest, DISABLED_Speed) { RunCheckOutput(100000); } +TEST_P(AV1CornerMatchTest, CheckOutput) { RunCheckOutput(); } +TEST_P(AV1CornerMatchTest, DISABLED_Speed) { RunSpeedTest(); } #if HAVE_SSE4_1 INSTANTIATE_TEST_SUITE_P( SSE4_1, AV1CornerMatchTest, - ::testing::Values(make_tuple(0, &av1_compute_cross_correlation_sse4_1), - make_tuple(1, &av1_compute_cross_correlation_sse4_1))); + ::testing::Values(make_tuple(0, &aom_compute_mean_stddev_sse4_1, + &aom_compute_correlation_sse4_1), + make_tuple(1, &aom_compute_mean_stddev_sse4_1, + &aom_compute_correlation_sse4_1))); #endif #if HAVE_AVX2 INSTANTIATE_TEST_SUITE_P( AVX2, AV1CornerMatchTest, - ::testing::Values(make_tuple(0, &av1_compute_cross_correlation_avx2), - make_tuple(1, &av1_compute_cross_correlation_avx2))); + ::testing::Values(make_tuple(0, &aom_compute_mean_stddev_avx2, + &aom_compute_correlation_avx2), + make_tuple(1, &aom_compute_mean_stddev_avx2, + &aom_compute_correlation_avx2))); #endif } // namespace AV1CornerMatch diff --git a/third_party/aom/test/disflow_test.cc b/third_party/aom/test/disflow_test.cc index 124c9a96c7..4f004480e2 100644 --- a/third_party/aom/test/disflow_test.cc +++ b/third_party/aom/test/disflow_test.cc @@ -114,6 +114,11 @@ INSTANTIATE_TEST_SUITE_P(SSE4_1, ComputeFlowTest, ::testing::Values(aom_compute_flow_at_point_sse4_1)); #endif +#if HAVE_AVX2 +INSTANTIATE_TEST_SUITE_P(AVX2, ComputeFlowTest, + ::testing::Values(aom_compute_flow_at_point_avx2)); +#endif + #if HAVE_NEON INSTANTIATE_TEST_SUITE_P(NEON, ComputeFlowTest, ::testing::Values(aom_compute_flow_at_point_neon)); diff --git a/third_party/aom/test/encode_api_test.cc b/third_party/aom/test/encode_api_test.cc index 605743f9be..a7d5b3aa3c 100644 --- a/third_party/aom/test/encode_api_test.cc +++ b/third_party/aom/test/encode_api_test.cc @@ -10,6 +10,8 @@ */ #include +#include +#include #include #include #include @@ -556,6 +558,83 @@ TEST(EncodeAPI, Buganizer310457427) { encoder.Encode(false); } +TEST(EncodeAPI, PtsSmallerThanInitialPts) { + // Initialize libaom encoder. + aom_codec_iface_t *const iface = aom_codec_av1_cx(); + aom_codec_ctx_t enc; + aom_codec_enc_cfg_t cfg; + + ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), + AOM_CODEC_OK); + + cfg.g_w = 1280; + cfg.g_h = 720; + cfg.rc_target_bitrate = 1000; + + ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); + + // Create input image. + aom_image_t *const image = + CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); + ASSERT_NE(image, nullptr); + + // Encode frame. + ASSERT_EQ(aom_codec_encode(&enc, image, 12, 1, 0), AOM_CODEC_OK); + ASSERT_EQ(aom_codec_encode(&enc, image, 13, 1, 0), AOM_CODEC_OK); + // pts (10) is smaller than the initial pts (12). + ASSERT_EQ(aom_codec_encode(&enc, image, 10, 1, 0), AOM_CODEC_INVALID_PARAM); + + // Free resources. + aom_img_free(image); + aom_codec_destroy(&enc); +} + +TEST(EncodeAPI, PtsOrDurationTooBig) { + // Initialize libaom encoder. + aom_codec_iface_t *const iface = aom_codec_av1_cx(); + aom_codec_ctx_t enc; + aom_codec_enc_cfg_t cfg; + + ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), + AOM_CODEC_OK); + + cfg.g_w = 1280; + cfg.g_h = 720; + cfg.rc_target_bitrate = 1000; + + ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); + + // Create input image. + aom_image_t *const image = + CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); + ASSERT_NE(image, nullptr); + + // Encode frame. + ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK); + // pts, when converted to ticks, is too big. + ASSERT_EQ(aom_codec_encode(&enc, image, INT64_MAX / 1000000 + 1, 1, 0), + AOM_CODEC_INVALID_PARAM); +#if ULONG_MAX > INT64_MAX + // duration is too big. + ASSERT_EQ(aom_codec_encode(&enc, image, 0, (1ul << 63), 0), + AOM_CODEC_INVALID_PARAM); + // pts + duration is too big. + ASSERT_EQ(aom_codec_encode(&enc, image, 1, INT64_MAX, 0), + AOM_CODEC_INVALID_PARAM); +#endif + // pts + duration, when converted to ticks, is too big. +#if ULONG_MAX > INT64_MAX + ASSERT_EQ(aom_codec_encode(&enc, image, 0, 0x1c0a0a1a3232, 0), + AOM_CODEC_INVALID_PARAM); +#endif + ASSERT_EQ(aom_codec_encode(&enc, image, INT64_MAX / 1000000, 1, 0), + AOM_CODEC_INVALID_PARAM); + + // Free resources. + aom_img_free(image); + aom_codec_destroy(&enc); +} + class EncodeAPIParameterized : public testing::TestWithParam> {}; diff --git a/third_party/aom/test/hbd_metrics_test.cc b/third_party/aom/test/hbd_metrics_test.cc index 303d580c4a..71c816f1cc 100644 --- a/third_party/aom/test/hbd_metrics_test.cc +++ b/third_party/aom/test/hbd_metrics_test.cc @@ -112,10 +112,10 @@ class HBDMetricsTestBase { memset(&hbd_src, 0, sizeof(hbd_src)); memset(&hbd_dst, 0, sizeof(hbd_dst)); - aom_alloc_frame_buffer(&lbd_src, width, height, 1, 1, 0, 32, 16, 0, 0); - aom_alloc_frame_buffer(&lbd_dst, width, height, 1, 1, 0, 32, 16, 0, 0); - aom_alloc_frame_buffer(&hbd_src, width, height, 1, 1, 1, 32, 16, 0, 0); - aom_alloc_frame_buffer(&hbd_dst, width, height, 1, 1, 1, 32, 16, 0, 0); + aom_alloc_frame_buffer(&lbd_src, width, height, 1, 1, 0, 32, 16, false, 0); + aom_alloc_frame_buffer(&lbd_dst, width, height, 1, 1, 0, 32, 16, false, 0); + aom_alloc_frame_buffer(&hbd_src, width, height, 1, 1, 1, 32, 16, false, 0); + aom_alloc_frame_buffer(&hbd_dst, width, height, 1, 1, 1, 32, 16, false, 0); memset(lbd_src.buffer_alloc, kPixFiller, lbd_src.buffer_alloc_sz); while (i < lbd_src.buffer_alloc_sz) { diff --git a/third_party/aom/test/level_test.cc b/third_party/aom/test/level_test.cc index a7c26d2305..6d59f45272 100644 --- a/third_party/aom/test/level_test.cc +++ b/third_party/aom/test/level_test.cc @@ -135,12 +135,12 @@ TEST_P(LevelTest, TestLevelMonitoringLowBitrate) { // To save run time, we only test speed 4. if (cpu_used_ == 4) { libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 40); + 30, 1, 0, 30); target_level_ = kLevelKeepStats; cfg_.rc_target_bitrate = 1000; - cfg_.g_limit = 40; + cfg_.g_limit = 30; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_EQ(level_[0], 0); + ASSERT_LE(level_[0], 0); } } @@ -148,12 +148,12 @@ TEST_P(LevelTest, TestLevelMonitoringHighBitrate) { // To save run time, we only test speed 4. if (cpu_used_ == 4) { libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, - 30, 1, 0, 40); + 30, 1, 0, 30); target_level_ = kLevelKeepStats; cfg_.rc_target_bitrate = 4000; - cfg_.g_limit = 40; + cfg_.g_limit = 30; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_EQ(level_[0], 4); + ASSERT_LE(level_[0], 4); } } @@ -166,7 +166,7 @@ TEST_P(LevelTest, TestTargetLevel0) { target_level_ = target_level; cfg_.rc_target_bitrate = 4000; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - ASSERT_EQ(level_[0], target_level); + ASSERT_LE(level_[0], target_level); } } diff --git a/third_party/aom/test/quantize_func_test.cc b/third_party/aom/test/quantize_func_test.cc index 328d5b10df..61f26ea57f 100644 --- a/third_party/aom/test/quantize_func_test.cc +++ b/third_party/aom/test/quantize_func_test.cc @@ -19,6 +19,7 @@ #include "config/av1_rtcd.h" #include "aom/aom_codec.h" +#include "aom_dsp/txfm_common.h" #include "aom_ports/aom_timer.h" #include "av1/encoder/encoder.h" #include "av1/common/scan.h" @@ -482,9 +483,9 @@ const QuantizeParam kLPQParamArrayAvx2[] = { make_tuple(&av1_quantize_lp_c, &av1_quantize_lp_avx2, static_cast(TX_16X16), TYPE_FP, AOM_BITS_8), make_tuple(&av1_quantize_lp_c, &av1_quantize_lp_avx2, - static_cast(TX_32X32), TYPE_FP, AOM_BITS_8), + static_cast(TX_8X8), TYPE_FP, AOM_BITS_8), make_tuple(&av1_quantize_lp_c, &av1_quantize_lp_avx2, - static_cast(TX_64X64), TYPE_FP, AOM_BITS_8) + static_cast(TX_4X4), TYPE_FP, AOM_BITS_8) }; INSTANTIATE_TEST_SUITE_P(AVX2, LowPrecisionQuantizeTest, @@ -704,9 +705,9 @@ const QuantizeParam kLPQParamArrayNEON[] = { make_tuple(av1_quantize_lp_c, av1_quantize_lp_neon, static_cast(TX_16X16), TYPE_FP, AOM_BITS_8), make_tuple(av1_quantize_lp_c, av1_quantize_lp_neon, - static_cast(TX_32X32), TYPE_FP, AOM_BITS_8), + static_cast(TX_8X8), TYPE_FP, AOM_BITS_8), make_tuple(av1_quantize_lp_c, av1_quantize_lp_neon, - static_cast(TX_64X64), TYPE_FP, AOM_BITS_8) + static_cast(TX_4X4), TYPE_FP, AOM_BITS_8) }; INSTANTIATE_TEST_SUITE_P(NEON, LowPrecisionQuantizeTest, diff --git a/third_party/aom/test/resize_test.cc b/third_party/aom/test/resize_test.cc index 755d4e3d02..a84a4654a8 100644 --- a/third_party/aom/test/resize_test.cc +++ b/third_party/aom/test/resize_test.cc @@ -15,7 +15,6 @@ #include "aom/aomcx.h" #include "aom_dsp/aom_dsp_common.h" #include "av1/encoder/encoder.h" -#include "common/tools_common.h" #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "test/codec_factory.h" #include "test/encode_test_driver.h" @@ -690,6 +689,45 @@ TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) { } } +TEST_P(ResizeRealtimeTest, TestExternalResizeWorksUsePSNR) { + ResizingVideoSource video; + video.flag_codec_ = 1; + change_bitrate_ = false; + set_scale_mode_ = false; + set_scale_mode2_ = false; + set_scale_mode3_ = false; + mismatch_psnr_ = 0.0; + mismatch_nframes_ = 0; + init_flags_ = AOM_CODEC_USE_PSNR; + cfg_.rc_dropframe_thresh = 30; + DefaultConfig(); + // Test external resizing with start resolution equal to + // 1. kInitialWidth and kInitialHeight + // 2. down-scaled kInitialWidth and kInitialHeight + for (int i = 0; i < 2; i++) { + video.change_start_resln_ = static_cast(i); + + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + + // Check we decoded the same number of frames as we attempted to encode + ASSERT_EQ(frame_info_list_.size(), video.limit()); + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); + unsigned int expected_w; + unsigned int expected_h; + ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, + video.flag_codec_, video.change_start_resln_, + &expected_w, &expected_h); + EXPECT_EQ(expected_w, info.w) + << "Frame " << frame << " had unexpected width"; + EXPECT_EQ(expected_h, info.h) + << "Frame " << frame << " had unexpected height"; + EXPECT_EQ(static_cast(0), GetMismatchFrames()); + } + frame_info_list_.clear(); + } +} + // Verify the dynamic resizer behavior for real time, 1 pass CBR mode. // Run at low bitrate, with resize_allowed = 1, and verify that we get // one resize down event. diff --git a/third_party/aom/test/sad_test.cc b/third_party/aom/test/sad_test.cc index 521274863c..64cf8006be 100644 --- a/third_party/aom/test/sad_test.cc +++ b/third_party/aom/test/sad_test.cc @@ -3202,6 +3202,7 @@ const SadSkipMxNx4Param skip_x4d_avx2_tests[] = { make_tuple(32, 8, &aom_sad_skip_32x8x4d_avx2, -1), make_tuple(16, 64, &aom_sad_skip_16x64x4d_avx2, -1), + make_tuple(16, 4, &aom_sad_skip_16x4x4d_avx2, -1), #endif }; @@ -3294,6 +3295,7 @@ const SadMxNx4Param x3d_avx2_tests[] = { #if !CONFIG_REALTIME_ONLY make_tuple(32, 8, &aom_sad32x8x3d_avx2, -1), make_tuple(64, 16, &aom_sad64x16x3d_avx2, -1), + make_tuple(16, 4, &aom_sad16x4x3d_avx2, -1), #endif // !CONFIG_REALTIME_ONLY #if CONFIG_AV1_HIGHBITDEPTH diff --git a/third_party/aom/test/segment_binarization_sync.cc b/third_party/aom/test/segment_binarization_sync.cc index bd8cf11410..108e66a838 100644 --- a/third_party/aom/test/segment_binarization_sync.cc +++ b/third_party/aom/test/segment_binarization_sync.cc @@ -10,15 +10,14 @@ */ #include "third_party/googletest/src/googletest/include/gtest/gtest.h" + +#include "av1/common/seg_common.h" +#include "av1/decoder/decodemv.h" +#include "av1/encoder/bitstream.h" #include "test/acm_random.h" using libaom_test::ACMRandom; -extern "C" { -int av1_neg_interleave(int x, int ref, int max); -int av1_neg_deinterleave(int diff, int ref, int max); -} - namespace { struct Segment { @@ -28,8 +27,6 @@ struct Segment { }; Segment GenerateSegment(int seed) { - static const int MAX_SEGMENTS = 8; - ACMRandom rnd_(seed); Segment segment; diff --git a/third_party/aom/test/sharpness_test.cc b/third_party/aom/test/sharpness_test.cc index 64465c88eb..054fbcc660 100644 --- a/third_party/aom/test/sharpness_test.cc +++ b/third_party/aom/test/sharpness_test.cc @@ -30,7 +30,7 @@ const std::unordered_map< kPsnrThreshold = { { static_cast(::libaom_test::kTwoPassGood), { { 2, { { 2, 37.6 }, { 5, 37.6 } } }, { 4, { { 2, 37.5 }, { 5, 37.5 } } }, - { 6, { { 2, 37.5 }, { 5, 37.5 } } } } }, + { 6, { { 2, 37.4 }, { 5, 37.4 } } } } }, { static_cast(::libaom_test::kAllIntra), { { 3, { { 2, 42.2 }, { 5, 42.2 } } }, { 6, { { 2, 41.8 }, { 4, 41.9 }, { 5, 41.9 } } }, diff --git a/third_party/aom/test/test.cmake b/third_party/aom/test/test.cmake index ce94a5a657..e2f5da570d 100644 --- a/third_party/aom/test/test.cmake +++ b/third_party/aom/test/test.cmake @@ -28,8 +28,7 @@ function(add_to_libaom_test_srcs src_list_name) set(AOM_TEST_SOURCE_VARS "${AOM_TEST_SOURCE_VARS}" PARENT_SCOPE) endfunction() -list(APPEND AOM_UNIT_TEST_WRAPPER_SOURCES "${AOM_GEN_SRC_DIR}/usage_exit.c" - "${AOM_ROOT}/test/test_libaom.cc") +list(APPEND AOM_UNIT_TEST_WRAPPER_SOURCES "${AOM_ROOT}/test/test_libaom.cc") add_to_libaom_test_srcs(AOM_UNIT_TEST_WRAPPER_SOURCES) list(APPEND AOM_UNIT_TEST_COMMON_SOURCES @@ -102,7 +101,7 @@ add_to_libaom_test_srcs(AOM_UNIT_TEST_ENCODER_SOURCES) list(APPEND AOM_ENCODE_PERF_TEST_SOURCES "${AOM_ROOT}/test/encode_perf_test.cc") list(APPEND AOM_UNIT_TEST_WEBM_SOURCES "${AOM_ROOT}/test/webm_video_source.h") add_to_libaom_test_srcs(AOM_UNIT_TEST_WEBM_SOURCES) -list(APPEND AOM_TEST_INTRA_PRED_SPEED_SOURCES "${AOM_GEN_SRC_DIR}/usage_exit.c" +list(APPEND AOM_TEST_INTRA_PRED_SPEED_SOURCES "${AOM_ROOT}/test/test_intra_pred_speed.cc") if(CONFIG_AV1_DECODER) @@ -277,24 +276,24 @@ if(NOT BUILD_SHARED_LIBS) list(APPEND AOM_UNIT_TEST_COMMON_SOURCES "${AOM_ROOT}/test/coding_path_sync.cc") endif() - if(CONFIG_REALTIME_ONLY) - list(REMOVE_ITEM AOM_UNIT_TEST_COMMON_SOURCES - "${AOM_ROOT}/test/altref_test.cc" - "${AOM_ROOT}/test/av1_encoder_parms_get_to_decoder.cc" - "${AOM_ROOT}/test/av1_ext_tile_test.cc" - "${AOM_ROOT}/test/cnn_test.cc" - "${AOM_ROOT}/test/decode_multithreaded_test.cc" - "${AOM_ROOT}/test/error_resilience_test.cc" - "${AOM_ROOT}/test/kf_test.cc" - "${AOM_ROOT}/test/lossless_test.cc" - "${AOM_ROOT}/test/sb_multipass_test.cc" - "${AOM_ROOT}/test/sb_qp_sweep_test.cc" - "${AOM_ROOT}/test/selfguided_filter_test.cc" - "${AOM_ROOT}/test/screen_content_test.cc" - "${AOM_ROOT}/test/still_picture_test.cc" - "${AOM_ROOT}/test/tile_independence_test.cc" - "${AOM_ROOT}/test/tpl_model_test.cc") - endif() + endif() + if(CONFIG_REALTIME_ONLY) + list(REMOVE_ITEM AOM_UNIT_TEST_COMMON_SOURCES + "${AOM_ROOT}/test/altref_test.cc" + "${AOM_ROOT}/test/av1_encoder_parms_get_to_decoder.cc" + "${AOM_ROOT}/test/av1_ext_tile_test.cc" + "${AOM_ROOT}/test/cnn_test.cc" + "${AOM_ROOT}/test/decode_multithreaded_test.cc" + "${AOM_ROOT}/test/error_resilience_test.cc" + "${AOM_ROOT}/test/kf_test.cc" + "${AOM_ROOT}/test/lossless_test.cc" + "${AOM_ROOT}/test/sb_multipass_test.cc" + "${AOM_ROOT}/test/sb_qp_sweep_test.cc" + "${AOM_ROOT}/test/selfguided_filter_test.cc" + "${AOM_ROOT}/test/screen_content_test.cc" + "${AOM_ROOT}/test/still_picture_test.cc" + "${AOM_ROOT}/test/tile_independence_test.cc" + "${AOM_ROOT}/test/tpl_model_test.cc") endif() if(CONFIG_FPMT_TEST AND (NOT CONFIG_REALTIME_ONLY)) @@ -462,6 +461,7 @@ function(setup_aom_test_targets) add_executable(test_libaom ${AOM_UNIT_TEST_WRAPPER_SOURCES} $ + $ $) set_property(TARGET test_libaom PROPERTY FOLDER ${AOM_IDE_TEST_FOLDER}) list(APPEND AOM_APP_TARGETS test_libaom) @@ -484,9 +484,9 @@ function(setup_aom_test_targets) endif() if(NOT BUILD_SHARED_LIBS) - add_executable(test_intra_pred_speed - ${AOM_TEST_INTRA_PRED_SPEED_SOURCES} - $) + add_executable(test_intra_pred_speed ${AOM_TEST_INTRA_PRED_SPEED_SOURCES} + $ + $) set_property(TARGET test_intra_pred_speed PROPERTY FOLDER ${AOM_IDE_TEST_FOLDER}) target_link_libraries(test_intra_pred_speed ${AOM_LIB_LINK_TYPE} aom diff --git a/third_party/aom/test/test_libaom.cc b/third_party/aom/test/test_libaom.cc index fbd7f2e380..26abbb0a06 100644 --- a/third_party/aom/test/test_libaom.cc +++ b/third_party/aom/test/test_libaom.cc @@ -62,6 +62,7 @@ int main(int argc, char **argv) { if (!(caps & HAS_NEON_DOTPROD)) append_negative_gtest_filter("NEON_DOTPROD"); if (!(caps & HAS_NEON_I8MM)) append_negative_gtest_filter("NEON_I8MM"); if (!(caps & HAS_SVE)) append_negative_gtest_filter("SVE"); + if (!(caps & HAS_SVE2)) append_negative_gtest_filter("SVE2"); #elif AOM_ARCH_ARM const int caps = aom_arm_cpu_caps(); if (!(caps & HAS_NEON)) append_negative_gtest_filter("NEON"); diff --git a/third_party/aom/test/variance_test.cc b/third_party/aom/test/variance_test.cc index e31f8f820c..261c080028 100644 --- a/third_party/aom/test/variance_test.cc +++ b/third_party/aom/test/variance_test.cc @@ -2785,64 +2785,6 @@ const GetSseSumParamsDual kArrayGetSseSum16x16Dual_sse2[] = { INSTANTIATE_TEST_SUITE_P(SSE2, GetSseSum16x16DualTest, ::testing::ValuesIn(kArrayGetSseSum16x16Dual_sse2)); -const SubpelVarianceParams kArraySubpelVariance_sse2[] = { - SubpelVarianceParams(7, 7, &aom_sub_pixel_variance128x128_sse2, 0), - SubpelVarianceParams(7, 6, &aom_sub_pixel_variance128x64_sse2, 0), - SubpelVarianceParams(6, 7, &aom_sub_pixel_variance64x128_sse2, 0), - SubpelVarianceParams(6, 6, &aom_sub_pixel_variance64x64_sse2, 0), - SubpelVarianceParams(6, 5, &aom_sub_pixel_variance64x32_sse2, 0), - SubpelVarianceParams(5, 6, &aom_sub_pixel_variance32x64_sse2, 0), - SubpelVarianceParams(5, 5, &aom_sub_pixel_variance32x32_sse2, 0), - SubpelVarianceParams(5, 4, &aom_sub_pixel_variance32x16_sse2, 0), - SubpelVarianceParams(4, 5, &aom_sub_pixel_variance16x32_sse2, 0), - SubpelVarianceParams(4, 4, &aom_sub_pixel_variance16x16_sse2, 0), - SubpelVarianceParams(4, 3, &aom_sub_pixel_variance16x8_sse2, 0), - SubpelVarianceParams(3, 4, &aom_sub_pixel_variance8x16_sse2, 0), - SubpelVarianceParams(3, 3, &aom_sub_pixel_variance8x8_sse2, 0), - SubpelVarianceParams(3, 2, &aom_sub_pixel_variance8x4_sse2, 0), - SubpelVarianceParams(2, 3, &aom_sub_pixel_variance4x8_sse2, 0), - SubpelVarianceParams(2, 2, &aom_sub_pixel_variance4x4_sse2, 0), -#if !CONFIG_REALTIME_ONLY - SubpelVarianceParams(6, 4, &aom_sub_pixel_variance64x16_sse2, 0), - SubpelVarianceParams(4, 6, &aom_sub_pixel_variance16x64_sse2, 0), - SubpelVarianceParams(5, 3, &aom_sub_pixel_variance32x8_sse2, 0), - SubpelVarianceParams(3, 5, &aom_sub_pixel_variance8x32_sse2, 0), - SubpelVarianceParams(4, 2, &aom_sub_pixel_variance16x4_sse2, 0), - SubpelVarianceParams(2, 4, &aom_sub_pixel_variance4x16_sse2, 0), -#endif -}; -INSTANTIATE_TEST_SUITE_P(SSE2, AvxSubpelVarianceTest, - ::testing::ValuesIn(kArraySubpelVariance_sse2)); - -const SubpelAvgVarianceParams kArraySubpelAvgVariance_sse2[] = { - SubpelAvgVarianceParams(7, 7, &aom_sub_pixel_avg_variance128x128_sse2, 0), - SubpelAvgVarianceParams(7, 6, &aom_sub_pixel_avg_variance128x64_sse2, 0), - SubpelAvgVarianceParams(6, 7, &aom_sub_pixel_avg_variance64x128_sse2, 0), - SubpelAvgVarianceParams(6, 6, &aom_sub_pixel_avg_variance64x64_sse2, 0), - SubpelAvgVarianceParams(6, 5, &aom_sub_pixel_avg_variance64x32_sse2, 0), - SubpelAvgVarianceParams(5, 6, &aom_sub_pixel_avg_variance32x64_sse2, 0), - SubpelAvgVarianceParams(5, 5, &aom_sub_pixel_avg_variance32x32_sse2, 0), - SubpelAvgVarianceParams(5, 4, &aom_sub_pixel_avg_variance32x16_sse2, 0), - SubpelAvgVarianceParams(4, 5, &aom_sub_pixel_avg_variance16x32_sse2, 0), - SubpelAvgVarianceParams(4, 4, &aom_sub_pixel_avg_variance16x16_sse2, 0), - SubpelAvgVarianceParams(4, 3, &aom_sub_pixel_avg_variance16x8_sse2, 0), - SubpelAvgVarianceParams(3, 4, &aom_sub_pixel_avg_variance8x16_sse2, 0), - SubpelAvgVarianceParams(3, 3, &aom_sub_pixel_avg_variance8x8_sse2, 0), - SubpelAvgVarianceParams(3, 2, &aom_sub_pixel_avg_variance8x4_sse2, 0), - SubpelAvgVarianceParams(2, 3, &aom_sub_pixel_avg_variance4x8_sse2, 0), - SubpelAvgVarianceParams(2, 2, &aom_sub_pixel_avg_variance4x4_sse2, 0), -#if !CONFIG_REALTIME_ONLY - SubpelAvgVarianceParams(6, 4, &aom_sub_pixel_avg_variance64x16_sse2, 0), - SubpelAvgVarianceParams(4, 6, &aom_sub_pixel_avg_variance16x64_sse2, 0), - SubpelAvgVarianceParams(5, 3, &aom_sub_pixel_avg_variance32x8_sse2, 0), - SubpelAvgVarianceParams(3, 5, &aom_sub_pixel_avg_variance8x32_sse2, 0), - SubpelAvgVarianceParams(4, 2, &aom_sub_pixel_avg_variance16x4_sse2, 0), - SubpelAvgVarianceParams(2, 4, &aom_sub_pixel_avg_variance4x16_sse2, 0), -#endif -}; -INSTANTIATE_TEST_SUITE_P(SSE2, AvxSubpelAvgVarianceTest, - ::testing::ValuesIn(kArraySubpelAvgVariance_sse2)); - #if CONFIG_AV1_HIGHBITDEPTH #if HAVE_SSE2 INSTANTIATE_TEST_SUITE_P( @@ -2852,6 +2794,15 @@ INSTANTIATE_TEST_SUITE_P( MseHBDWxHParams(2, 3, &aom_mse_wxh_16bit_highbd_sse2, 10), MseHBDWxHParams(2, 2, &aom_mse_wxh_16bit_highbd_sse2, 10))); + +INSTANTIATE_TEST_SUITE_P( + SSE2, AvxHBDMseTest, + ::testing::Values(MseParams(4, 4, &aom_highbd_12_mse16x16_sse2, 12), + MseParams(3, 3, &aom_highbd_12_mse8x8_sse2, 12), + MseParams(4, 4, &aom_highbd_10_mse16x16_sse2, 10), + MseParams(3, 3, &aom_highbd_10_mse8x8_sse2, 10), + MseParams(4, 4, &aom_highbd_8_mse16x16_sse2, 8), + MseParams(3, 3, &aom_highbd_8_mse8x8_sse2, 8))); #endif // HAVE_SSE2 #if HAVE_SSE4_1 INSTANTIATE_TEST_SUITE_P( @@ -2878,14 +2829,11 @@ INSTANTIATE_TEST_SUITE_P( 12))); #endif // HAVE_SSE4_1 +#if HAVE_AVX2 INSTANTIATE_TEST_SUITE_P( - SSE2, AvxHBDMseTest, - ::testing::Values(MseParams(4, 4, &aom_highbd_12_mse16x16_sse2, 12), - MseParams(3, 3, &aom_highbd_12_mse8x8_sse2, 12), - MseParams(4, 4, &aom_highbd_10_mse16x16_sse2, 10), - MseParams(3, 3, &aom_highbd_10_mse8x8_sse2, 10), - MseParams(4, 4, &aom_highbd_8_mse16x16_sse2, 8), - MseParams(3, 3, &aom_highbd_8_mse8x8_sse2, 8))); + AVX2, AvxHBDMseTest, + ::testing::Values(MseParams(4, 4, &aom_highbd_10_mse16x16_avx2, 10))); +#endif // HAVE_AVX2 const VarianceParams kArrayHBDVariance_sse2[] = { VarianceParams(7, 7, &aom_highbd_12_variance128x128_sse2, 12), diff --git a/third_party/aom/test/wiener_test.cc b/third_party/aom/test/wiener_test.cc index 7eb6372aaa..b995c84d8f 100644 --- a/third_party/aom/test/wiener_test.cc +++ b/third_party/aom/test/wiener_test.cc @@ -1075,6 +1075,233 @@ TEST(SearchWienerTest, 12bitSignedIntegerOverflowInUpdateBSepSym) { EXPECT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); } +// A test that reproduces crbug.com/oss-fuzz/66474: signed integer overflow in +// update_b_sep_sym(). +TEST(SearchWienerTest, 12bitSignedIntegerOverflowInUpdateBSepSym2) { + constexpr int kWidth = 510; + constexpr int kHeight = 3; + static const uint16_t buffer[kWidth * kHeight] = { + // Y plane: + 2136, 4095, 0, 0, 0, 4095, 4095, 0, 4095, 4095, 329, 0, + 4095, 0, 4095, 2587, 0, 0, 0, 4095, 0, 0, 0, 0, + 4095, 0, 4095, 878, 0, 4095, 0, 4095, 1474, 0, 573, 0, + 2401, 0, 1663, 4095, 0, 9, 3381, 0, 1084, 0, 270, 0, + 4095, 4095, 4095, 3992, 4095, 2047, 0, 0, 0, 4095, 41, 0, + 2726, 279, 0, 0, 4095, 0, 0, 1437, 0, 4095, 4095, 0, + 0, 0, 4095, 1683, 183, 3976, 3052, 0, 4095, 0, 0, 0, + 4095, 4095, 1882, 4095, 0, 4095, 83, 4095, 0, 4095, 0, 0, + 4095, 4095, 0, 0, 1637, 4095, 0, 4095, 0, 4095, 4095, 4095, + 0, 4095, 197, 4095, 563, 0, 3696, 3073, 3670, 0, 4095, 4095, + 0, 0, 0, 4095, 0, 0, 0, 0, 4095, 4095, 0, 0, + 0, 3539, 3468, 0, 2856, 3880, 0, 0, 1350, 2358, 4095, 802, + 4051, 0, 4095, 4095, 4095, 1677, 4095, 1135, 0, 4095, 0, 0, + 0, 618, 4095, 4095, 4095, 0, 2080, 4095, 0, 0, 1917, 0, + 0, 4095, 1937, 2835, 4095, 4095, 4095, 4095, 0, 4095, 4095, 3938, + 1707, 0, 0, 0, 4095, 448, 4095, 0, 1000, 2481, 3408, 0, + 0, 4095, 0, 3176, 0, 4095, 0, 4095, 4095, 4095, 0, 160, + 222, 1134, 4095, 4095, 0, 3539, 4095, 569, 3364, 0, 4095, 3687, + 0, 4095, 0, 0, 473, 0, 0, 4095, 298, 0, 3126, 4095, + 3854, 424, 0, 0, 4095, 3893, 0, 0, 175, 2774, 0, 4095, + 0, 2661, 950, 4095, 0, 1553, 0, 4095, 0, 4095, 4095, 2767, + 3630, 799, 255, 0, 4095, 0, 0, 4095, 2375, 0, 0, 0, + 0, 4095, 4095, 0, 0, 0, 1404, 4095, 4095, 4095, 4095, 2317, + 4095, 1227, 2205, 775, 0, 4095, 0, 0, 797, 1125, 736, 1773, + 2996, 4095, 2822, 4095, 4095, 0, 0, 0, 919, 0, 968, 3426, + 2702, 2613, 3647, 0, 0, 4095, 4095, 129, 4095, 0, 0, 4095, + 0, 0, 3632, 0, 3275, 123, 4095, 1566, 0, 0, 0, 1609, + 0, 1466, 4095, 577, 4095, 4095, 0, 4095, 1103, 1103, 4095, 0, + 1909, 0, 4095, 0, 4095, 4095, 227, 0, 4095, 2168, 4095, 374, + 4095, 4095, 4095, 0, 0, 0, 4095, 2066, 4095, 4095, 1475, 0, + 1959, 673, 4095, 0, 4095, 4095, 4095, 1142, 0, 464, 1819, 2033, + 4095, 0, 2212, 4095, 4095, 3961, 0, 4095, 0, 2838, 0, 4095, + 4095, 4095, 4095, 0, 3796, 3379, 2208, 0, 4095, 4095, 1943, 478, + 3573, 4095, 1763, 0, 0, 4095, 4095, 4095, 4095, 2061, 3346, 4095, + 0, 0, 4095, 0, 4095, 4095, 4095, 3738, 4095, 4095, 0, 4095, + 0, 425, 0, 0, 0, 927, 0, 0, 1814, 966, 4095, 0, + 0, 3185, 570, 3883, 2932, 0, 1413, 4095, 4095, 4095, 4095, 2477, + 2270, 4095, 2531, 4095, 1936, 3110, 99, 3936, 4095, 1315, 4095, 0, + 4095, 3564, 4095, 0, 0, 2797, 4095, 0, 1598, 0, 0, 3064, + 3526, 4095, 4095, 0, 3473, 3661, 0, 2388, 0, 4095, 639, 4095, + 0, 4095, 2390, 3715, 4095, 0, 0, 0, 740, 4095, 1432, 0, + 0, 0, 4057, 0, 0, 757, 4095, 4095, 0, 1437, 0, 0, + 4095, 0, 0, 0, 0, 0, 272, 4095, 4095, 4095, 2175, 4058, + 0, 4095, 4095, 4095, 3959, 3535, 0, 4095, 0, 0, 4095, 4095, + 4095, 4095, 0, 0, 4095, 4095, 4095, 3440, 3811, 0, 4095, 4095, + 4095, 4095, 0, 4095, 3193, 3674, 2819, 4095, 4095, 4048, 0, 0, + 4037, 4095, 3110, 4095, 1003, 0, 3650, 4095, 4095, 3154, 0, 1274, + 2192, 4095, 0, 4095, 0, 2814, 981, 370, 1407, 0, 4095, 1518, + 4095, 0, 0, 0, 0, 4095, 1577, 0, 4095, 0, 2607, 4095, + 3583, 0, 0, 4095, 1983, 1498, 4095, 4095, 2645, 4095, 4095, 3480, + 2587, 4095, 0, 0, 0, 0, 4095, 0, 4095, 4095, 0, 284, + 3973, 0, 0, 3677, 2463, 4095, 1338, 0, 4095, 0, 0, 4095, + 212, 2000, 4095, 4095, 0, 4095, 3780, 2039, 4095, 2453, 4095, 2050, + 2660, 1, 3839, 5, 1, 505, 809, 2907, 0, 0, 0, 1421, + 4095, 0, 0, 4095, 4095, 4095, 552, 0, 0, 4095, 3056, 0, + 0, 0, 0, 0, 4095, 0, 3386, 0, 0, 0, 4095, 0, + 0, 3404, 2702, 3534, 4095, 3562, 0, 4095, 4095, 150, 4095, 0, + 0, 3599, 4095, 4095, 0, 0, 0, 4095, 4095, 2093, 4095, 3753, + 3754, 4095, 0, 4095, 2733, 4095, 4095, 0, 0, 4095, 0, 0, + 0, 1496, 4095, 2366, 2936, 2494, 4095, 744, 1173, 4095, 0, 0, + 0, 1966, 4095, 4095, 0, 178, 3254, 4095, 4095, 995, 4095, 2083, + 0, 2639, 4095, 3422, 4095, 4095, 4095, 0, 842, 4095, 4095, 552, + 3681, 4095, 0, 1075, 2631, 554, 0, 0, 4095, 0, 0, 0, + 4095, 4095, 0, 0, 0, 2234, 0, 1098, 4095, 3164, 4095, 0, + 2748, 0, 0, 0, 4095, 4095, 4095, 1724, 891, 3496, 3964, 4095, + 0, 0, 1923, 4095, 4095, 4095, 3118, 0, 0, 0, 4095, 4095, + 0, 0, 3856, 4095, 0, 0, 4095, 4095, 2647, 0, 2089, 4095, + 471, 0, 4095, 0, 0, 0, 4095, 0, 1263, 2969, 289, 0, + 0, 4095, 289, 0, 0, 2965, 0, 0, 3280, 2279, 4091, 5, + 512, 1776, 4, 2046, 3994, 1, 4095, 898, 4095, 0, 0, 0, + 0, 4095, 0, 4095, 4095, 1930, 0, 0, 3725, 4095, 4095, 0, + 2593, 4095, 0, 4095, 984, 0, 4095, 2388, 0, 0, 4095, 4095, + 3341, 4095, 0, 2787, 0, 831, 2978, 4095, 0, 0, 0, 4095, + 1624, 4095, 1054, 1039, 0, 89, 3565, 0, 4095, 468, 0, 4095, + 4095, 0, 4095, 4095, 0, 3907, 0, 0, 0, 0, 0, 0, + 4095, 1898, 2178, 4095, 0, 3708, 2825, 0, 4095, 0, 4095, 4095, + 0, 0, 811, 1078, 0, 4095, 0, 3478, 0, 0, 1127, 0, + 504, 4095, 4095, 2006, 4095, 0, 2666, 1172, 4095, 4095, 4095, 4095, + 4095, 0, 199, 4095, 0, 2355, 2650, 2961, 0, 0, 0, 4095, + 4095, 0, 4095, 0, 4095, 1477, 0, 0, 1946, 0, 3352, 1988, + 0, 0, 2321, 4095, 0, 4095, 3367, 0, 0, 4095, 4095, 1946, + 0, 4034, 0, 0, 4095, 4095, 0, 0, 0, 0, 4095, 973, + 1734, 3966, 4095, 0, 3780, 1242, 0, 4095, 1301, 0, 1513, 4095, + 1079, 4095, 0, 0, 1316, 4095, 4095, 675, 2713, 2006, 4095, 4095, + 0, 0, 4095, 4095, 0, 3542, 4095, 0, 2365, 130, 4095, 2919, + 0, 4095, 3434, 0, 905, 4095, 673, 4095, 4095, 0, 3923, 293, + 4095, 213, 4095, 4095, 1334, 4095, 0, 3317, 0, 0, 0, 4095, + 4095, 4095, 2598, 2010, 0, 0, 3507, 0, 0, 0, 489, 0, + 0, 1782, 2681, 3303, 4095, 4095, 1955, 4095, 4095, 4095, 203, 1973, + 4095, 4020, 0, 4095, 1538, 0, 373, 1934, 4095, 0, 4095, 2244, + 4095, 1936, 4095, 640, 0, 4095, 0, 0, 0, 3653, 4095, 1966, + 4095, 4095, 4095, 4095, 0, 4095, 843, 0, 4095, 4095, 4095, 1646, + 4095, 0, 0, 4095, 4095, 4095, 2164, 0, 0, 0, 2141, 4095, + 0, 903, 4095, 4095, 0, 624, 4095, 792, 0, 0, 0, 0, + 0, 0, 0, 4095, 0, 4095, 4095, 2466, 0, 3631, 0, 4095, + 4095, 4095, 0, 941, 4095, 4095, 1609, 4095, 4095, 0, 0, 2398, + 4095, 4095, 2579, 0, 4020, 3485, 0, 0, 4095, 0, 4095, 0, + 3158, 2355, 0, 4095, 4095, 4095, 0, 0, 4095, 0, 0, 4095, + 475, 2272, 1010, 0, 0, 4095, 0, 0, 4095, 841, 4095, 4095, + 4095, 4095, 0, 4095, 0, 1046, 4095, 1738, 708, 4095, 0, 4095, + 4095, 0, 4095, 4095, 0, 4095, 4095, 0, 0, 0, 4032, 0, + 2679, 0, 1564, 0, 0, 0, 659, 1915, 4095, 3682, 0, 3660, + 4095, 723, 1383, 2499, 1353, 4095, 0, 3898, 2322, 3798, 4095, 0, + 444, 2277, 3729, 4095, 4095, 4095, 3054, 387, 3309, 4048, 3793, 2842, + 2087, 0, 3274, 2454, 518, 0, 4095, 0, 4095, 4095, 3358, 4095, + 2083, 2105, 0, 0, 0, 1125, 2636, 0, 0, 0, 0, 736, + 0, 349, 0, 4095, 2031, 4095, 992, 0, 4095, 3284, 4095, 214, + 3692, 4010, 402, 0, 0, 3776, 4095, 4095, 4095, 4095, 803, 2095, + 3864, 4095, 3323, 0, 0, 361, 1634, 0, 983, 0, 1181, 4095, + 1791, 4095, 367, 792, 4095, 4095, 3315, 3149, 4095, 62, 4095, 1791, + 3708, 2030, 4095, 1237, 0, 4095, 4095, 0, 0, 0, 0, 4095, + 1902, 2257, 4095, 4095, 0, 0, 2929, 4095, 0, 4095, 2356, 4095, + 2877, 1296, 4095, 0, 0, 0, 1310, 1968, 820, 4095, 4095, 4095, + 4095, 4095, 0, 0, 4095, 4095, 4095, 2897, 1787, 2218, 0, 129, + 4095, 4095, 0, 4095, 2331, 4095, 4095, 3192, 4095, 1744, 755, 0, + 1905, 0, 4095, 4095, 4095, 0, 0, 4095, 4095, 4095, 0, 0, + 0, 1467, 266, 1719, 4095, 729, 4095, 4095, 2647, 3543, 3388, 3326, + 4095, 0, 4095, 4095, 4095, 1416, 4095, 2131, 810, 0, 0, 4095, + 4095, 1250, 0, 0, 4095, 2722, 1493, 4095, 0, 4095, 0, 2895, + 0, 3847, 0, 2078, 0, 0, 0, 4095, 4095, 4095, 4095, 0, + 4095, 2651, 4095, 4095, 351, 2675, 4095, 0, 858, 0, 0, 0, + 816, 4095, 0, 4095, 0, 3842, 1990, 593, 0, 0, 3992, 4095, + 4095, 0, 4095, 1314, 4095, 4095, 1864, 2561, 4095, 1339, 0, 4095, + 2201, 4095, 0, 1403, 0, 0, 4095, 4095, 4095, 0, 0, 0, + 0, 0, 0, 577, 4095, 995, 2534, 827, 1431, 4095, 4095, 778, + 1405, 0, 0, 4095, 0, 4095, 1327, 4095, 0, 2725, 3351, 3937, + 741, 0, 2690, 2849, 4095, 4095, 2151, 0, 4095, 0, 4095, 4095, + 4095, 1342, 142, 1920, 1007, 2001 + }; + unsigned char *img_data = + reinterpret_cast(const_cast(buffer)); + + aom_image_t img; + EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I42016, kWidth, kHeight, 1, + img_data)); + img.cp = AOM_CICP_CP_UNSPECIFIED; + img.tc = AOM_CICP_TC_UNSPECIFIED; + img.mc = AOM_CICP_MC_UNSPECIFIED; + img.monochrome = 1; + img.csp = AOM_CSP_UNKNOWN; + img.range = AOM_CR_FULL_RANGE; + img.planes[1] = img.planes[2] = nullptr; + img.stride[1] = img.stride[2] = 0; + + aom_codec_iface_t *iface = aom_codec_av1_cx(); + aom_codec_enc_cfg_t cfg; + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY)); + cfg.rc_end_usage = AOM_Q; + cfg.g_profile = 2; + cfg.g_bit_depth = AOM_BITS_12; + cfg.g_input_bit_depth = 12; + cfg.g_w = kWidth; + cfg.g_h = kHeight; + cfg.g_lag_in_frames = 0; + cfg.g_threads = 53; + cfg.monochrome = 1; + cfg.rc_min_quantizer = 22; + cfg.rc_max_quantizer = 30; + aom_codec_ctx_t enc; + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_enc_init(&enc, iface, &cfg, AOM_CODEC_USE_HIGHBITDEPTH)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 26)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AV1E_SET_TILE_ROWS, 3)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6)); + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE)); + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIM)); + + // Encode frame + EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); + aom_codec_iter_t iter = nullptr; + const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter); + ASSERT_NE(pkt, nullptr); + EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); + // pkt->data.frame.flags is 0x1f0011. + EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY); + pkt = aom_codec_get_cx_data(&enc, &iter); + EXPECT_EQ(pkt, nullptr); + + // Encode frame + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_encode(&enc, &img, 0, 1, AOM_EFLAG_FORCE_KF)); + iter = nullptr; + pkt = aom_codec_get_cx_data(&enc, &iter); + ASSERT_NE(pkt, nullptr); + EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); + // pkt->data.frame.flags is 0x1f0011. + EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY); + pkt = aom_codec_get_cx_data(&enc, &iter); + EXPECT_EQ(pkt, nullptr); + + // Encode frame + EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); + iter = nullptr; + pkt = aom_codec_get_cx_data(&enc, &iter); + ASSERT_NE(pkt, nullptr); + EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); + pkt = aom_codec_get_cx_data(&enc, &iter); + EXPECT_EQ(pkt, nullptr); + + // Encode frame + EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); + iter = nullptr; + pkt = aom_codec_get_cx_data(&enc, &iter); + ASSERT_NE(pkt, nullptr); + EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); + pkt = aom_codec_get_cx_data(&enc, &iter); + EXPECT_EQ(pkt, nullptr); + + // Flush encoder + EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0)); + iter = nullptr; + pkt = aom_codec_get_cx_data(&enc, &iter); + EXPECT_EQ(pkt, nullptr); + + EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); +} + // A test that reproduces b/272139363: signed integer overflow in // update_b_sep_sym(). TEST(SearchWienerTest, 10bitSignedIntegerOverflowInUpdateBSepSym) { @@ -1164,6 +1391,161 @@ TEST(SearchWienerTest, 10bitSignedIntegerOverflowInUpdateBSepSym) { EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); } +// A test that reproduces b/319140742: signed integer overflow in +// update_b_sep_sym(). +TEST(SearchWienerTest, 10bitSignedIntegerOverflowInUpdateBSepSym2) { + constexpr int kWidth = 326; + constexpr int kHeight = 3; + static const uint16_t buffer[kWidth * kHeight] = { + // Y plane: + 1023, 1023, 0, 1023, 1023, 0, 623, 0, 0, 1023, 1023, 0, + 0, 0, 0, 523, 1023, 2, 0, 0, 863, 1023, 1023, 409, + 7, 1023, 0, 409, 1023, 0, 579, 1023, 1023, 1023, 0, 0, + 1023, 1023, 446, 1023, 1023, 0, 0, 1023, 0, 0, 829, 1023, + 0, 1023, 939, 0, 0, 23, 1022, 990, 1023, 0, 0, 4, + 0, 299, 0, 0, 1023, 1023, 629, 688, 1023, 1023, 266, 1023, + 865, 0, 413, 0, 267, 0, 0, 69, 1023, 866, 1023, 885, + 0, 762, 330, 382, 0, 1023, 1023, 734, 504, 899, 119, 0, + 378, 1011, 0, 0, 1023, 364, 0, 1023, 1023, 462, 1023, 0, + 504, 1023, 1023, 0, 695, 1023, 57, 1023, 1023, 362, 0, 0, + 0, 0, 1023, 1023, 387, 12, 929, 1023, 0, 194, 1023, 0, + 1023, 505, 0, 1023, 1023, 1023, 1023, 1023, 0, 0, 676, 0, + 6, 683, 70, 0, 0, 1023, 226, 1023, 320, 758, 0, 0, + 648, 1023, 867, 550, 630, 960, 1023, 1023, 1023, 0, 0, 822, + 0, 0, 0, 1023, 1011, 1023, 1023, 0, 0, 15, 30, 0, + 1023, 1023, 0, 0, 0, 84, 954, 1023, 933, 416, 333, 323, + 0, 0, 1023, 355, 1023, 176, 1023, 1023, 886, 87, 1023, 0, + 1023, 1023, 1023, 562, 0, 1023, 1023, 354, 0, 0, 1023, 0, + 86, 0, 0, 1023, 0, 1023, 192, 0, 1023, 0, 1023, 0, + 0, 0, 735, 1023, 1023, 1023, 0, 372, 988, 131, 1023, 1023, + 0, 1023, 1023, 1023, 1023, 970, 1023, 1023, 248, 757, 665, 330, + 223, 273, 0, 274, 1023, 0, 1023, 613, 786, 1023, 792, 0, + 390, 282, 0, 1023, 0, 1023, 0, 1023, 1023, 1023, 614, 993, + 135, 737, 662, 0, 1023, 524, 970, 1023, 0, 906, 1023, 1023, + 959, 1023, 1023, 1023, 1023, 836, 838, 0, 0, 0, 0, 0, + 1023, 917, 492, 290, 1023, 1023, 817, 1023, 0, 0, 588, 410, + 419, 0, 1023, 1023, 178, 0, 0, 563, 775, 977, 1023, 1023, + 0, 1023, 0, 370, 434, 1023, 963, 587, 0, 0, 1023, 1023, + 1023, 1023, 1023, 1023, 619, 0, 1023, 352, 1023, 0, 0, 0, + 133, 557, 36, 1023, 1023, 1023, 0, 469, 1023, 1023, 0, 900, + 59, 841, 1023, 886, 0, 193, 126, 263, 119, 629, 0, 1023, + 0, 1023, 0, 0, 478, 0, 1023, 63, 1023, 0, 0, 0, + 0, 0, 0, 0, 1023, 888, 1023, 905, 646, 0, 0, 1023, + 752, 1023, 1023, 0, 1023, 0, 0, 648, 1023, 0, 0, 838, + 0, 321, 1023, 475, 0, 215, 867, 1023, 0, 1023, 1023, 624, + 417, 1023, 426, 0, 0, 960, 1020, 839, 687, 1023, 161, 1023, + 1023, 1023, 1023, 968, 0, 95, 430, 0, 132, 1023, 1023, 113, + 0, 1023, 1023, 606, 1023, 0, 0, 31, 1023, 1023, 0, 180, + 140, 654, 1023, 1023, 1023, 1023, 1023, 779, 1023, 0, 0, 1023, + 1023, 1023, 0, 1023, 0, 0, 1023, 963, 723, 536, 1023, 0, + 0, 0, 337, 812, 0, 0, 0, 428, 48, 0, 321, 205, + 0, 587, 799, 272, 5, 1023, 322, 0, 761, 0, 749, 1023, + 0, 0, 1023, 1023, 1023, 1023, 242, 402, 98, 0, 1023, 884, + 219, 1023, 0, 1023, 0, 0, 0, 106, 1023, 0, 1023, 414, + 1023, 0, 1023, 619, 0, 0, 973, 854, 82, 1023, 1023, 1023, + 0, 1023, 1023, 0, 0, 588, 433, 0, 0, 961, 0, 0, + 0, 917, 859, 461, 455, 68, 1023, 409, 1023, 821, 1023, 487, + 1023, 0, 717, 0, 613, 0, 0, 840, 932, 782, 1023, 1023, + 576, 1023, 0, 1023, 1023, 187, 876, 162, 0, 1023, 1023, 946, + 873, 0, 0, 953, 0, 537, 0, 0, 1023, 193, 807, 756, + 0, 0, 1023, 732, 1023, 1023, 1023, 0, 0, 1023, 1023, 1023, + 1023, 1023, 119, 0, 0, 90, 1023, 0, 1023, 0, 0, 0, + 1023, 366, 1023, 655, 0, 58, 1023, 1023, 8, 1023, 1023, 24, + 1023, 103, 0, 0, 1023, 919, 1023, 566, 1023, 0, 0, 480, + 1023, 1023, 0, 0, 807, 0, 1023, 0, 273, 412, 632, 1023, + 1023, 1023, 10, 633, 1023, 692, 978, 0, 0, 1023, 1023, 1023, + 25, 494, 215, 0, 148, 1023, 840, 118, 1023, 1023, 999, 1023, + 1023, 1023, 0, 0, 1023, 435, 894, 0, 1023, 1023, 168, 1023, + 1023, 211, 1023, 1023, 656, 1023, 0, 0, 0, 744, 238, 1023, + 0, 196, 907, 0, 0, 0, 838, 726, 1023, 1023, 1023, 0, + 0, 0, 1023, 0, 1023, 1023, 1023, 0, 1023, 0, 0, 0, + 323, 1023, 1023, 0, 1023, 0, 0, 925, 582, 1023, 0, 685, + 1023, 661, 464, 0, 0, 0, 1023, 0, 807, 0, 1023, 1023, + 1023, 100, 0, 1023, 302, 1023, 1023, 1023, 616, 0, 1023, 0, + 0, 377, 1023, 1023, 1023, 0, 1023, 555, 1023, 784, 0, 0, + 1023, 0, 0, 1023, 755, 0, 839, 1023, 0, 0, 0, 1023, + 1023, 1023, 0, 1023, 413, 0, 1023, 1023, 384, 0, 823, 797, + 1023, 0, 1023, 0, 0, 1023, 1023, 1023, 1023, 0, 1023, 39, + 0, 473, 299, 0, 0, 1023, 567, 1023, 1023, 0, 0, 1023, + 650, 1023, 41, 1023, 0, 1023, 0, 1023, 0, 1023, 0, 0, + 444, 1023, 23, 0, 503, 97, 0, 1023, 0, 890, 59, 578, + 0, 201, 1023, 672, 1023, 593, 1023, 599, 213, 1023, 1023, 1023, + 986, 1023, 335, 1023, 457, 0, 888, 1023, 1023, 97, 308, 259, + 813, 1023, 1023, 1023, 0, 1023, 798, 907, 105, 0, 1023, 0, + 1023, 1023, 0, 970, 518, 0, 635, 0, 634, 329, 1023, 430, + 0, 17, 1023, 1023, 1023, 0, 0, 407, 1023, 1023, 0, 1023, + 0, 0, 0, 0, 1023, 1023, 1023, 402, 1023, 0, 0, 101, + 1023, 1023, 1023, 1023, 1023, 1023, 425, 791, 1023, 1023, 961, 0, + 0, 1023, 474, 1023, 1023, 1023, 1023, 468, 1023, 1023, 0, 1023, + 215, 0, 1023, 1023, 334, 463, 286, 1023, 0, 1023, 0, 1023, + 270, 401, 0, 0, 1023, 0, 794, 0, 0, 0, 1023, 0, + 1023, 172, 317, 905, 950, 0 + }; + unsigned char *img_data = + reinterpret_cast(const_cast(buffer)); + + aom_image_t img; + EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I42016, kWidth, kHeight, 1, + img_data)); + img.cp = AOM_CICP_CP_UNSPECIFIED; + img.tc = AOM_CICP_TC_UNSPECIFIED; + img.mc = AOM_CICP_MC_UNSPECIFIED; + img.monochrome = 1; + img.csp = AOM_CSP_UNKNOWN; + img.range = AOM_CR_FULL_RANGE; + img.planes[1] = img.planes[2] = nullptr; + img.stride[1] = img.stride[2] = 0; + + aom_codec_iface_t *iface = aom_codec_av1_cx(); + aom_codec_enc_cfg_t cfg; + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY)); + cfg.rc_end_usage = AOM_Q; + cfg.g_profile = 0; + cfg.g_bit_depth = AOM_BITS_10; + cfg.g_input_bit_depth = 10; + cfg.g_w = kWidth; + cfg.g_h = kHeight; + cfg.g_threads = 6; + cfg.monochrome = 1; + cfg.rc_min_quantizer = 54; + cfg.rc_max_quantizer = 62; + aom_codec_ctx_t enc; + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_enc_init(&enc, iface, &cfg, AOM_CODEC_USE_HIGHBITDEPTH)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 58)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AV1E_SET_TILE_ROWS, 1)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6)); + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE)); + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIM)); + + // Encode frame + EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); + aom_codec_iter_t iter = nullptr; + const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter); + ASSERT_EQ(pkt, nullptr); + + // Flush encoder + EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0)); + iter = nullptr; + pkt = aom_codec_get_cx_data(&enc, &iter); + ASSERT_NE(pkt, nullptr); + EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); + // pkt->data.frame.flags is 0x1f0011. + EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY); + pkt = aom_codec_get_cx_data(&enc, &iter); + EXPECT_EQ(pkt, nullptr); + + EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0)); + iter = nullptr; + pkt = aom_codec_get_cx_data(&enc, &iter); + EXPECT_EQ(pkt, nullptr); + + EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); +} + // A test that reproduces b/277121724: signed integer overflow in // update_b_sep_sym(). TEST(SearchWienerTest, 8bitSignedIntegerOverflowInUpdateBSepSym) { diff --git a/third_party/aom/third_party/libwebm/README.libaom b/third_party/aom/third_party/libwebm/README.libaom index ee350a523a..1eb0ce9a94 100644 --- a/third_party/aom/third_party/libwebm/README.libaom +++ b/third_party/aom/third_party/libwebm/README.libaom @@ -1,5 +1,5 @@ URL: https://chromium.googlesource.com/webm/libwebm -Version: 1930e3ca23b007f3ff11d98a570077be6201957e +Version: affd7f4d9644aa2b65981fa6c7616400be760e6e License: BSD License File: LICENSE.TXT diff --git a/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.cc b/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.cc index faaf0165f4..21e51be474 100644 --- a/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.cc +++ b/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.cc @@ -65,7 +65,8 @@ bool StrCpy(const char* src, char** dst_ptr) { if (dst == NULL) return false; - strcpy(dst, src); // NOLINT + memcpy(dst, src, size - 1); + dst[size - 1] = '\0'; return true; } @@ -919,11 +920,8 @@ void Track::set_codec_id(const char* codec_id) { const size_t length = strlen(codec_id) + 1; codec_id_ = new (std::nothrow) char[length]; // NOLINT if (codec_id_) { -#ifdef _MSC_VER - strcpy_s(codec_id_, length, codec_id); -#else - strcpy(codec_id_, codec_id); -#endif + memcpy(codec_id_, codec_id, length - 1); + codec_id_[length - 1] = '\0'; } } } @@ -936,11 +934,8 @@ void Track::set_language(const char* language) { const size_t length = strlen(language) + 1; language_ = new (std::nothrow) char[length]; // NOLINT if (language_) { -#ifdef _MSC_VER - strcpy_s(language_, length, language); -#else - strcpy(language_, language); -#endif + memcpy(language_, language, length - 1); + language_[length - 1] = '\0'; } } } @@ -952,11 +947,8 @@ void Track::set_name(const char* name) { const size_t length = strlen(name) + 1; name_ = new (std::nothrow) char[length]; // NOLINT if (name_) { -#ifdef _MSC_VER - strcpy_s(name_, length, name); -#else - strcpy(name_, name); -#endif + memcpy(name_, name, length - 1); + name_[length - 1] = '\0'; } } } @@ -1559,11 +1551,8 @@ void VideoTrack::set_colour_space(const char* colour_space) { const size_t length = strlen(colour_space) + 1; colour_space_ = new (std::nothrow) char[length]; // NOLINT if (colour_space_) { -#ifdef _MSC_VER - strcpy_s(colour_space_, length, colour_space); -#else - strcpy(colour_space_, colour_space); -#endif + memcpy(colour_space_, colour_space, length - 1); + colour_space_[length - 1] = '\0'; } } } @@ -2856,13 +2845,13 @@ bool SeekHead::AddSeekEntry(uint32_t id, uint64_t pos) { uint32_t SeekHead::GetId(int index) const { if (index < 0 || index >= kSeekEntryCount) - return UINT_MAX; + return UINT32_MAX; return seek_entry_id_[index]; } uint64_t SeekHead::GetPosition(int index) const { if (index < 0 || index >= kSeekEntryCount) - return ULLONG_MAX; + return UINT64_MAX; return seek_entry_pos_[index]; } @@ -2896,7 +2885,7 @@ SegmentInfo::SegmentInfo() muxing_app_(NULL), timecode_scale_(1000000ULL), writing_app_(NULL), - date_utc_(LLONG_MIN), + date_utc_(INT64_MIN), duration_pos_(-1) {} SegmentInfo::~SegmentInfo() { @@ -2927,11 +2916,8 @@ bool SegmentInfo::Init() { if (!muxing_app_) return false; -#ifdef _MSC_VER - strcpy_s(muxing_app_, app_len, temp); -#else - strcpy(muxing_app_, temp); -#endif + memcpy(muxing_app_, temp, app_len - 1); + muxing_app_[app_len - 1] = '\0'; set_writing_app(temp); if (!writing_app_) @@ -2974,7 +2960,7 @@ bool SegmentInfo::Write(IMkvWriter* writer) { if (duration_ > 0.0) size += EbmlElementSize(libwebm::kMkvDuration, static_cast(duration_)); - if (date_utc_ != LLONG_MIN) + if (date_utc_ != INT64_MIN) size += EbmlDateElementSize(libwebm::kMkvDateUTC); size += EbmlElementSize(libwebm::kMkvMuxingApp, muxing_app_); size += EbmlElementSize(libwebm::kMkvWritingApp, writing_app_); @@ -2999,7 +2985,7 @@ bool SegmentInfo::Write(IMkvWriter* writer) { return false; } - if (date_utc_ != LLONG_MIN) + if (date_utc_ != INT64_MIN) WriteEbmlDateElement(writer, libwebm::kMkvDateUTC, date_utc_); if (!WriteEbmlElement(writer, libwebm::kMkvMuxingApp, muxing_app_)) @@ -3022,11 +3008,8 @@ void SegmentInfo::set_muxing_app(const char* app) { if (!temp_str) return; -#ifdef _MSC_VER - strcpy_s(temp_str, length, app); -#else - strcpy(temp_str, app); -#endif + memcpy(temp_str, app, length - 1); + temp_str[length - 1] = '\0'; delete[] muxing_app_; muxing_app_ = temp_str; @@ -3040,11 +3023,8 @@ void SegmentInfo::set_writing_app(const char* app) { if (!temp_str) return; -#ifdef _MSC_VER - strcpy_s(temp_str, length, app); -#else - strcpy(temp_str, app); -#endif + memcpy(temp_str, app, length - 1); + temp_str[length - 1] = '\0'; delete[] writing_app_; writing_app_ = temp_str; @@ -3628,19 +3608,17 @@ bool Segment::SetChunking(bool chunking, const char* filename) { if (chunking_ && !strcmp(filename, chunking_base_name_)) return true; - const size_t name_length = strlen(filename) + 1; - char* const temp = new (std::nothrow) char[name_length]; // NOLINT + const size_t filename_length = strlen(filename); + char* const temp = new (std::nothrow) char[filename_length + 1]; // NOLINT if (!temp) return false; -#ifdef _MSC_VER - strcpy_s(temp, name_length, filename); -#else - strcpy(temp, filename); -#endif + memcpy(temp, filename, filename_length); + temp[filename_length] = '\0'; delete[] chunking_base_name_; chunking_base_name_ = temp; + // From this point, strlen(chunking_base_name_) == filename_length if (!UpdateChunkName("chk", &chunk_name_)) return false; @@ -3666,18 +3644,16 @@ bool Segment::SetChunking(bool chunking, const char* filename) { if (!chunk_writer_cluster_->Open(chunk_name_)) return false; - const size_t header_length = strlen(filename) + strlen(".hdr") + 1; + const size_t hdr_length = strlen(".hdr"); + const size_t header_length = filename_length + hdr_length + 1; char* const header = new (std::nothrow) char[header_length]; // NOLINT if (!header) return false; -#ifdef _MSC_VER - strcpy_s(header, header_length - strlen(".hdr"), chunking_base_name_); - strcat_s(header, header_length, ".hdr"); -#else - strcpy(header, chunking_base_name_); - strcat(header, ".hdr"); -#endif + memcpy(header, chunking_base_name_, filename_length); + memcpy(&header[filename_length], ".hdr", hdr_length); + header[filename_length + hdr_length] = '\0'; + if (!chunk_writer_header_->Open(header)) { delete[] header; return false; @@ -4022,18 +3998,16 @@ bool Segment::UpdateChunkName(const char* ext, char** name) const { snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext); #endif - const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1; + const size_t chunking_base_name_length = strlen(chunking_base_name_); + const size_t ext_chk_length = strlen(ext_chk); + const size_t length = chunking_base_name_length + ext_chk_length + 1; char* const str = new (std::nothrow) char[length]; // NOLINT if (!str) return false; -#ifdef _MSC_VER - strcpy_s(str, length - strlen(ext_chk), chunking_base_name_); - strcat_s(str, length, ext_chk); -#else - strcpy(str, chunking_base_name_); - strcat(str, ext_chk); -#endif + memcpy(str, chunking_base_name_, chunking_base_name_length); + memcpy(&str[chunking_base_name_length], ext_chk, ext_chk_length); + str[chunking_base_name_length + ext_chk_length] = '\0'; delete[] * name; *name = str; diff --git a/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.h b/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.h index 8602d82325..2c4bb9e93e 100644 --- a/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.h +++ b/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.h @@ -1481,7 +1481,7 @@ class SegmentInfo { uint64_t timecode_scale_; // Initially set to libwebm-%d.%d.%d.%d, major, minor, build, revision. char* writing_app_; - // LLONG_MIN when DateUTC is not set. + // INT64_MIN when DateUTC is not set. int64_t date_utc_; // The file position of the duration element. diff --git a/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc b/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc index 300b155797..f538310e21 100644 --- a/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc +++ b/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc @@ -607,22 +607,18 @@ uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) { void GetVersion(int32* major, int32* minor, int32* build, int32* revision) { *major = 0; *minor = 3; - *build = 1; + *build = 3; *revision = 0; } uint64 MakeUID(unsigned int* seed) { uint64 uid = 0; -#ifdef __MINGW32__ - srand(*seed); -#endif - for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values uid <<= 8; // TODO(fgalligan): Move random number generation to platform specific code. -#ifdef _MSC_VER +#ifdef _WIN32 (void)seed; const int32 nn = rand(); #elif __ANDROID__ @@ -634,8 +630,6 @@ uint64 MakeUID(unsigned int* seed) { close(fd); } const int32 nn = temp_num; -#elif defined __MINGW32__ - const int32 nn = rand(); #else const int32 nn = rand_r(seed); #endif diff --git a/third_party/aom/third_party/libwebm/mkvparser/mkvparser.cc b/third_party/aom/third_party/libwebm/mkvparser/mkvparser.cc index 868afcb3ed..eddbc7eb50 100644 --- a/third_party/aom/third_party/libwebm/mkvparser/mkvparser.cc +++ b/third_party/aom/third_party/libwebm/mkvparser/mkvparser.cc @@ -55,7 +55,7 @@ Type* SafeArrayAlloc(unsigned long long num_elements, void GetVersion(int& major, int& minor, int& build, int& revision) { major = 1; minor = 1; - build = 1; + build = 3; revision = 0; } @@ -246,7 +246,8 @@ long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_, if (size == 4) { union { float f; - unsigned long ff; + uint32_t ff; + static_assert(sizeof(float) == sizeof(uint32_t), ""); }; ff = 0; @@ -264,7 +265,8 @@ long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_, } else { union { double d; - unsigned long long dd; + uint64_t dd; + static_assert(sizeof(double) == sizeof(uint64_t), ""); }; dd = 0; @@ -4569,7 +4571,8 @@ int Track::Info::CopyStr(char* Info::*str, Info& dst_) const { if (dst == NULL) return -1; - strcpy(dst, src); + memcpy(dst, src, len); + dst[len] = '\0'; return 0; } diff --git a/third_party/content_analysis_sdk/.gitignore b/third_party/content_analysis_sdk/.gitignore deleted file mode 100644 index 0ab461830e..0000000000 --- a/third_party/content_analysis_sdk/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.vscode/ -.ccls-cache/ -.cache/ -build/ -*.bak -*.swp diff --git a/third_party/content_analysis_sdk/agent/src/event_win.cc b/third_party/content_analysis_sdk/agent/src/event_win.cc index 907bdfb858..99b4233237 100644 --- a/third_party/content_analysis_sdk/agent/src/event_win.cc +++ b/third_party/content_analysis_sdk/agent/src/event_win.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include -#include #include #include diff --git a/third_party/content_analysis_sdk/agent_improvements.patch b/third_party/content_analysis_sdk/agent_improvements.patch new file mode 100644 index 0000000000..c1475caded --- /dev/null +++ b/third_party/content_analysis_sdk/agent_improvements.patch @@ -0,0 +1,480 @@ +commit 4ad63eb3aa65ce7baa08190aac2770540dc25f43 +Author: Greg Stoll +Date: Wed, 27 Mar 2024 12:13:56 -0500 + + Mozilla improvements to content_analysis_sdk + + - add ability for demo agent to block/warn/report specific regexes + - add ability for demo agent to chose a sequence of delays to apply + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 39477223f031c..5dacc81031117 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -203,6 +203,7 @@ add_executable(agent + ./demo/agent.cc + ./demo/handler.h + ) ++target_compile_features(agent PRIVATE cxx_std_17) + target_include_directories(agent PRIVATE ${AGENT_INCLUDES}) + target_link_libraries(agent PRIVATE cac_agent) + +diff --git a/agent/src/event_win.h b/agent/src/event_win.h +index 9f8b6903566f2..f631f693dcd9c 100644 +--- a/agent/src/event_win.h ++++ b/agent/src/event_win.h +@@ -28,6 +28,12 @@ class ContentAnalysisEventWin : public ContentAnalysisEventBase { + ResultCode Close() override; + ResultCode Send() override; + std::string DebugString() const override; ++ std::string SerializeStringToSendToBrowser() { ++ return agent_to_chrome()->SerializeAsString(); ++ } ++ void SetResponseSent() { response_sent_ = true; } ++ ++ HANDLE Pipe() const { return hPipe_; } + + private: + void Shutdown(); +diff --git a/browser/src/client_win.cc b/browser/src/client_win.cc +index 9d3d7e8c52662..039946d131398 100644 +--- a/browser/src/client_win.cc ++++ b/browser/src/client_win.cc +@@ -418,7 +418,11 @@ DWORD ClientWin::ConnectToPipe(const std::string& pipename, HANDLE* handle) { + + void ClientWin::Shutdown() { + if (hPipe_ != INVALID_HANDLE_VALUE) { +- FlushFileBuffers(hPipe_); ++ // TODO: This trips the LateWriteObserver. We could move this earlier ++ // (before the LateWriteObserver is created) or just remove it, although ++ // the later could mean an ACK message is not processed by the agent ++ // in time. ++ // FlushFileBuffers(hPipe_); + CloseHandle(hPipe_); + hPipe_ = INVALID_HANDLE_VALUE; + } +diff --git a/demo/agent.cc b/demo/agent.cc +index ff8b93f647ebd..3e168b0915a0c 100644 +--- a/demo/agent.cc ++++ b/demo/agent.cc +@@ -2,12 +2,18 @@ + // Use of this source code is governed by a BSD-style license that can be + // found in the LICENSE file. + ++#include + #include + #include + #include ++#include ++#include + + #include "content_analysis/sdk/analysis_agent.h" + #include "demo/handler.h" ++#include "demo/handler_misbehaving.h" ++ ++using namespace content_analysis::sdk; + + // Different paths are used depending on whether this agent should run as a + // use specific agent or not. These values are chosen to match the test +@@ -19,19 +25,50 @@ constexpr char kPathSystem[] = "brcm_chrm_cas"; + std::string path = kPathSystem; + bool use_queue = false; + bool user_specific = false; +-unsigned long delay = 0; // In seconds. ++std::vector delays = {0}; // In seconds. + unsigned long num_threads = 8u; + std::string save_print_data_path = ""; ++RegexArray toBlock, toWarn, toReport; ++static bool useMisbehavingHandler = false; ++static std::string modeStr; + + // Command line parameters. +-constexpr const char* kArgDelaySpecific = "--delay="; ++constexpr const char* kArgDelaySpecific = "--delays="; + constexpr const char* kArgPath = "--path="; + constexpr const char* kArgQueued = "--queued"; + constexpr const char* kArgThreads = "--threads="; + constexpr const char* kArgUserSpecific = "--user"; ++constexpr const char* kArgToBlock = "--toblock="; ++constexpr const char* kArgToWarn = "--towarn="; ++constexpr const char* kArgToReport = "--toreport="; ++constexpr const char* kArgMisbehave = "--misbehave="; + constexpr const char* kArgHelp = "--help"; + constexpr const char* kArgSavePrintRequestDataTo = "--save-print-request-data-to="; + ++std::map sStringToMode = { ++#define AGENT_MODE(name) {#name, Mode::Mode_##name}, ++#include "modes.h" ++#undef AGENT_MODE ++}; ++ ++std::map sModeToString = { ++#define AGENT_MODE(name) {Mode::Mode_##name, #name}, ++#include "modes.h" ++#undef AGENT_MODE ++}; ++ ++std::vector> ++ParseRegex(const std::string str) { ++ std::vector> ret; ++ for (auto it = str.begin(); it != str.end(); /* nop */) { ++ auto it2 = std::find(it, str.end(), ','); ++ ret.push_back(std::make_pair(std::string(it, it2), std::regex(it, it2))); ++ it = it2 == str.end() ? it2 : it2 + 1; ++ } ++ ++ return ret; ++} ++ + bool ParseCommandLine(int argc, char* argv[]) { + for (int i = 1; i < argc; ++i) { + const std::string arg = argv[i]; +@@ -44,16 +81,38 @@ bool ParseCommandLine(int argc, char* argv[]) { + path = kPathUser; + user_specific = true; + } else if (arg.find(kArgDelaySpecific) == 0) { +- delay = std::stoul(arg.substr(strlen(kArgDelaySpecific))); ++ std::string delaysStr = arg.substr(strlen(kArgDelaySpecific)); ++ delays.clear(); ++ size_t posStart = 0, posEnd; ++ unsigned long delay; ++ while ((posEnd = delaysStr.find(',', posStart)) != std::string::npos) { ++ delay = std::stoul(delaysStr.substr(posStart, posEnd - posStart)); ++ if (delay > 30) { ++ delay = 30; ++ } ++ delays.push_back(delay); ++ posStart = posEnd + 1; ++ } ++ delay = std::stoul(delaysStr.substr(posStart)); + if (delay > 30) { + delay = 30; + } ++ delays.push_back(delay); + } else if (arg.find(kArgPath) == 0) { + path = arg.substr(strlen(kArgPath)); + } else if (arg.find(kArgQueued) == 0) { + use_queue = true; + } else if (arg.find(kArgThreads) == 0) { + num_threads = std::stoul(arg.substr(strlen(kArgThreads))); ++ } else if (arg.find(kArgToBlock) == 0) { ++ toBlock = ParseRegex(arg.substr(strlen(kArgToBlock))); ++ } else if (arg.find(kArgToWarn) == 0) { ++ toWarn = ParseRegex(arg.substr(strlen(kArgToWarn))); ++ } else if (arg.find(kArgToReport) == 0) { ++ toReport = ParseRegex(arg.substr(strlen(kArgToReport))); ++ } else if (arg.find(kArgMisbehave) == 0) { ++ modeStr = arg.substr(strlen(kArgMisbehave)); ++ useMisbehavingHandler = true; + } else if (arg.find(kArgHelp) == 0) { + return false; + } else if (arg.find(kArgSavePrintRequestDataTo) == 0) { +@@ -72,13 +131,17 @@ void PrintHelp() { + << "A simple agent to process content analysis requests." << std::endl + << "Data containing the string 'block' blocks the request data from being used." << std::endl + << std::endl << "Options:" << std::endl +- << kArgDelaySpecific << " : Add a delay to request processing in seconds (max 30)." << std::endl ++ << kArgDelaySpecific << " : Add delays to request processing in seconds. Delays are limited to 30 seconds and are applied round-robin to requests. Default is 0." << std::endl + << kArgPath << " : Used the specified path instead of default. Must come after --user." << std::endl + << kArgQueued << " : Queue requests for processing in a background thread" << std::endl + << kArgThreads << " : When queued, number of threads in the request processing thread pool" << std::endl + << kArgUserSpecific << " : Make agent OS user specific." << std::endl + << kArgHelp << " : prints this help message" << std::endl +- << kArgSavePrintRequestDataTo << " : saves the PDF data to the given file path for print requests"; ++ << kArgSavePrintRequestDataTo << " : saves the PDF data to the given file path for print requests" << std::endl ++ << kArgToBlock << " : Regular expression matching file and text content to block." << std::endl ++ << kArgToWarn << " : Regular expression matching file and text content to warn about." << std::endl ++ << kArgToReport << " : Regular expression matching file and text content to report." << std::endl ++ << kArgMisbehave << " : Use 'misbehaving' agent in given mode for testing purposes." << std::endl; + } + + int main(int argc, char* argv[]) { +@@ -87,9 +150,17 @@ int main(int argc, char* argv[]) { + return 1; + } + +- auto handler = use_queue +- ? std::make_unique(num_threads, delay, save_print_data_path) +- : std::make_unique(delay, save_print_data_path); ++ auto handler = ++ useMisbehavingHandler ++ ? MisbehavingHandler::Create(modeStr, std::move(delays), save_print_data_path, std::move(toBlock), std::move(toWarn), std::move(toReport)) ++ : use_queue ++ ? std::make_unique(num_threads, std::move(delays), save_print_data_path, std::move(toBlock), std::move(toWarn), std::move(toReport)) ++ : std::make_unique(std::move(delays), save_print_data_path, std::move(toBlock), std::move(toWarn), std::move(toReport)); ++ ++ if (!handler) { ++ std::cout << "[Demo] Failed to construct handler." << std::endl; ++ return 1; ++ } + + // Each agent uses a unique name to identify itself with Google Chrome. + content_analysis::sdk::ResultCode rc; +diff --git a/demo/handler.h b/demo/handler.h +index 9d1ccfdf9857a..88599963c51b0 100644 +--- a/demo/handler.h ++++ b/demo/handler.h +@@ -7,31 +7,51 @@ + + #include + ++#include ++#include + #include + #include + #include + #include ++#include + #include + #include ++#include + #include + + #include "content_analysis/sdk/analysis_agent.h" + #include "demo/atomic_output.h" + #include "demo/request_queue.h" + ++using RegexArray = std::vector>; ++ + // An AgentEventHandler that dumps requests information to stdout and blocks + // any requests that have the keyword "block" in their data + class Handler : public content_analysis::sdk::AgentEventHandler { + public: + using Event = content_analysis::sdk::ContentAnalysisEvent; + +- Handler(unsigned long delay, const std::string& print_data_file_path) : +- delay_(delay), print_data_file_path_(print_data_file_path) { +- } ++ Handler(std::vector&& delays, const std::string& print_data_file_path, ++ RegexArray&& toBlock = RegexArray(), ++ RegexArray&& toWarn = RegexArray(), ++ RegexArray&& toReport = RegexArray()) : ++ toBlock_(std::move(toBlock)), toWarn_(std::move(toWarn)), toReport_(std::move(toReport)), ++ delays_(std::move(delays)), print_data_file_path_(print_data_file_path) {} + +- unsigned long delay() { return delay_; } ++ const std::vector delays() { return delays_; } ++ size_t nextDelayIndex() const { return nextDelayIndex_; } + + protected: ++ // subclasses can override this ++ // returns whether the response has been set ++ virtual bool SetCustomResponse(AtomicCout& aout, std::unique_ptr& event) { ++ return false; ++ } ++ // subclasses can override this ++ // returns whether the response has been sent ++ virtual bool SendCustomResponse(std::unique_ptr& event) { ++ return false; ++ } + // Analyzes one request from Google Chrome and responds back to the browser + // with either an allow or block verdict. + void AnalyzeContent(AtomicCout& aout, std::unique_ptr event) { +@@ -43,29 +63,25 @@ class Handler : public content_analysis::sdk::AgentEventHandler { + + DumpEvent(aout.stream(), event.get()); + +- bool block = false; + bool success = true; +- unsigned long delay = delay_; +- +- if (event->GetRequest().has_text_content()) { +- block = ShouldBlockRequest( +- event->GetRequest().text_content()); +- GetFileSpecificDelay(event->GetRequest().text_content(), &delay); +- } else if (event->GetRequest().has_file_path()) { +- std::string content; +- success = +- ReadContentFromFile(event->GetRequest().file_path(), +- &content); +- if (success) { +- block = ShouldBlockRequest(content); +- GetFileSpecificDelay(content, &delay); ++ std::optional caResponse; ++ bool setResponse = SetCustomResponse(aout, event); ++ if (!setResponse) { ++ caResponse = content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_BLOCK; ++ if (event->GetRequest().has_text_content()) { ++ caResponse = DecideCAResponse( ++ event->GetRequest().text_content(), aout.stream()); ++ } else if (event->GetRequest().has_file_path()) { ++ // TODO: Fix downloads to store file *first* so we can check contents. ++ // Until then, just check the file name: ++ caResponse = DecideCAResponse( ++ event->GetRequest().file_path(), aout.stream()); ++ } else if (event->GetRequest().has_print_data()) { ++ // In the case of print request, normally the PDF bytes would be parsed ++ // for sensitive data violations. To keep this class simple, only the ++ // URL is checked for the word "block". ++ caResponse = DecideCAResponse(event->GetRequest().request_data().url(), aout.stream()); + } +- } else if (event->GetRequest().has_print_data()) { +- // In the case of print request, normally the PDF bytes would be parsed +- // for sensitive data violations. To keep this class simple, only the +- // URL is checked for the word "block". +- block = ShouldBlockRequest(event->GetRequest().request_data().url()); +- GetFileSpecificDelay(event->GetRequest().request_data().url(), &delay); + } + + if (!success) { +@@ -75,22 +91,44 @@ class Handler : public content_analysis::sdk::AgentEventHandler { + content_analysis::sdk::ContentAnalysisResponse::Result::FAILURE); + aout.stream() << " Verdict: failed to reach verdict: "; + aout.stream() << event->DebugString() << std::endl; +- } else if (block) { +- auto rc = content_analysis::sdk::SetEventVerdictToBlock(event.get()); +- aout.stream() << " Verdict: block"; +- if (rc != content_analysis::sdk::ResultCode::OK) { +- aout.stream() << " error: " +- << content_analysis::sdk::ResultCodeToString(rc) << std::endl; +- aout.stream() << " " << event->DebugString() << std::endl; ++ } else { ++ aout.stream() << " Verdict: "; ++ if (caResponse) { ++ switch (caResponse.value()) { ++ case content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_BLOCK: ++ aout.stream() << "BLOCK"; ++ break; ++ case content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_WARN: ++ aout.stream() << "WARN"; ++ break; ++ case content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_REPORT_ONLY: ++ aout.stream() << "REPORT_ONLY"; ++ break; ++ case content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_ACTION_UNSPECIFIED: ++ aout.stream() << "ACTION_UNSPECIFIED"; ++ break; ++ default: ++ aout.stream() << ""; ++ break; ++ } ++ auto rc = ++ content_analysis::sdk::SetEventVerdictTo(event.get(), caResponse.value()); ++ if (rc != content_analysis::sdk::ResultCode::OK) { ++ aout.stream() << " error: " ++ << content_analysis::sdk::ResultCodeToString(rc) << std::endl; ++ aout.stream() << " " << event->DebugString() << std::endl; ++ } ++ aout.stream() << std::endl; ++ } else { ++ aout.stream() << " Verdict: allow" << std::endl; + } + aout.stream() << std::endl; +- } else { +- aout.stream() << " Verdict: allow" << std::endl; + } +- + aout.stream() << std::endl; + + // If a delay is specified, wait that much. ++ size_t nextDelayIndex = nextDelayIndex_.fetch_add(1); ++ unsigned long delay = delays_[nextDelayIndex % delays_.size()]; + if (delay > 0) { + aout.stream() << "Delaying response to " << event->GetRequest().request_token() + << " for " << delay << "s" << std::endl<< std::endl; +@@ -99,16 +137,19 @@ class Handler : public content_analysis::sdk::AgentEventHandler { + } + + // Send the response back to Google Chrome. +- auto rc = event->Send(); +- if (rc != content_analysis::sdk::ResultCode::OK) { +- aout.stream() << "[Demo] Error sending response: " +- << content_analysis::sdk::ResultCodeToString(rc) +- << std::endl; +- aout.stream() << event->DebugString() << std::endl; ++ bool sentCustomResponse = SendCustomResponse(event); ++ if (!sentCustomResponse) { ++ auto rc = event->Send(); ++ if (rc != content_analysis::sdk::ResultCode::OK) { ++ aout.stream() << "[Demo] Error sending response: " ++ << content_analysis::sdk::ResultCodeToString(rc) ++ << std::endl; ++ aout.stream() << event->DebugString() << std::endl; ++ } + } + } + +- private: ++ protected: + void OnBrowserConnected( + const content_analysis::sdk::BrowserInfo& info) override { + AtomicCout aout; +@@ -362,21 +403,40 @@ class Handler : public content_analysis::sdk::AgentEventHandler { + return true; + } + +- bool ShouldBlockRequest(const std::string& content) { +- // Determines if the request should be blocked. For this simple example +- // the content is blocked if the string "block" is found. Otherwise the +- // content is allowed. +- return content.find("block") != std::string::npos; +- } +- +- void GetFileSpecificDelay(const std::string& content, unsigned long* delay) { +- auto pos = content.find("delay="); +- if (pos != std::string::npos) { +- std::sscanf(content.substr(pos).c_str(), "delay=%lu", delay); ++ std::optional ++ DecideCAResponse(const std::string& content, std::stringstream& stream) { ++ for (auto& r : toBlock_) { ++ if (std::regex_search(content, r.second)) { ++ stream << "'" << content << "' matches BLOCK regex '" ++ << r.first << "'" << std::endl; ++ return content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_BLOCK; ++ } + } ++ for (auto& r : toWarn_) { ++ if (std::regex_search(content, r.second)) { ++ stream << "'" << content << "' matches WARN regex '" ++ << r.first << "'" << std::endl; ++ return content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_WARN; ++ } ++ } ++ for (auto& r : toReport_) { ++ if (std::regex_search(content, r.second)) { ++ stream << "'" << content << "' matches REPORT_ONLY regex '" ++ << r.first << "'" << std::endl; ++ return content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_REPORT_ONLY; ++ } ++ } ++ stream << "'" << content << "' was ALLOWed\n"; ++ return {}; + } + +- unsigned long delay_; ++ // For the demo, block any content that matches these wildcards. ++ RegexArray toBlock_; ++ RegexArray toWarn_; ++ RegexArray toReport_; ++ ++ std::vector delays_; ++ std::atomic nextDelayIndex_; + std::string print_data_file_path_; + }; + +@@ -384,8 +444,11 @@ class Handler : public content_analysis::sdk::AgentEventHandler { + // any requests that have the keyword "block" in their data + class QueuingHandler : public Handler { + public: +- QueuingHandler(unsigned long threads, unsigned long delay, const std::string& print_data_file_path) +- : Handler(delay, print_data_file_path) { ++ QueuingHandler(unsigned long threads, std::vector&& delays, const std::string& print_data_file_path, ++ RegexArray&& toBlock = RegexArray(), ++ RegexArray&& toWarn = RegexArray(), ++ RegexArray&& toReport = RegexArray()) ++ : Handler(std::move(delays), print_data_file_path, std::move(toBlock), std::move(toWarn), std::move(toReport)) { + StartBackgroundThreads(threads); + } + +@@ -421,6 +484,8 @@ class QueuingHandler : public Handler { + aout.stream() << std::endl << "----------" << std::endl; + aout.stream() << "Thread: " << std::this_thread::get_id() + << std::endl; ++ aout.stream() << "Delaying request processing for " ++ << handler->delays()[handler->nextDelayIndex() % handler->delays().size()] << "s" << std::endl << std::endl; + aout.flush(); + + handler->AnalyzeContent(aout, std::move(event)); +-- +2.42.0.windows.2 + diff --git a/third_party/content_analysis_sdk/browser/src/client_mac.cc b/third_party/content_analysis_sdk/browser/src/client_mac.cc index c6f5a798c1..fd0902e516 100644 --- a/third_party/content_analysis_sdk/browser/src/client_mac.cc +++ b/third_party/content_analysis_sdk/browser/src/client_mac.cc @@ -11,7 +11,7 @@ namespace sdk { // static std::unique_ptr Client::Create(Config config) { - return std::make_unique(std::move(config)); + return nullptr; } ClientMac::ClientMac(Config config) : ClientBase(std::move(config)) {} @@ -30,4 +30,4 @@ int ClientMac::CancelRequests(const ContentAnalysisCancelRequests& cancel) { } } // namespace sdk -} // namespace content_analysis \ No newline at end of file +} // namespace content_analysis diff --git a/third_party/content_analysis_sdk/browser/src/client_posix.cc b/third_party/content_analysis_sdk/browser/src/client_posix.cc index 14277724fd..bd62b845a0 100644 --- a/third_party/content_analysis_sdk/browser/src/client_posix.cc +++ b/third_party/content_analysis_sdk/browser/src/client_posix.cc @@ -11,7 +11,7 @@ namespace sdk { // static std::unique_ptr Client::Create(Config config) { - return std::make_unique(std::move(config)); + return nullptr; } ClientPosix::ClientPosix(Config config) : ClientBase(std::move(config)) {} diff --git a/third_party/content_analysis_sdk/demo/agent.cc b/third_party/content_analysis_sdk/demo/agent.cc index c3640018e6..3e168b0915 100644 --- a/third_party/content_analysis_sdk/demo/agent.cc +++ b/third_party/content_analysis_sdk/demo/agent.cc @@ -136,12 +136,12 @@ void PrintHelp() { << kArgQueued << " : Queue requests for processing in a background thread" << std::endl << kArgThreads << " : When queued, number of threads in the request processing thread pool" << std::endl << kArgUserSpecific << " : Make agent OS user specific." << std::endl + << kArgHelp << " : prints this help message" << std::endl << kArgSavePrintRequestDataTo << " : saves the PDF data to the given file path for print requests" << std::endl << kArgToBlock << " : Regular expression matching file and text content to block." << std::endl << kArgToWarn << " : Regular expression matching file and text content to warn about." << std::endl << kArgToReport << " : Regular expression matching file and text content to report." << std::endl - << kArgMisbehave << " : Use 'misbehaving' agent in given mode for testing purposes." << std::endl - << kArgHelp << " : prints this help message" << std::endl; + << kArgMisbehave << " : Use 'misbehaving' agent in given mode for testing purposes." << std::endl; } int main(int argc, char* argv[]) { @@ -150,10 +150,9 @@ int main(int argc, char* argv[]) { return 1; } - // TODO: Add toBlock, toWarn, toReport to QueueingHandler auto handler = useMisbehavingHandler - ? MisbehavingHandler::Create(delays[0], modeStr) + ? MisbehavingHandler::Create(modeStr, std::move(delays), save_print_data_path, std::move(toBlock), std::move(toWarn), std::move(toReport)) : use_queue ? std::make_unique(num_threads, std::move(delays), save_print_data_path, std::move(toBlock), std::move(toWarn), std::move(toReport)) : std::make_unique(std::move(delays), save_print_data_path, std::move(toBlock), std::move(toWarn), std::move(toReport)); diff --git a/third_party/content_analysis_sdk/demo/client.cc b/third_party/content_analysis_sdk/demo/client.cc index 5e47fca57f..84ca6e2356 100644 --- a/third_party/content_analysis_sdk/demo/client.cc +++ b/third_party/content_analysis_sdk/demo/client.cc @@ -317,7 +317,7 @@ void HandleRequest(const ContentAnalysisRequest& request) { global_final_action = final_action; } else { int err = client->Acknowledge( - BuildAcknowledgement(request.request_token(), final_action)); + BuildAcknowledgement(response.request_token(), final_action)); if (err != 0) { aout.stream() << "[Demo] Error sending ack " << request.request_token() << std::endl; diff --git a/third_party/content_analysis_sdk/demo/handler.h b/third_party/content_analysis_sdk/demo/handler.h index 1c9871bd08..88599963c5 100644 --- a/third_party/content_analysis_sdk/demo/handler.h +++ b/third_party/content_analysis_sdk/demo/handler.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -41,34 +42,46 @@ class Handler : public content_analysis::sdk::AgentEventHandler { size_t nextDelayIndex() const { return nextDelayIndex_; } protected: + // subclasses can override this + // returns whether the response has been set + virtual bool SetCustomResponse(AtomicCout& aout, std::unique_ptr& event) { + return false; + } + // subclasses can override this + // returns whether the response has been sent + virtual bool SendCustomResponse(std::unique_ptr& event) { + return false; + } // Analyzes one request from Google Chrome and responds back to the browser // with either an allow or block verdict. - void AnalyzeContent(std::stringstream& stream, std::unique_ptr event) { + void AnalyzeContent(AtomicCout& aout, std::unique_ptr event) { // An event represents one content analysis request and response triggered // by a user action in Google Chrome. The agent determines whether the // user is allowed to perform the action by examining event->GetRequest(). // The verdict, which can be "allow" or "block" is written into // event->GetResponse(). - DumpEvent(stream, event.get()); + DumpEvent(aout.stream(), event.get()); bool success = true; - std::optional caResponse = - content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_BLOCK; - - if (event->GetRequest().has_text_content()) { - caResponse = DecideCAResponse( - event->GetRequest().text_content(), stream); - } else if (event->GetRequest().has_file_path()) { - // TODO: Fix downloads to store file *first* so we can check contents. - // Until then, just check the file name: - caResponse = DecideCAResponse( - event->GetRequest().file_path(), stream); - } else if (event->GetRequest().has_print_data()) { - // In the case of print request, normally the PDF bytes would be parsed - // for sensitive data violations. To keep this class simple, only the - // URL is checked for the word "block". - caResponse = DecideCAResponse(event->GetRequest().request_data().url(), stream); + std::optional caResponse; + bool setResponse = SetCustomResponse(aout, event); + if (!setResponse) { + caResponse = content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_BLOCK; + if (event->GetRequest().has_text_content()) { + caResponse = DecideCAResponse( + event->GetRequest().text_content(), aout.stream()); + } else if (event->GetRequest().has_file_path()) { + // TODO: Fix downloads to store file *first* so we can check contents. + // Until then, just check the file name: + caResponse = DecideCAResponse( + event->GetRequest().file_path(), aout.stream()); + } else if (event->GetRequest().has_print_data()) { + // In the case of print request, normally the PDF bytes would be parsed + // for sensitive data violations. To keep this class simple, only the + // URL is checked for the word "block". + caResponse = DecideCAResponse(event->GetRequest().request_data().url(), aout.stream()); + } } if (!success) { @@ -76,61 +89,67 @@ class Handler : public content_analysis::sdk::AgentEventHandler { event->GetResponse(), std::string(), content_analysis::sdk::ContentAnalysisResponse::Result::FAILURE); - stream << " Verdict: failed to reach verdict: "; - stream << event->DebugString() << std::endl; + aout.stream() << " Verdict: failed to reach verdict: "; + aout.stream() << event->DebugString() << std::endl; } else { - stream << " Verdict: "; + aout.stream() << " Verdict: "; if (caResponse) { switch (caResponse.value()) { case content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_BLOCK: - stream << "BLOCK"; + aout.stream() << "BLOCK"; break; case content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_WARN: - stream << "WARN"; + aout.stream() << "WARN"; break; case content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_REPORT_ONLY: - stream << "REPORT_ONLY"; + aout.stream() << "REPORT_ONLY"; break; case content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule_Action_ACTION_UNSPECIFIED: - stream << "ACTION_UNSPECIFIED"; + aout.stream() << "ACTION_UNSPECIFIED"; break; default: - stream << ""; + aout.stream() << ""; break; } auto rc = content_analysis::sdk::SetEventVerdictTo(event.get(), caResponse.value()); if (rc != content_analysis::sdk::ResultCode::OK) { - stream << " error: " - << content_analysis::sdk::ResultCodeToString(rc) << std::endl; - stream << " " << event->DebugString() << std::endl; + aout.stream() << " error: " + << content_analysis::sdk::ResultCodeToString(rc) << std::endl; + aout.stream() << " " << event->DebugString() << std::endl; } - stream << std::endl; + aout.stream() << std::endl; } else { - stream << " Verdict: allow" << std::endl; + aout.stream() << " Verdict: allow" << std::endl; } - stream << std::endl; + aout.stream() << std::endl; } - stream << std::endl; + aout.stream() << std::endl; // If a delay is specified, wait that much. size_t nextDelayIndex = nextDelayIndex_.fetch_add(1); unsigned long delay = delays_[nextDelayIndex % delays_.size()]; if (delay > 0) { + aout.stream() << "Delaying response to " << event->GetRequest().request_token() + << " for " << delay << "s" << std::endl<< std::endl; + aout.flush(); std::this_thread::sleep_for(std::chrono::seconds(delay)); } // Send the response back to Google Chrome. - auto rc = event->Send(); - if (rc != content_analysis::sdk::ResultCode::OK) { - stream << "[Demo] Error sending response: " - << content_analysis::sdk::ResultCodeToString(rc) - << std::endl; - stream << event->DebugString() << std::endl; + bool sentCustomResponse = SendCustomResponse(event); + if (!sentCustomResponse) { + auto rc = event->Send(); + if (rc != content_analysis::sdk::ResultCode::OK) { + aout.stream() << "[Demo] Error sending response: " + << content_analysis::sdk::ResultCodeToString(rc) + << std::endl; + aout.stream() << event->DebugString() << std::endl; + } } } - private: + protected: void OnBrowserConnected( const content_analysis::sdk::BrowserInfo& info) override { AtomicCout aout; @@ -155,7 +174,7 @@ class Handler : public content_analysis::sdk::AgentEventHandler { // In this example code, the event is handled synchronously. AtomicCout aout; aout.stream() << std::endl << "----------" << std::endl << std::endl; - AnalyzeContent(aout.stream(), std::move(event)); + AnalyzeContent(aout, std::move(event)); } void OnResponseAcknowledged( @@ -183,7 +202,7 @@ class Handler : public content_analysis::sdk::AgentEventHandler { } AtomicCout aout; - aout.stream() << "Ack: " << ack.request_token() << std::endl; + aout.stream() << " Ack: " << ack.request_token() << std::endl; aout.stream() << " Final action: " << final_action << std::endl; } void OnCancelRequests( @@ -206,31 +225,62 @@ class Handler : public content_analysis::sdk::AgentEventHandler { void DumpEvent(std::stringstream& stream, Event* event) { time_t now = time(nullptr); - stream << "Received at: " << ctime(&now); // Returned string includes \n. + stream << "Received at: " << ctime(&now); // Includes \n. + stream << "Received from: pid=" << event->GetBrowserInfo().pid + << " path=" << event->GetBrowserInfo().binary_path << std::endl; const content_analysis::sdk::ContentAnalysisRequest& request = event->GetRequest(); std::string connector = ""; if (request.has_analysis_connector()) { - switch (request.analysis_connector()) - { - case content_analysis::sdk::FILE_DOWNLOADED: - connector = "download"; - break; - case content_analysis::sdk::FILE_ATTACHED: - connector = "attach"; - break; - case content_analysis::sdk::BULK_DATA_ENTRY: - connector = "bulk-data-entry"; - break; - case content_analysis::sdk::PRINT: - connector = "print"; - break; - case content_analysis::sdk::FILE_TRANSFER: - connector = "file-transfer"; - break; - default: - break; + switch (request.analysis_connector()) { + case content_analysis::sdk::FILE_DOWNLOADED: + connector = "download"; + break; + case content_analysis::sdk::FILE_ATTACHED: + connector = "attach"; + break; + case content_analysis::sdk::BULK_DATA_ENTRY: + connector = "bulk-data-entry"; + break; + case content_analysis::sdk::PRINT: + connector = "print"; + break; + case content_analysis::sdk::FILE_TRANSFER: + connector = "file-transfer"; + break; + default: + break; + } + } + std::string reason; + if (request.has_reason()) { + using content_analysis::sdk::ContentAnalysisRequest; + switch (request.reason()) { + case content_analysis::sdk::ContentAnalysisRequest::UNKNOWN: + reason = ""; + break; + case content_analysis::sdk::ContentAnalysisRequest::CLIPBOARD_PASTE: + reason = "CLIPBOARD_PASTE"; + break; + case content_analysis::sdk::ContentAnalysisRequest::DRAG_AND_DROP: + reason = "DRAG_AND_DROP"; + break; + case content_analysis::sdk::ContentAnalysisRequest::FILE_PICKER_DIALOG: + reason = "FILE_PICKER_DIALOG"; + break; + case content_analysis::sdk::ContentAnalysisRequest::PRINT_PREVIEW_PRINT: + reason = "PRINT_PREVIEW_PRINT"; + break; + case content_analysis::sdk::ContentAnalysisRequest::SYSTEM_DIALOG_PRINT: + reason = "SYSTEM_DIALOG_PRINT"; + break; + case content_analysis::sdk::ContentAnalysisRequest::NORMAL_DOWNLOAD: + reason = "NORMAL_DOWNLOAD"; + break; + case content_analysis::sdk::ContentAnalysisRequest::SAVE_AS_DOWNLOAD: + reason = "SAVE_AS_DOWNLOAD"; + break; } } @@ -252,11 +302,7 @@ class Handler : public content_analysis::sdk::AgentEventHandler { std::string file_path = request.has_file_path() - ? request.file_path() : ""; - - std::string text_content = - request.has_text_content() - ? request.text_content() : ""; + ? request.file_path() : "None, bulk text entry or print"; std::string machine_user = request.has_client_metadata() && @@ -282,14 +328,35 @@ class Handler : public content_analysis::sdk::AgentEventHandler { stream << " Expires at: " << expires_at_str << " (" << secs_remaining << " seconds from now)" << std::endl; stream << " Connector: " << connector << std::endl; + if (!reason.empty()) { + stream << " Reason: " << reason << std::endl; + } stream << " URL: " << url << std::endl; stream << " Tab title: " << tab_title << std::endl; stream << " Filename: " << filename << std::endl; stream << " Digest: " << digest << std::endl; stream << " Filepath: " << file_path << std::endl; - stream << " Text content: '" << text_content << "'" << std::endl; stream << " Machine user: " << machine_user << std::endl; stream << " Email: " << email << std::endl; + + if (request.has_text_content() && !request.text_content().empty()) { + std::string prefix = " Pasted data: "; + std::string text_content = request.text_content(); + + // Truncate the text past 50 bytes to keep it to a reasonable length in + // the terminal window. + if (text_content.size() > 50) { + prefix = " Pasted data (truncated): "; + text_content = text_content.substr(0, 50) + "..."; + } + stream << prefix + << text_content + << std::endl; + stream << " Pasted data size (bytes): " + << request.text_content().size() + << std::endl; + } + if (request.has_print_data() && !print_data_file_path_.empty()) { if (request.request_data().has_print_metadata() && request.request_data().print_metadata().has_printer_name()) { @@ -415,12 +482,13 @@ class QueuingHandler : public Handler { AtomicCout aout; aout.stream() << std::endl << "----------" << std::endl; - aout.stream() << "Thread: " << std::this_thread::get_id() << std::endl; + aout.stream() << "Thread: " << std::this_thread::get_id() + << std::endl; aout.stream() << "Delaying request processing for " << handler->delays()[handler->nextDelayIndex() % handler->delays().size()] << "s" << std::endl << std::endl; aout.flush(); - handler->AnalyzeContent(aout.stream(), std::move(event)); + handler->AnalyzeContent(aout, std::move(event)); } return 0; diff --git a/third_party/content_analysis_sdk/demo/handler_misbehaving.h b/third_party/content_analysis_sdk/demo/handler_misbehaving.h index d303049d98..bb0b4f18ad 100644 --- a/third_party/content_analysis_sdk/demo/handler_misbehaving.h +++ b/third_party/content_analysis_sdk/demo/handler_misbehaving.h @@ -20,6 +20,7 @@ #include "content_analysis/sdk/analysis.pb.h" #include "content_analysis/sdk/analysis_agent.h" #include "agent/src/event_win.h" +#include "handler.h" enum class Mode { // Have to use a "Mode_" prefix to avoid preprocessing problems in StringToMode @@ -93,13 +94,18 @@ static DWORD WriteBigMessageToPipe(HANDLE pipe, const std::string& message) { } // An AgentEventHandler that does various misbehaving things -class MisbehavingHandler final : public content_analysis::sdk::AgentEventHandler { +class MisbehavingHandler final : public Handler { public: using Event = content_analysis::sdk::ContentAnalysisEvent; static - std::unique_ptr Create(unsigned long delay, - const std::string& modeStr) { + std::unique_ptr Create( + const std::string& modeStr, + std::vector&& delays, + const std::string& print_data_file_path, + RegexArray&& toBlock = RegexArray(), + RegexArray&& toWarn = RegexArray(), + RegexArray&& toReport = RegexArray()) { auto it = sStringToMode.find(modeStr); if (it == sStringToMode.end()) { std::cout << "\"" << modeStr << "\"" @@ -107,11 +113,17 @@ class MisbehavingHandler final : public content_analysis::sdk::AgentEventHandler return nullptr; } - return std::unique_ptr(new MisbehavingHandler(delay, it->second)); + return std::unique_ptr(new MisbehavingHandler(it->second, std::move(delays), print_data_file_path, std::move(toBlock), std::move(toWarn), std::move(toReport))); } private: - MisbehavingHandler(unsigned long delay, Mode mode) : delay_(delay), mode_(mode) {} + MisbehavingHandler(Mode mode, std::vector&& delays, const std::string& print_data_file_path, + RegexArray&& toBlock = RegexArray(), + RegexArray&& toWarn = RegexArray(), + RegexArray&& toReport = RegexArray()) : + Handler(std::move(delays), print_data_file_path, std::move(toBlock), std::move(toWarn), std::move(toReport)), + mode_(mode) {} + template DWORD SendBytesOverPipe(const unsigned char (&bytes)[N], @@ -124,20 +136,11 @@ class MisbehavingHandler final : public content_analysis::sdk::AgentEventHandler return WriteBigMessageToPipe(pipe, s); } - // Analyzes one request from Google Chrome and responds back to the browser - // with either an allow or block verdict. - void AnalyzeContent(std::unique_ptr event) { - // An event represents one content analysis request and response triggered - // by a user action in Google Chrome. The agent determines whether the - // user is allowed to perform the action by examining event->GetRequest(). - // The verdict, which can be "allow" or "block" is written into - // event->GetResponse(). - + bool SetCustomResponse(AtomicCout& aout, std::unique_ptr& event) override { std::cout << std::endl << "----------" << std::endl << std::endl; - - DumpRequest(event->GetRequest()); std::cout << "Mode is " << sModeToString[mode_] << std::endl; + bool handled = true; if (mode_ == Mode::Mode_largeResponse) { for (size_t i = 0; i < 1000; ++i) { content_analysis::sdk::ContentAnalysisResponse_Result* result = @@ -177,7 +180,7 @@ class MisbehavingHandler final : public content_analysis::sdk::AgentEventHandler event->GetResponse().clear_results(); } else if (mode_ == Mode::Mode_resultWithInvalidStatus) { // This causes an assertion failure and the process exits - // So we just serialize this ourselves below + // So we just serialize this ourselves in SendCustomResponse() /*content_analysis::sdk::ContentAnalysisResponse_Result* result = event->GetResponse().mutable_results(0); result->set_status( @@ -185,38 +188,12 @@ class MisbehavingHandler final : public content_analysis::sdk::AgentEventHandler ::content_analysis::sdk::ContentAnalysisResponse_Result_Status>( 100));*/ } else { - bool block = false; - - if (event->GetRequest().has_text_content()) { - block = ShouldBlockRequest(event->GetRequest().text_content()); - } else if (event->GetRequest().has_file_path()) { - block = ShouldBlockRequest(event->GetRequest().file_path()); - } - - if (block) { - auto rc = content_analysis::sdk::SetEventVerdictToBlock(event.get()); - std::cout << " Verdict: block"; - if (rc != content_analysis::sdk::ResultCode::OK) { - std::cout << " error: " - << content_analysis::sdk::ResultCodeToString(rc) - << std::endl; - std::cout << " " << event->DebugString() << std::endl; - } - std::cout << std::endl; - } else { - std::cout << " Verdict: allow" << std::endl; - } - } - - std::cout << std::endl; - - // If a delay is specified, wait that much. - if (delay_ > 0) { - std::cout << "[Demo] delaying request processing for " << delay_ << "s" - << std::endl; - std::this_thread::sleep_for(std::chrono::seconds(delay_)); + handled = false; } + return handled; + } + bool SendCustomResponse(std::unique_ptr& event) override { if (mode_ == Mode::Mode_largeResponse) { content_analysis::sdk::ContentAnalysisEventWin* eventWin = static_cast( @@ -301,194 +278,12 @@ class MisbehavingHandler final : public content_analysis::sdk::AgentEventHandler // bit, indicating there should be a byte after this SendBytesOverPipe(bytes, event); } else { - std::cout << "(misbehaving) Handler::AnalyzeContent() about to call " - "event->Send(), mode is " - << sModeToString[mode_] << std::endl; - // Send the response back to Google Chrome. - auto rc = event->Send(); - if (rc != content_analysis::sdk::ResultCode::OK) { - std::cout << "[Demo] Error sending response: " - << content_analysis::sdk::ResultCodeToString(rc) << std::endl; - std::cout << event->DebugString() << std::endl; - } - } - } - - private: - void OnBrowserConnected( - const content_analysis::sdk::BrowserInfo& info) override { - std::cout << std::endl << "==========" << std::endl; - std::cout << "Browser connected pid=" << info.pid << std::endl; - } - - void OnBrowserDisconnected( - const content_analysis::sdk::BrowserInfo& info) override { - std::cout << std::endl - << "Browser disconnected pid=" << info.pid << std::endl; - std::cout << "==========" << std::endl; - } - - void OnAnalysisRequested(std::unique_ptr event) override { - // If the agent is capable of analyzing content in the background, the - // events may be handled in background threads. Having said that, a - // event should not be assumed to be thread safe, that is, it should not - // be accessed by more than one thread concurrently. - // - // In this example code, the event is handled synchronously. - AnalyzeContent(std::move(event)); - } - void OnResponseAcknowledged( - const content_analysis::sdk::ContentAnalysisAcknowledgement& ack) - override { - const char* final_action = ""; - if (ack.has_final_action()) { - switch (ack.final_action()) { - case content_analysis::sdk::ContentAnalysisAcknowledgement:: - ACTION_UNSPECIFIED: - final_action = ""; - break; - case content_analysis::sdk::ContentAnalysisAcknowledgement::ALLOW: - final_action = "Allow"; - break; - case content_analysis::sdk::ContentAnalysisAcknowledgement::REPORT_ONLY: - final_action = "Report only"; - break; - case content_analysis::sdk::ContentAnalysisAcknowledgement::WARN: - final_action = "Warn"; - break; - case content_analysis::sdk::ContentAnalysisAcknowledgement::BLOCK: - final_action = "Block"; - break; - } - } - - std::cout << "Ack: " << ack.request_token() << std::endl; - std::cout << " Final action: " << final_action << std::endl; - } - void OnCancelRequests( - const content_analysis::sdk::ContentAnalysisCancelRequests& cancel) - override { - std::cout << "Cancel: " << std::endl; - std::cout << " User action ID: " << cancel.user_action_id() << std::endl; - } - - void OnInternalError(const char* context, - content_analysis::sdk::ResultCode error) override { - std::cout << std::endl - << "*ERROR*: context=\"" << context << "\" " - << content_analysis::sdk::ResultCodeToString(error) << std::endl; - } - - void DumpRequest( - const content_analysis::sdk::ContentAnalysisRequest& request) { - std::string connector = ""; - if (request.has_analysis_connector()) { - switch (request.analysis_connector()) { - case content_analysis::sdk::FILE_DOWNLOADED: - connector = "download"; - break; - case content_analysis::sdk::FILE_ATTACHED: - connector = "attach"; - break; - case content_analysis::sdk::BULK_DATA_ENTRY: - connector = "bulk-data-entry"; - break; - case content_analysis::sdk::PRINT: - connector = "print"; - break; - case content_analysis::sdk::FILE_TRANSFER: - connector = "file-transfer"; - break; - default: - break; - } + return false; } - - std::string url = - request.has_request_data() && request.request_data().has_url() - ? request.request_data().url() - : ""; - - std::string tab_title = - request.has_request_data() && request.request_data().has_tab_title() - ? request.request_data().tab_title() - : ""; - - std::string filename = - request.has_request_data() && request.request_data().has_filename() - ? request.request_data().filename() - : ""; - - std::string digest = - request.has_request_data() && request.request_data().has_digest() - ? request.request_data().digest() - : ""; - - std::string file_path = - request.has_file_path() ? request.file_path() : ""; - - std::string text_content = - request.has_text_content() ? request.text_content() : ""; - - std::string machine_user = - request.has_client_metadata() && - request.client_metadata().has_browser() && - request.client_metadata().browser().has_machine_user() - ? request.client_metadata().browser().machine_user() - : ""; - - std::string email = - request.has_request_data() && request.request_data().has_email() - ? request.request_data().email() - : ""; - - time_t t = request.expires_at(); - - std::string user_action_id = request.has_user_action_id() - ? request.user_action_id() - : ""; - - std::cout << "Request: " << request.request_token() << std::endl; - std::cout << " User action ID: " << user_action_id << std::endl; - std::cout << " Expires at: " << ctime(&t); // Returned string includes \n. - std::cout << " Connector: " << connector << std::endl; - std::cout << " URL: " << url << std::endl; - std::cout << " Tab title: " << tab_title << std::endl; - std::cout << " Filename: " << filename << std::endl; - std::cout << " Digest: " << digest << std::endl; - std::cout << " Filepath: " << file_path << std::endl; - std::cout << " Text content: '" << text_content << "'" << std::endl; - std::cout << " Machine user: " << machine_user << std::endl; - std::cout << " Email: " << email << std::endl; - } - - bool ReadContentFromFile(const std::string& file_path, std::string* content) { - std::ifstream file(file_path, - std::ios::in | std::ios::binary | std::ios::ate); - if (!file.is_open()) return false; - - // Get file size. This example does not handle files larger than 1MB. - // Make sure content string can hold the contents of the file. - int size = file.tellg(); - if (size > 1024 * 1024) return false; - - content->resize(size + 1); - - // Read file into string. - file.seekg(0, std::ios::beg); - file.read(&(*content)[0], size); - content->at(size) = 0; return true; } - bool ShouldBlockRequest(const std::string& content) { - // Determines if the request should be blocked. (not needed for the - // misbehaving agent) - std::cout << "'" << content << "' was not blocked\n"; - return false; - } - - unsigned long delay_; + private: Mode mode_; }; diff --git a/third_party/content_analysis_sdk/moz.yaml b/third_party/content_analysis_sdk/moz.yaml new file mode 100644 index 0000000000..9d12c72924 --- /dev/null +++ b/third_party/content_analysis_sdk/moz.yaml @@ -0,0 +1,33 @@ +schema: 1 + +bugzilla: + product: Firefox + component: Data Loss Prevention + +origin: + name: Content Analysis SDK + description: SDK that DLP agents may use to interoperate with web browsers + url: https://github.com/chromium/content_analysis_sdk + release: 3d82f7523b557d0d5c75e1acf28c3deb8081ead1 (2024-04-03T14:44:34Z). + revision: 3d82f7523b557d0d5c75e1acf28c3deb8081ead1 + license: BSD-3-Clause + +vendoring: + url: https://github.com/chromium/content_analysis_sdk + source-hosting: github + exclude: + - .gitattributes + keep: + - demo/handler_misbehaving.h + - demo/modes.h + patches: + - agent_improvements.patch + +updatebot: + maintainer-phab: "#dlp-reviewers" + maintainer-bz: davidp99@gmail.com + tasks: + - type: vendoring + enabled: True + frequency: every + blocking: 1885485 diff --git a/third_party/content_analysis_sdk/prepare_build b/third_party/content_analysis_sdk/prepare_build index ce68760f0a..b61cdc42a5 100644 --- a/third_party/content_analysis_sdk/prepare_build +++ b/third_party/content_analysis_sdk/prepare_build @@ -1,48 +1,48 @@ -#!/bin/bash -# Copyright 2022 The Chromium Authors. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This script is meant to be run once to setup the example demo agent. -# Run it with one command line argument: the path to a directory where the -# demo agent will be built. This should be a directory outside the SDK -# directory tree. By default, if no directory is supplied, a directory -# named `build` in the project root will be used. -# -# Once the build is prepared, the demo binary is built using the command -# `cmake --build `, where is the same argument given -# to this script. - -set -euo pipefail - -export ROOT_DIR=$(realpath $(dirname $0)) -export DEMO_DIR=$(realpath $ROOT_DIR/demo) -export PROTO_DIR=$(realpath $ROOT_DIR/proto) -# Defaults to $ROOT_DIR/build if no argument is provided. -export BUILD_DIR=$(realpath ${1:-$ROOT_DIR/build}) - -echo Root dir: $ROOT_DIR -echo Build dir: $BUILD_DIR -echo Demo dir: $DEMO_DIR -echo Proto dir: $PROTO_DIR - -# Prepare build directory -mkdir -p $BUILD_DIR -# Prepare protobuf out directory -mkdir -p $BUILD_DIR/gen -# Enter build directory -cd $BUILD_DIR - -# Install vcpkg and use it to install Google Protocol Buffers. -test -d vcpkg || ( - git clone https://github.com/microsoft/vcpkg - ./vcpkg/bootstrap-vcpkg.sh -disableMetrics -) -# Install any packages we want from vcpkg. -./vcpkg/vcpkg install protobuf -./vcpkg/vcpkg install gtest - -# Generate the build files. -export CMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake -cmake $ROOT_DIR - +#!/bin/bash +# Copyright 2022 The Chromium Authors. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This script is meant to be run once to setup the example demo agent. +# Run it with one command line argument: the path to a directory where the +# demo agent will be built. This should be a directory outside the SDK +# directory tree. By default, if no directory is supplied, a directory +# named `build` in the project root will be used. +# +# Once the build is prepared, the demo binary is built using the command +# `cmake --build `, where is the same argument given +# to this script. + +set -euo pipefail + +export ROOT_DIR=$(realpath $(dirname $0)) +export DEMO_DIR=$(realpath $ROOT_DIR/demo) +export PROTO_DIR=$(realpath $ROOT_DIR/proto) +# Defaults to $ROOT_DIR/build if no argument is provided. +export BUILD_DIR=$(realpath ${1:-$ROOT_DIR/build}) + +echo Root dir: $ROOT_DIR +echo Build dir: $BUILD_DIR +echo Demo dir: $DEMO_DIR +echo Proto dir: $PROTO_DIR + +# Prepare build directory +mkdir -p $BUILD_DIR +# Prepare protobuf out directory +mkdir -p $BUILD_DIR/gen +# Enter build directory +cd $BUILD_DIR + +# Install vcpkg and use it to install Google Protocol Buffers. +test -d vcpkg || ( + git clone https://github.com/microsoft/vcpkg + ./vcpkg/bootstrap-vcpkg.sh -disableMetrics +) +# Install any packages we want from vcpkg. +./vcpkg/vcpkg install protobuf +./vcpkg/vcpkg install gtest + +# Generate the build files. +export CMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake +cmake $ROOT_DIR + diff --git a/third_party/content_analysis_sdk/proto/content_analysis/sdk/analysis.proto b/third_party/content_analysis_sdk/proto/content_analysis/sdk/analysis.proto index 0bbd3d4368..614b793f9b 100644 --- a/third_party/content_analysis_sdk/proto/content_analysis/sdk/analysis.proto +++ b/third_party/content_analysis_sdk/proto/content_analysis/sdk/analysis.proto @@ -156,8 +156,30 @@ message ContentAnalysisRequest { // Count of analysis requests that belong to the same user action. optional int64 user_action_requests_count = 17; + // Indicates the exact reason the request was created, ie which user action + // led to a data transfer. + enum Reason { + UNKNOWN = 0; + + // Only possible for the `FILE_ATTACHED` and `BULK_DATA_ENTRY` actions. + CLIPBOARD_PASTE = 1; + DRAG_AND_DROP = 2; + + // Only possible for the `FILE_ATTACHED` action. + FILE_PICKER_DIALOG = 3; + + // Only possible for the `PRINT` analysis connector. + PRINT_PREVIEW_PRINT = 4; + SYSTEM_DIALOG_PRINT = 5; + + // Only possible for the `FILE_DOWNLOADED` analysis connector. + NORMAL_DOWNLOAD = 6; + SAVE_AS_DOWNLOAD = 7; + } + optional Reason reason = 19; + // Reserved to make sure there is no overlap with DeepScanningClientRequest. - reserved 1 to 4, 6 to 8; + reserved 1 to 4, 6 to 8, 20; } // Verdict response sent from agent to Google Chrome. diff --git a/third_party/dav1d/NEWS b/third_party/dav1d/NEWS index 3645474a04..88b1eea00e 100644 --- a/third_party/dav1d/NEWS +++ b/third_party/dav1d/NEWS @@ -1,3 +1,15 @@ +Changes for 1.4.1 'Road Runner': +-------------------------------- + +1.4.1 is a small release of dav1d, improving notably ARM and RISC-V speed + +- Optimizations for 6tap filters for NEON (ARM) +- More RISC-V optimizations for itx (4x8, 8x4, 4x16, 16x4, 8x16, 16x8) +- Reduction of binary size on ARM64, ARM32 and RISC-V +- Fix out-of-bounds read in 8bpc SSE2/SSSE3 wiener_filter +- Msac optimizations + + Changes for 1.4.0 'Road Runner': -------------------------------- @@ -26,7 +38,7 @@ Changes for 1.3.0 'Tundra Peregrine Falcon (Calidus)': Changes for 1.2.1 'Arctic Peregrine Falcon': -------------------------------------------- +-------------------------------------------- 1.2.1 is a small release of dav1d, adding more SIMD and fixes @@ -42,7 +54,7 @@ Changes for 1.2.1 'Arctic Peregrine Falcon': Changes for 1.2.0 'Arctic Peregrine Falcon': -------------------------------------------- +-------------------------------------------- 1.2.0 is a small release of dav1d, adding more SIMD and fixes @@ -55,7 +67,7 @@ Changes for 1.2.0 'Arctic Peregrine Falcon': Changes for 1.1.0 'Arctic Peregrine Falcon': -------------------------------------------- +-------------------------------------------- 1.1.0 is an important release of dav1d, fixing numerous bugs, and adding SIMD diff --git a/third_party/dav1d/THANKS.md b/third_party/dav1d/THANKS.md index 4fc8d27f14..b7aa200d0e 100644 --- a/third_party/dav1d/THANKS.md +++ b/third_party/dav1d/THANKS.md @@ -16,19 +16,20 @@ The Alliance for Open Media (AOM) for partially funding this project. And all the dav1d Authors (git shortlog -sn), including: -Martin Storsjö, Henrik Gramner, Ronald S. Bultje, Janne Grunau, James Almer, -Victorien Le Couviour--Tuffet, Matthias Dressel, Marvin Scholz, -Jean-Baptiste Kempf, Luc Trudeau, Hugo Beauzée-Luyssen, Konstantin Pavlov, -Niklas Haas, David Michael Barr, Steve Lhomme, Nathan E. Egge, Wan-Teh Chang, -Kyle Siefring, B Krishnan Iyer, Francois Cartegnie, Liwei Wang, Luca Barbato, -David Conrad, Derek Buitenhuis, Jan Beich, Michael Bradshaw, Raphaël Zumer, -Xuefeng Jiang, Christophe Gisquet, Justin Bull, Boyuan Xiao, Dale Curtis, -Emmanuel Gil Peyrot, Raphael Zumer, Rupert Swarbrick, Thierry Foucu, -Thomas Daede, Colin Lee, Jonathan Wright, Lynne, Michail Alvanos, Nico Weber, -Salome Thirot, SmilingWolf, Tristan Laurent, Vittorio Giovara, Yannis Guyon, -André Kempe, Anisse Astier, Anton Mitrofanov, Charlie Hayden, Dmitriy Sychov, -Ewout ter Hoeven, Fred Barbier, Jean-Yves Avenard, Joe Drago, Mark Shuttleworth, -Matthieu Bouron, Mehdi Sabwat, Nicolas Frattaroli, Pablo Stebler, Rostislav -Pehlivanov, Sebastian Dröge, Shiz, Steinar Midtskogen, Sylvain BERTRAND, -Sylvestre Ledru, Timo Gurr, Tristan Matthews, Vibhoothi, Xavier Claessens, -Xu Guangxin, kossh1 and skal. +Henrik Gramner, Martin Storsjö, Ronald S. Bultje, Janne Grunau, James Almer, +Victorien Le Couviour--Tuffet, Matthias Dressel, Nathan E. Egge, +Jean-Baptiste Kempf, Marvin Scholz, Luc Trudeau, Niklas Haas, +Hugo Beauzée-Luyssen, Konstantin Pavlov, David Michael Barr, Steve Lhomme, +yuanhecai, Luca Barbato, Wan-Teh Chang, Kyle Siefring, B Krishnan Iyer, +Francois Cartegnie, Liwei Wang, David Conrad, Derek Buitenhuis, Jan Beich, +Michael Bradshaw, Raphaël Zumer, Xuefeng Jiang, Arpad Panyik, Christophe Gisquet, +Justin Bull, Boyuan Xiao, Dale Curtis, Emmanuel Gil Peyrot, Raphael Zumer, +Rupert Swarbrick, Thierry Foucu, Thomas Daede, jinbo, André Kempe, Colin Lee, +Jonathan Wright, Lynne, Michail Alvanos, Nico Weber, Salome Thirot, SmilingWolf, +Tristan Laurent, Tristan Matthews, Vittorio Giovara, Yannis Guyon, +Andrey Semashev, Anisse Astier, Anton Mitrofanov, Charlie Hayden, Dmitriy Sychov, +Ewout ter Hoeven, Fred Barbier, Hao Chen, Jean-Yves Avenard, Joe Drago, +Mark Shuttleworth, Matthieu Bouron, Mehdi Sabwat, Nicolas Frattaroli, +Pablo Stebler, Rostislav Pehlivanov, Sebastian Dröge, Shiz, Steinar Midtskogen, +Sylvain BERTRAND, Sylvestre Ledru, Timo Gurr, Vibhoothi, +Vignesh Venkatasubramanian, Xavier Claessens, Xu Guangxin, kossh1 and skal. diff --git a/third_party/dav1d/gcovr.cfg b/third_party/dav1d/gcovr.cfg index d09a0ecab5..e02ae33c33 100644 --- a/third_party/dav1d/gcovr.cfg +++ b/third_party/dav1d/gcovr.cfg @@ -1,4 +1,4 @@ exclude = .*/tests/.* exclude = .*/tools/.* exclude = .*/include/common/dump.h -gcov-ignore-parse-errors = yes +gcov-ignore-parse-errors = negative_hits.warn diff --git a/third_party/dav1d/meson.build b/third_party/dav1d/meson.build index 6e49852103..e371415d53 100644 --- a/third_party/dav1d/meson.build +++ b/third_party/dav1d/meson.build @@ -23,7 +23,7 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. project('dav1d', ['c'], - version: '1.4.0', + version: '1.4.1', default_options: ['c_std=c99', 'warning_level=2', 'buildtype=release', @@ -309,6 +309,10 @@ if (host_machine.system() in ['darwin', 'ios', 'tvos'] and cc.get_id() == 'clang optional_arguments += '-fno-stack-check' endif +if (host_machine.cpu_family() == 'aarch64' or host_machine.cpu_family().startswith('arm')) + optional_arguments += '-fno-align-functions' +endif + add_project_arguments(cc.get_supported_arguments(optional_arguments), language : 'c') add_project_link_arguments(cc.get_supported_link_arguments(optional_link_arguments), language : 'c') @@ -365,6 +369,66 @@ if (is_asm_enabled and if cc.compiles(check_pic_code) cdata.set('PIC', '3') endif + + if host_machine.cpu_family() == 'aarch64' + have_as_arch = cc.compiles('''__asm__ (".arch armv8-a");''') + cdata.set10('HAVE_AS_ARCH_DIRECTIVE', have_as_arch) + as_arch_str = '' + if have_as_arch + as_arch_level = 'armv8-a' + # Check what .arch levels are supported. In principle, we only + # want to detect up to armv8.2-a here (binutils requires that + # in order to enable i8mm). However, older Clang versions + # (before Clang 17, and Xcode versions up to and including 15.0) + # didn't support controlling dotprod/i8mm extensions via + # .arch_extension, therefore try to enable a high enough .arch + # level as well, to implicitly make them available via that. + foreach arch : ['armv8.2-a', 'armv8.4-a', 'armv8.6-a'] + if cc.compiles('__asm__ (".arch ' + arch + '\\n");') + as_arch_level = arch + endif + endforeach + # Clang versions before 17 also had a bug + # (https://github.com/llvm/llvm-project/issues/32220) + # causing a plain ".arch " to not have any effect unless it + # had an extra "+" included - but it was activated on the + # next ".arch_extension" directive instead. Check if we can include + # "+crc" as dummy feature to make the .arch directive behave as + # expected and take effect right away. + if cc.compiles('__asm__ (".arch ' + as_arch_level + '+crc\\n");') + as_arch_level = as_arch_level + '+crc' + endif + cdata.set('AS_ARCH_LEVEL', as_arch_level) + as_arch_str = '".arch ' + as_arch_level + '\\n"' + endif + extensions = { + 'dotprod': 'udot v0.4s, v0.16b, v0.16b', + 'i8mm': 'usdot v0.4s, v0.16b, v0.16b', + 'sve': 'whilelt p0.s, x0, x1', + 'sve2': 'sqrdmulh z0.s, z0.s, z0.s', + } + foreach name, instr : extensions + # Test for support for the various extensions. First test if + # the assembler supports the .arch_extension directive for + # enabling/disabling the extension, then separately check whether + # the instructions themselves are supported. Even if .arch_extension + # isn't supported, we may be able to assemble the instructions + # if the .arch level includes support for them. + code = '__asm__ (' + as_arch_str + code += '".arch_extension ' + name + '\\n"' + code += ');' + supports_archext = cc.compiles(code) + cdata.set10('HAVE_AS_ARCHEXT_' + name.to_upper() + '_DIRECTIVE', supports_archext) + code = '__asm__ (' + as_arch_str + if supports_archext + code += '".arch_extension ' + name + '\\n"' + endif + code += '"' + instr + '\\n"' + code += ');' + supports_instr = cc.compiles(code, name: name.to_upper()) + cdata.set10('HAVE_' + name.to_upper(), supports_instr) + endforeach + endif endif cdata.set10('ARCH_X86', host_machine.cpu_family().startswith('x86')) @@ -477,6 +541,17 @@ if (is_asm_enabled and ]) endif +if is_asm_enabled and host_machine.cpu_family().startswith('riscv') + as_option_code = '''__asm__ ( +".option arch, +v\n" +"vsetivli zero, 0, e8, m1, ta, ma" +); +''' + if not cc.compiles(as_option_code, name : 'RISC-V Vector') + error('Compiler doesn\'t support \'.option arch\' asm directive. Update to binutils>=2.38 or clang>=17 or use \'-Denable_asm=false\'.') + endif +endif + # Generate config.h config_h_target = configure_file(output: 'config.h', configuration: cdata) diff --git a/third_party/dav1d/src/arm/32/itx.S b/third_party/dav1d/src/arm/32/itx.S index ceea025e45..9ba1df7a68 100644 --- a/third_party/dav1d/src/arm/32/itx.S +++ b/third_party/dav1d/src/arm/32/itx.S @@ -965,6 +965,8 @@ function inv_txfm_\variant\()add_8x8_neon .ifc \variant, identity_ // The identity shl #1 and downshift srshr #1 cancel out + + b L(itx_8x8_epilog) .else blx r4 @@ -976,8 +978,8 @@ function inv_txfm_\variant\()add_8x8_neon vrshr.s16 q13, q13, #1 vrshr.s16 q14, q14, #1 vrshr.s16 q15, q15, #1 -.endif +L(itx_8x8_epilog): transpose_8x8h q8, q9, q10, q11, q12, q13, q14, q15, d17, d19, d21, d23, d24, d26, d28, d30 blx r5 @@ -985,11 +987,12 @@ function inv_txfm_\variant\()add_8x8_neon load_add_store_8x8 r0, r7 vpop {q4-q7} pop {r4-r5,r7,pc} +.endif endfunc .endm -def_fn_8x8_base def_fn_8x8_base identity_ +def_fn_8x8_base .macro def_fn_8x8 txfm1, txfm2 function inv_txfm_add_\txfm1\()_\txfm2\()_8x8_8bpc_neon, export=1 @@ -1444,14 +1447,16 @@ function inv_txfm_horz\suffix\()_16x4_neon .else identity_4x16_shift1 d0[0] .endif + b L(horz_16x4_epilog) .else blx r4 -.endif -.if \shift > 0 .irp i, q8, q9, q10, q11, q12, q13, q14, q15 vrshr.s16 \i, \i, #\shift .endr -.endif +.if \shift == 1 + b L(horz_16x4_epilog) +.else +L(horz_16x4_epilog): transpose_4x4h q8, q9, d16, d17, d18, d19 transpose_4x4h q10, q11, d20, d21, d22, d23 transpose_4x4h q12, q13, d24, d25, d26, d27 @@ -1462,13 +1467,15 @@ function inv_txfm_horz\suffix\()_16x4_neon .endr pop {pc} +.endif +.endif endfunc .endm -def_horz_16 scale=0, identity=0, shift=2 -def_horz_16 scale=1, identity=0, shift=1, suffix=_scale -def_horz_16 scale=0, identity=1, shift=-2, suffix=_identity def_horz_16 scale=1, identity=1, shift=-1, suffix=_scale_identity +def_horz_16 scale=0, identity=1, shift=-2, suffix=_identity +def_horz_16 scale=1, identity=0, shift=1, suffix=_scale +def_horz_16 scale=0, identity=0, shift=2 function inv_txfm_add_vert_4x16_neon push {lr} @@ -1597,6 +1604,8 @@ function inv_txfm_\variant\()add_16x4_neon .endr identity_4x16_shift1 d0[0] + + b L(itx_16x4_epilog) .else vmov.i16 q2, #0 vmov.i16 q3, #0 @@ -1615,30 +1624,25 @@ function inv_txfm_\variant\()add_16x4_neon vswp d19, d22 vswp d18, d20 vswp d19, d21 -.irp i, q8, q9, q10, q11 + vswp d25, d28 + vswp d27, d30 + vswp d26, d28 + vswp d27, d29 +.irp i, q8, q9, q10, q11, q12, q13, q14, q15 vrshr.s16 \i, \i, #1 .endr -.endif + +L(itx_16x4_epilog): transpose_4x8h q8, q9, q10, q11 blx r5 mov r6, r0 load_add_store_8x4 r6, r7 -.ifc \variant, identity_ vmov q8, q12 vmov q9, q13 vmov q10, q14 vmov q11, q15 -.else - vswp d25, d28 - vswp d27, d30 - vswp d26, d28 - vswp d27, d29 - vrshr.s16 q8, q12, #1 - vrshr.s16 q9, q13, #1 - vrshr.s16 q10, q14, #1 - vrshr.s16 q11, q15, #1 -.endif + transpose_4x8h q8, q9, q10, q11 blx r5 add r6, r0, #8 @@ -1646,6 +1650,7 @@ function inv_txfm_\variant\()add_16x4_neon vpop {q4-q7} pop {r4-r11,pc} +.endif endfunc function inv_txfm_\variant\()add_4x16_neon @@ -1696,12 +1701,14 @@ function inv_txfm_\variant\()add_4x16_neon movw r12, #(5793-4096)*8 vdup.16 d0, r12 identity_8x4_shift1 q8, q9, q10, q11, d0[0] + + b L(itx_4x16_epilog) .else blx r4 .irp i, q8, q9, q10, q11 vrshr.s16 \i, \i, #1 .endr -.endif +L(itx_4x16_epilog): transpose_4x8h q8, q9, q10, q11 vswp d19, d21 vswp d18, d20 @@ -1714,11 +1721,12 @@ function inv_txfm_\variant\()add_4x16_neon vpop {q4-q7} pop {r4-r11,pc} +.endif endfunc .endm -def_fn_416_base def_fn_416_base identity_ +def_fn_416_base .macro def_fn_416 w, h, txfm1, txfm2, eob_half function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1 @@ -1728,11 +1736,15 @@ function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1 push {r4-r11,lr} vpush {q4-q7} .if \w == 4 +.ifnc \txfm1, identity movrel_local r4, inv_\txfm1\()_8h_x\w\()_neon +.endif movrel_local r5, inv_\txfm2\()_4h_x\h\()_neon mov r10, #\eob_half .else +.ifnc \txfm1, identity movrel_local r4, inv_\txfm1\()_4h_x\w\()_neon +.endif movrel_local r5, inv_\txfm2\()_8h_x\h\()_neon .endif .ifc \txfm1, identity @@ -1765,8 +1777,7 @@ def_fn_416 \w, \h, identity, flipadst, 32 def_fns_416 4, 16 def_fns_416 16, 4 -.macro def_fn_816_base variant -function inv_txfm_\variant\()add_16x8_neon +function inv_txfm_add_16x8_neon sub_sp_align 256 .irp i, 0, 4 @@ -1805,6 +1816,7 @@ function inv_txfm_\variant\()add_16x8_neon pop {r4-r11,pc} endfunc +.macro def_fn_816_base variant function inv_txfm_\variant\()add_8x16_neon sub_sp_align 256 @@ -1849,6 +1861,10 @@ function inv_txfm_\variant\()add_8x16_neon .endr 2: +.ifc \variant, identity_ + b L(itx_8x16_epilog) +.else +L(itx_8x16_epilog): .irp i, 0, 4 add r6, r0, #(\i) add r7, sp, #(\i*2) @@ -1859,11 +1875,18 @@ function inv_txfm_\variant\()add_8x16_neon add_sp_align 256 vpop {q4-q7} pop {r4-r11,pc} +.endif endfunc .endm -def_fn_816_base def_fn_816_base identity_ +def_fn_816_base + +/* Define symbols used in .if statement */ +.equ dct, 1 +.equ identity, 2 +.equ adst, 3 +.equ flipadst, 4 .macro def_fn_816 w, h, txfm1, txfm2, eob_8x8, eob_4x4 function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1 @@ -1873,7 +1896,9 @@ function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1 push {r4-r11,lr} vpush {q4-q7} .if \w == 8 +.ifnc \txfm1, identity movrel_local r4, inv_\txfm1\()_8h_x8_neon +.endif movrel_local r5, inv_\txfm2\()_4h_x16_neon .else .ifc \txfm1, identity @@ -1889,7 +1914,7 @@ function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1 .else mov r10, #\eob_4x4 .endif -.ifc \txfm1, identity +.if \w == 8 && \txfm1 == identity b inv_txfm_identity_add_\w\()x\h\()_neon .else b inv_txfm_add_\w\()x\h\()_neon diff --git a/third_party/dav1d/src/arm/32/itx16.S b/third_party/dav1d/src/arm/32/itx16.S index aa6c272e71..7691272517 100644 --- a/third_party/dav1d/src/arm/32/itx16.S +++ b/third_party/dav1d/src/arm/32/itx16.S @@ -547,11 +547,11 @@ function inv_txfm_add_wht_wht_4x4_16bpc_neon, export=1 vmov.i16 q15, #0 vld1.32 {q8, q9}, [r2, :128] vst1.32 {q14, q15}, [r2, :128]! - vshr.s16 q8, q8, #2 + vshr.s32 q8, q8, #2 vld1.32 {q10, q11}, [r2, :128] - vshr.s16 q9, q9, #2 - vshr.s16 q10, q10, #2 - vshr.s16 q11, q11, #2 + vshr.s32 q9, q9, #2 + vshr.s32 q10, q10, #2 + vshr.s32 q11, q11, #2 iwht4 @@ -598,7 +598,9 @@ function inv_txfm_add_4x4_neon vld1.16 {d3}, [r0, :64], r1 L(itx_4x4_end): - vmvn.i16 q15, #0xfc00 // 0x3ff + // read bitdepth_max from the callers stack + ldr r4, [sp, #44] + vdup.i16 q15, r4 sub r0, r0, r1, lsl #2 vqadd.s16 q8, q8, q0 vqadd.s16 q9, q9, q1 @@ -1487,6 +1489,10 @@ function inv_txfm_horz\suffix\()_16x2_neon vqrshrn.s32 d21, q13, #\shift vqrshrn.s32 d22, q14, #\shift vqrshrn.s32 d23, q15, #\shift +.if \scale + b L(horz_16x2_epilog) +.else +L(horz_16x2_epilog): vuzp.16 q8, q9 vuzp.16 q10, q11 @@ -1495,11 +1501,12 @@ function inv_txfm_horz\suffix\()_16x2_neon .endr pop {pc} +.endif endfunc .endm -def_horz_16 scale=0, shift=2 def_horz_16 scale=1, shift=1, suffix=_scale +def_horz_16 scale=0, shift=2 function inv_txfm_add_vert_4x16_neon push {lr} diff --git a/third_party/dav1d/src/arm/32/msac.S b/third_party/dav1d/src/arm/32/msac.S index b06e109dda..b16957fb7e 100644 --- a/third_party/dav1d/src/arm/32/msac.S +++ b/third_party/dav1d/src/arm/32/msac.S @@ -279,60 +279,67 @@ L(renorm): sub r4, r4, r3 // rng = u - v clz r5, r4 // clz(rng) eor r5, r5, #16 // d = clz(rng) ^ 16 - mvn r7, r7 // ~dif - add r7, r7, r3, lsl #16 // ~dif + (v << 16) + sub r7, r7, r3, lsl #16 // dif - (v << 16) L(renorm2): lsl r4, r4, r5 // rng << d subs r6, r6, r5 // cnt -= d - lsl r7, r7, r5 // (~dif + (v << 16)) << d + lsl r7, r7, r5 // (dif - (v << 16)) << d str r4, [r0, #RNG] - mvn r7, r7 // ~dif - bhs 9f + bhs 4f // refill ldr r3, [r0, #BUF_POS] // BUF_POS ldr r4, [r0, #BUF_END] // BUF_END add r5, r3, #4 - cmp r5, r4 - bgt 2f - - ldr r3, [r3] // next_bits - add r8, r6, #23 // shift_bits = cnt + 23 - add r6, r6, #16 // cnt += 16 - rev r3, r3 // next_bits = bswap(next_bits) - sub r5, r5, r8, lsr #3 // buf_pos -= shift_bits >> 3 - and r8, r8, #24 // shift_bits &= 24 - lsr r3, r3, r8 // next_bits >>= shift_bits - sub r8, r8, r6 // shift_bits -= 16 + cnt - str r5, [r0, #BUF_POS] - lsl r3, r3, r8 // next_bits <<= shift_bits - rsb r6, r8, #16 // cnt = cnt + 32 - shift_bits - eor r7, r7, r3 // dif ^= next_bits - b 9f - -2: // refill_eob - rsb r5, r6, #8 // c = 8 - cnt -3: - cmp r3, r4 - bge 4f - ldrb r8, [r3], #1 - lsl r8, r8, r5 - eor r7, r7, r8 - subs r5, r5, #8 - bge 3b - -4: // refill_eob_end + subs r5, r5, r4 + bhi 6f + + ldr r8, [r3] // next_bits + rsb r5, r6, #16 + add r4, r6, #16 // shift_bits = cnt + 16 + mvn r8, r8 + lsr r5, r5, #3 // num_bytes_read + rev r8, r8 // next_bits = bswap(next_bits) + lsr r8, r8, r4 // next_bits >>= shift_bits + +2: // refill_end + add r3, r3, r5 + add r6, r6, r5, lsl #3 // cnt += num_bits_read str r3, [r0, #BUF_POS] - rsb r6, r5, #8 // cnt = 8 - c -9: +3: // refill_end2 + orr r7, r7, r8 // dif |= next_bits + +4: // end str r6, [r0, #CNT] str r7, [r0, #DIF] - mov r0, lr add sp, sp, #48 - pop {r4-r10,pc} + +5: // pad_with_ones + add r8, r6, #-240 + lsr r8, r8, r8 + b 3b + +6: // refill_eob + cmp r3, r4 + bhs 5b + + ldr r8, [r4, #-4] + lsl r5, r5, #3 + lsr r8, r8, r5 + add r5, r6, #16 + mvn r8, r8 + sub r4, r4, r3 // num_bytes_left + rev r8, r8 + lsr r8, r8, r5 + rsb r5, r6, #16 + lsr r5, r5, #3 + cmp r5, r4 + it hs + movhs r5, r4 + b 2b endfunc function msac_decode_symbol_adapt8_neon, export=1 @@ -414,53 +421,38 @@ function msac_decode_hi_tok_neon, export=1 sub r4, r4, r3 // rng = u - v clz r5, r4 // clz(rng) eor r5, r5, #16 // d = clz(rng) ^ 16 - mvn r7, r7 // ~dif - add r7, r7, r3, lsl #16 // ~dif + (v << 16) + sub r7, r7, r3, lsl #16 // dif - (v << 16) lsl r4, r4, r5 // rng << d subs r6, r6, r5 // cnt -= d - lsl r7, r7, r5 // (~dif + (v << 16)) << d + lsl r7, r7, r5 // (dif - (v << 16)) << d str r4, [r0, #RNG] vdup.16 d1, r4 - mvn r7, r7 // ~dif - bhs 9f + bhs 5f // refill ldr r3, [r0, #BUF_POS] // BUF_POS ldr r4, [r0, #BUF_END] // BUF_END add r5, r3, #4 - cmp r5, r4 - bgt 2f - - ldr r3, [r3] // next_bits - add r8, r6, #23 // shift_bits = cnt + 23 - add r6, r6, #16 // cnt += 16 - rev r3, r3 // next_bits = bswap(next_bits) - sub r5, r5, r8, lsr #3 // buf_pos -= shift_bits >> 3 - and r8, r8, #24 // shift_bits &= 24 - lsr r3, r3, r8 // next_bits >>= shift_bits - sub r8, r8, r6 // shift_bits -= 16 + cnt - str r5, [r0, #BUF_POS] - lsl r3, r3, r8 // next_bits <<= shift_bits - rsb r6, r8, #16 // cnt = cnt + 32 - shift_bits - eor r7, r7, r3 // dif ^= next_bits - b 9f - -2: // refill_eob - rsb r5, r6, #8 // c = 40 - cnt -3: - cmp r3, r4 - bge 4f - ldrb r8, [r3], #1 - lsl r8, r8, r5 - eor r7, r7, r8 - subs r5, r5, #8 - bge 3b - -4: // refill_eob_end + subs r5, r5, r4 + bhi 7f + + ldr r8, [r3] // next_bits + rsb r5, r6, #16 + add r4, r6, #16 // shift_bits = cnt + 16 + mvn r8, r8 + lsr r5, r5, #3 // num_bytes_read + rev r8, r8 // next_bits = bswap(next_bits) + lsr r8, r8, r4 // next_bits >>= shift_bits + +3: // refill_end + add r3, r3, r5 + add r6, r6, r5, lsl #3 // cnt += num_bits_read str r3, [r0, #BUF_POS] - rsb r6, r5, #8 // cnt = 40 - c -9: +4: // refill_end2 + orr r7, r7, r8 // dif |= next_bits + +5: // end lsl lr, lr, #1 sub lr, lr, #5 lsr r12, r7, #16 @@ -473,6 +465,30 @@ function msac_decode_hi_tok_neon, export=1 str r7, [r0, #DIF] lsr r0, r2, #1 pop {r4-r10,pc} + +6: // pad_with_ones + add r8, r6, #-240 + lsr r8, r8, r8 + b 4b + +7: // refill_eob + cmp r3, r4 + bhs 6b + + ldr r8, [r4, #-4] + lsl r5, r5, #3 + lsr r8, r8, r5 + add r5, r6, #16 + mvn r8, r8 + sub r4, r4, r3 // num_bytes_left + rev r8, r8 + lsr r8, r8, r5 + rsb r5, r6, #16 + lsr r5, r5, #3 + cmp r5, r4 + it hs + movhs r5, r4 + b 3b endfunc function msac_decode_bool_equi_neon, export=1 @@ -493,7 +509,6 @@ function msac_decode_bool_equi_neon, export=1 movhs r7, r8 // if (ret) dif = dif - vw; clz r5, r4 // clz(rng) - mvn r7, r7 // ~dif eor r5, r5, #16 // d = clz(rng) ^ 16 mov lr, r2 b L(renorm2) @@ -519,7 +534,6 @@ function msac_decode_bool_neon, export=1 movhs r7, r8 // if (ret) dif = dif - vw; clz r5, r4 // clz(rng) - mvn r7, r7 // ~dif eor r5, r5, #16 // d = clz(rng) ^ 16 mov lr, r2 b L(renorm2) @@ -549,7 +563,6 @@ function msac_decode_bool_adapt_neon, export=1 cmp r10, #0 clz r5, r4 // clz(rng) - mvn r7, r7 // ~dif eor r5, r5, #16 // d = clz(rng) ^ 16 mov lr, r2 diff --git a/third_party/dav1d/src/arm/64/itx.S b/third_party/dav1d/src/arm/64/itx.S index 53490cd677..7063cbde1d 100644 --- a/third_party/dav1d/src/arm/64/itx.S +++ b/third_party/dav1d/src/arm/64/itx.S @@ -879,6 +879,8 @@ function inv_txfm_\variant\()add_8x8_neon .ifc \variant, identity_ // The identity shl #1 and downshift srshr #1 cancel out + + b L(itx_8x8_epilog) .else blr x4 @@ -890,19 +892,20 @@ function inv_txfm_\variant\()add_8x8_neon srshr v21.8h, v21.8h, #1 srshr v22.8h, v22.8h, #1 srshr v23.8h, v23.8h, #1 -.endif +L(itx_8x8_epilog): transpose_8x8h v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 blr x5 load_add_store_8x8 x0, x7 ret x15 +.endif endfunc .endm -def_fn_8x8_base def_fn_8x8_base identity_ +def_fn_8x8_base .macro def_fn_8x8 txfm1, txfm2 function inv_txfm_add_\txfm1\()_\txfm2\()_8x8_8bpc_neon, export=1 @@ -1390,14 +1393,16 @@ function inv_txfm_horz\suffix\()_16x8_neon .endif .if \identity identity_8x16_shift2 v0.h[0] + b L(horz_16x8_epilog) .else blr x4 -.endif -.if \shift > 0 .irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h srshr \i, \i, #\shift .endr -.endif +.if \shift == 1 + b L(horz_16x8_epilog) +.else +L(horz_16x8_epilog): transpose_8x8h v16, v17, v18, v19, v20, v21, v22, v23, v4, v5 transpose_8x8h v24, v25, v26, v27, v28, v29, v30, v31, v4, v5 @@ -1406,12 +1411,14 @@ function inv_txfm_horz\suffix\()_16x8_neon .endr ret x14 +.endif +.endif endfunc .endm -def_horz_16 scale=0, identity=0, shift=2 def_horz_16 scale=1, identity=0, shift=1, suffix=_scale def_horz_16 scale=0, identity=1, shift=0, suffix=_identity +def_horz_16 scale=0, identity=0, shift=2 function inv_txfm_add_vert_8x16_neon mov x14, x30 @@ -1512,6 +1519,8 @@ function inv_txfm_\variant\()add_16x4_neon .endr identity_8x16_shift1 v0.h[0] + + b L(itx_16x4_epilog) .else .irp i, v16.4h, v17.4h, v18.4h, v19.4h, v20.4h, v21.4h, v22.4h, v23.4h, v24.4h, v25.4h, v26.4h, v27.4h, v28.4h, v29.4h, v30.4h, v31.4h ld1 {\i}, [x2] @@ -1527,33 +1536,29 @@ function inv_txfm_\variant\()add_16x4_neon .irp i, v16.8h, v17.8h, v18.8h, v19.8h srshr \i, \i, #1 .endr -.endif - transpose_4x8h v16, v17, v18, v19, v2, v3, v4, v5 - blr x5 - mov x6, x0 - load_add_store_8x4 x6, x7 -.ifc \variant, identity_ - mov v16.16b, v20.16b - mov v17.16b, v21.16b - mov v18.16b, v22.16b - mov v19.16b, v23.16b -.else ins v24.d[1], v28.d[0] ins v25.d[1], v29.d[0] ins v26.d[1], v30.d[0] ins v27.d[1], v31.d[0] - srshr v16.8h, v24.8h, #1 - srshr v17.8h, v25.8h, #1 - srshr v18.8h, v26.8h, #1 - srshr v19.8h, v27.8h, #1 -.endif + srshr v20.8h, v24.8h, #1 + srshr v21.8h, v25.8h, #1 + srshr v22.8h, v26.8h, #1 + srshr v23.8h, v27.8h, #1 + +L(itx_16x4_epilog): transpose_4x8h v16, v17, v18, v19, v2, v3, v4, v5 blr x5 + mov x6, x0 + load_add_store_8x4 x6, x7 + + transpose_4x8h_mov v20, v21, v22, v23, v2, v3, v4, v5, v16, v17, v18, v19 + blr x5 add x6, x0, #8 load_add_store_8x4 x6, x7 ret x15 +.endif endfunc function inv_txfm_\variant\()add_4x16_neon @@ -1605,12 +1610,14 @@ function inv_txfm_\variant\()add_4x16_neon mov w16, #(5793-4096)*8 dup v0.4h, w16 identity_8x4_shift1 v16, v17, v18, v19, v0.h[0] + + b L(itx_4x16_epilog) .else blr x4 .irp i, v16.8h, v17.8h, v18.8h, v19.8h srshr \i, \i, #1 .endr -.endif +L(itx_4x16_epilog): transpose_4x8h v16, v17, v18, v19, v4, v5, v6, v7 ins v20.d[0], v16.d[1] ins v21.d[0], v17.d[1] @@ -1622,11 +1629,12 @@ function inv_txfm_\variant\()add_4x16_neon load_add_store_4x16 x0, x6 ret x15 +.endif endfunc .endm -def_fn_416_base def_fn_416_base identity_ +def_fn_416_base .macro def_fn_416 w, h, txfm1, txfm2, eob_half function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1 @@ -1634,11 +1642,15 @@ function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1 idct_dc \w, \h, 1 .endif .if \w == 4 +.ifnc \txfm1, identity adr x4, inv_\txfm1\()_8h_x\w\()_neon +.endif adr x5, inv_\txfm2\()_4h_x\h\()_neon mov w13, #\eob_half .else +.ifnc \txfm1, identity adr x4, inv_\txfm1\()_4h_x\w\()_neon +.endif adr x5, inv_\txfm2\()_8h_x\h\()_neon .endif .ifc \txfm1, identity @@ -1690,13 +1702,16 @@ function inv_txfm_\variant\()add_16x8_neon mov w16, #2*(5793-4096)*8 dup v0.4h, w16 identity_8x16_shift1 v0.h[0] + + b L(itx_16x8_epilog) .else blr x4 -.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h +.irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h, v24.8h, v25.8h, v26.8h, v27.8h, v28.8h, v29.8h, v30.8h, v31.8h srshr \i, \i, #1 .endr -.endif + +L(itx_16x8_epilog): transpose_8x8h v16, v17, v18, v19, v20, v21, v22, v23, v2, v3 blr x5 @@ -1704,27 +1719,7 @@ function inv_txfm_\variant\()add_16x8_neon mov x6, x0 load_add_store_8x8 x6, x7 -.ifc \variant, identity_ - mov v16.16b, v24.16b - mov v17.16b, v25.16b - mov v18.16b, v26.16b - mov v19.16b, v27.16b - mov v20.16b, v28.16b - mov v21.16b, v29.16b - mov v22.16b, v30.16b - mov v23.16b, v31.16b -.else - srshr v16.8h, v24.8h, #1 - srshr v17.8h, v25.8h, #1 - srshr v18.8h, v26.8h, #1 - srshr v19.8h, v27.8h, #1 - srshr v20.8h, v28.8h, #1 - srshr v21.8h, v29.8h, #1 - srshr v22.8h, v30.8h, #1 - srshr v23.8h, v31.8h, #1 -.endif - - transpose_8x8h v16, v17, v18, v19, v20, v21, v22, v23, v2, v3 + transpose_8x8h_mov v24, v25, v26, v27, v28, v29, v30, v31, v2, v3, v16, v17, v18, v19, v20, v21, v22, v23 blr x5 @@ -1732,6 +1727,7 @@ function inv_txfm_\variant\()add_16x8_neon load_add_store_8x8 x0, x7 ret x15 +.endif endfunc function inv_txfm_\variant\()add_8x16_neon @@ -1790,14 +1786,16 @@ function inv_txfm_\variant\()add_8x16_neon scale_input .8h, v0.h[0], v16, v17, v18, v19, v20, v21, v22, v23 .ifc \variant, identity_ // The identity shl #1 and downshift srshr #1 cancel out + + b L(itx_8x16_epilog) .else blr x4 .irp i, v16.8h, v17.8h, v18.8h, v19.8h, v20.8h, v21.8h, v22.8h, v23.8h srshr \i, \i, #1 .endr -.endif +L(itx_8x16_epilog): transpose_8x8h v16, v17, v18, v19, v20, v21, v22, v23, v2, v3 blr x5 @@ -1805,18 +1803,21 @@ function inv_txfm_\variant\()add_8x16_neon load_add_store_8x16 x0, x6 ret x15 +.endif endfunc .endm -def_fn_816_base def_fn_816_base identity_ +def_fn_816_base .macro def_fn_816 w, h, txfm1, txfm2, eob_half function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_neon, export=1 .ifc \txfm1\()_\txfm2, dct_dct idct_dc \w, \h, 1 .endif +.ifnc \txfm1, identity adr x4, inv_\txfm1\()_8h_x\w\()_neon +.endif adr x5, inv_\txfm2\()_8h_x\h\()_neon .if \w == 8 mov x13, #\eob_half diff --git a/third_party/dav1d/src/arm/64/itx16.S b/third_party/dav1d/src/arm/64/itx16.S index eee3a9636d..31ee9be1b4 100644 --- a/third_party/dav1d/src/arm/64/itx16.S +++ b/third_party/dav1d/src/arm/64/itx16.S @@ -514,13 +514,17 @@ function inv_txfm_add_wht_wht_4x4_16bpc_neon, export=1 b L(itx_4x4_end) endfunc +// HBD inv_txfm_add_4x4_neon deviates from the common pattern with registers +// x0-x4 external parameters +// x5 function pointer to first transform +// x6 function pointer to second transform function inv_txfm_add_4x4_neon movi v30.4s, #0 movi v31.4s, #0 ld1 {v16.4s,v17.4s,v18.4s,v19.4s}, [x2] st1 {v30.4s, v31.4s}, [x2], #32 - blr x4 + blr x5 st1 {v30.4s, v31.4s}, [x2], #32 sqxtn v16.4h, v16.4s @@ -529,7 +533,7 @@ function inv_txfm_add_4x4_neon sqxtn v19.4h, v19.4s transpose_4x4h v16, v17, v18, v19, v20, v21, v22, v23 - blr x5 + blr x6 ld1 {v0.d}[0], [x0], x1 ld1 {v0.d}[1], [x0], x1 @@ -541,7 +545,7 @@ function inv_txfm_add_4x4_neon srshr v18.8h, v18.8h, #4 L(itx_4x4_end): - mvni v31.8h, #0xfc, lsl #8 // 0x3ff + dup v31.8h, w4 sub x0, x0, x1, lsl #2 usqadd v0.8h, v16.8h usqadd v1.8h, v18.8h @@ -579,8 +583,8 @@ function inv_txfm_add_\txfm1\()_\txfm2\()_4x4_16bpc_neon, export=1 b L(itx_4x4_end) 1: .endif - adr x4, inv_\txfm1\()_4s_x4_neon - movrel x5, X(inv_\txfm2\()_4h_x4_neon) + adr x5, inv_\txfm1\()_4s_x4_neon + movrel x6, X(inv_\txfm2\()_4h_x4_neon) b inv_txfm_add_4x4_neon endfunc .endm @@ -1381,6 +1385,10 @@ function inv_txfm_horz\suffix\()_16x4_neon sqrshrn2 v21.8h, v29.4s, #\shift sqrshrn2 v22.8h, v30.4s, #\shift sqrshrn2 v23.8h, v31.4s, #\shift +.if \scale + b L(horz_16x4_epilog) +.else +L(horz_16x4_epilog): transpose_4x8h v16, v17, v18, v19, v4, v5, v6, v7 transpose_4x8h v20, v21, v22, v23, v4, v5, v6, v7 @@ -1389,11 +1397,12 @@ function inv_txfm_horz\suffix\()_16x4_neon .endr ret x14 +.endif endfunc .endm -def_horz_16 scale=0, shift=2 def_horz_16 scale=1, shift=1, suffix=_scale +def_horz_16 scale=0, shift=2 function inv_txfm_add_vert_8x16_neon mov x14, x30 diff --git a/third_party/dav1d/src/arm/64/mc.S b/third_party/dav1d/src/arm/64/mc.S index 9f7b4e7a89..3df0393c3a 100644 --- a/third_party/dav1d/src/arm/64/mc.S +++ b/third_party/dav1d/src/arm/64/mc.S @@ -1154,7 +1154,7 @@ endfunc uxtl \r6\().8h, \r6\().8b .endif .endm -.macro mul_mla_4 d, s0, s1, s2, s3, wd +.macro mul_mla_4tap d, s0, s1, s2, s3, wd mul \d\wd, \s0\wd, v0.h[0] mla \d\wd, \s1\wd, v0.h[1] mla \d\wd, \s2\wd, v0.h[2] @@ -1163,7 +1163,51 @@ endfunc // Interleaving the mul/mla chains actually hurts performance // significantly on Cortex A53, thus keeping mul/mla tightly // chained like this. -.macro mul_mla_8_0_4h d0, s0, s1, s2, s3, s4, s5, s6, s7 +.macro mul_mla_6tap_0_4h d0, s0, s1, s2, s3, s4, s5, s6, s7 + mul \d0\().4h, \s1\().4h, v0.h[1] + mla \d0\().4h, \s2\().4h, v0.h[2] + mla \d0\().4h, \s3\().4h, v0.h[3] + mla \d0\().4h, \s4\().4h, v0.h[4] + mla \d0\().4h, \s5\().4h, v0.h[5] + mla \d0\().4h, \s6\().4h, v0.h[6] +.endm +.macro mul_mla_6tap_0 d0, s0, s1, s2, s3, s4, s5, s6, s7 + mul \d0\().8h, \s1\().8h, v0.h[1] + mla \d0\().8h, \s2\().8h, v0.h[2] + mla \d0\().8h, \s3\().8h, v0.h[3] + mla \d0\().8h, \s4\().8h, v0.h[4] + mla \d0\().8h, \s5\().8h, v0.h[5] + mla \d0\().8h, \s6\().8h, v0.h[6] +.endm +.macro mul_mla_6tap_1 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8 + mul \d0\().8h, \s1\().8h, v0.h[1] + mla \d0\().8h, \s2\().8h, v0.h[2] + mla \d0\().8h, \s3\().8h, v0.h[3] + mla \d0\().8h, \s4\().8h, v0.h[4] + mla \d0\().8h, \s5\().8h, v0.h[5] + mla \d0\().8h, \s6\().8h, v0.h[6] + mul \d1\().8h, \s2\().8h, v0.h[1] + mla \d1\().8h, \s3\().8h, v0.h[2] + mla \d1\().8h, \s4\().8h, v0.h[3] + mla \d1\().8h, \s5\().8h, v0.h[4] + mla \d1\().8h, \s6\().8h, v0.h[5] + mla \d1\().8h, \s7\().8h, v0.h[6] +.endm +.macro mul_mla_6tap_2 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 + mul \d0\().8h, \s1\().8h, v0.h[1] + mla \d0\().8h, \s2\().8h, v0.h[2] + mla \d0\().8h, \s3\().8h, v0.h[3] + mla \d0\().8h, \s4\().8h, v0.h[4] + mla \d0\().8h, \s5\().8h, v0.h[5] + mla \d0\().8h, \s6\().8h, v0.h[6] + mul \d1\().8h, \s3\().8h, v0.h[1] + mla \d1\().8h, \s4\().8h, v0.h[2] + mla \d1\().8h, \s5\().8h, v0.h[3] + mla \d1\().8h, \s6\().8h, v0.h[4] + mla \d1\().8h, \s7\().8h, v0.h[5] + mla \d1\().8h, \s8\().8h, v0.h[6] +.endm +.macro mul_mla_8tap_0_4h d0, s0, s1, s2, s3, s4, s5, s6, s7 mul \d0\().4h, \s0\().4h, v0.h[0] mla \d0\().4h, \s1\().4h, v0.h[1] mla \d0\().4h, \s2\().4h, v0.h[2] @@ -1173,7 +1217,7 @@ endfunc mla \d0\().4h, \s6\().4h, v0.h[6] mla \d0\().4h, \s7\().4h, v0.h[7] .endm -.macro mul_mla_8_0 d0, s0, s1, s2, s3, s4, s5, s6, s7 +.macro mul_mla_8tap_0 d0, s0, s1, s2, s3, s4, s5, s6, s7 mul \d0\().8h, \s0\().8h, v0.h[0] mla \d0\().8h, \s1\().8h, v0.h[1] mla \d0\().8h, \s2\().8h, v0.h[2] @@ -1183,7 +1227,7 @@ endfunc mla \d0\().8h, \s6\().8h, v0.h[6] mla \d0\().8h, \s7\().8h, v0.h[7] .endm -.macro mul_mla_8_1 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8 +.macro mul_mla_8tap_1 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8 mul \d0\().8h, \s0\().8h, v0.h[0] mla \d0\().8h, \s1\().8h, v0.h[1] mla \d0\().8h, \s2\().8h, v0.h[2] @@ -1201,7 +1245,7 @@ endfunc mla \d1\().8h, \s7\().8h, v0.h[6] mla \d1\().8h, \s8\().8h, v0.h[7] .endm -.macro mul_mla_8_2 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 +.macro mul_mla_8tap_2 d0, d1, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 mul \d0\().8h, \s0\().8h, v0.h[0] mla \d0\().8h, \s1\().8h, v0.h[1] mla \d0\().8h, \s2\().8h, v0.h[2] @@ -1315,11 +1359,11 @@ endfunc .endif .endm -.macro make_8tap_fn op, type, type_h, type_v +.macro make_8tap_fn op, type, type_h, type_v, taps function \op\()_8tap_\type\()_8bpc_neon, export=1 mov x8, \type_h mov x9, \type_v - b \op\()_8tap_neon + b \op\()_\taps\()_neon endfunc .endm @@ -1328,18 +1372,8 @@ endfunc #define SMOOTH ((1*15<<7)|4*15) #define SHARP ((2*15<<7)|3*15) -.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, ds2, sr2, shift_hv -make_8tap_fn \type, regular, REGULAR, REGULAR -make_8tap_fn \type, regular_smooth, REGULAR, SMOOTH -make_8tap_fn \type, regular_sharp, REGULAR, SHARP -make_8tap_fn \type, smooth, SMOOTH, SMOOTH -make_8tap_fn \type, smooth_regular, SMOOTH, REGULAR -make_8tap_fn \type, smooth_sharp, SMOOTH, SHARP -make_8tap_fn \type, sharp, SHARP, SHARP -make_8tap_fn \type, sharp_regular, SHARP, REGULAR -make_8tap_fn \type, sharp_smooth, SHARP, SMOOTH - -function \type\()_8tap_neon +.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, ds2, sr2, shift_hv, taps +function \type\()_\taps\()_neon mov w10, #0x4081 // (1 << 14) | (1 << 7) | (1 << 0) mul \mx, \mx, w10 mul \my, \my, w10 @@ -1354,12 +1388,12 @@ function \type\()_8tap_neon tst \mx, #(0x7f << 14) sub w8, w8, #24 movrel x10, X(mc_subpel_filters), -8 - b.ne L(\type\()_8tap_h) + b.ne L(\type\()_\taps\()_h) tst \my, #(0x7f << 14) - b.ne L(\type\()_8tap_v) + b.ne L(\type\()_\taps\()_v) b \type\()_neon -L(\type\()_8tap_h): +L(\type\()_\taps\()_h): cmp \w, #4 ubfx w9, \mx, #7, #7 and \mx, \mx, #0x7f @@ -1368,9 +1402,9 @@ L(\type\()_8tap_h): 4: tst \my, #(0x7f << 14) add \xmx, x10, \mx, uxtw #3 - b.ne L(\type\()_8tap_hv) + b.ne L(\type\()_\taps\()_hv) - adr x9, L(\type\()_8tap_h_tbl) + adr x9, L(\type\()_\taps\()_h_tbl) ldrh w8, [x9, x8, lsl #1] sub x9, x9, w8, uxtw br x9 @@ -1471,6 +1505,18 @@ L(\type\()_8tap_h): uxtl v20.8h, v20.8b uxtl v21.8h, v21.8b +.ifc \taps, 6tap + ext v19.16b, v16.16b, v17.16b, #2 + ext v23.16b, v20.16b, v21.16b, #2 + mul v18.8h, v19.8h, v0.h[1] + mul v22.8h, v23.8h, v0.h[1] +.irpc i, 23456 + ext v19.16b, v16.16b, v17.16b, #(2*\i) + ext v23.16b, v20.16b, v21.16b, #(2*\i) + mla v18.8h, v19.8h, v0.h[\i] + mla v22.8h, v23.8h, v0.h[\i] +.endr +.else // 8tap mul v18.8h, v16.8h, v0.h[0] mul v22.8h, v20.8h, v0.h[0] .irpc i, 1234567 @@ -1479,6 +1525,7 @@ L(\type\()_8tap_h): mla v18.8h, v19.8h, v0.h[\i] mla v22.8h, v23.8h, v0.h[\i] .endr +.endif subs \h, \h, #2 srshr v18.8h, v18.8h, #2 srshr v22.8h, v22.8h, #2 @@ -1523,6 +1570,26 @@ L(\type\()_8tap_h): uxtl v22.8h, v22.8b 16: +.ifc \taps, 6tap + ext v28.16b, v16.16b, v17.16b, #2 + ext v29.16b, v17.16b, v18.16b, #2 + ext v30.16b, v20.16b, v21.16b, #2 + ext v31.16b, v21.16b, v22.16b, #2 + mul v24.8h, v28.8h, v0.h[1] + mul v25.8h, v29.8h, v0.h[1] + mul v26.8h, v30.8h, v0.h[1] + mul v27.8h, v31.8h, v0.h[1] +.irpc i, 23456 + ext v28.16b, v16.16b, v17.16b, #(2*\i) + ext v29.16b, v17.16b, v18.16b, #(2*\i) + ext v30.16b, v20.16b, v21.16b, #(2*\i) + ext v31.16b, v21.16b, v22.16b, #(2*\i) + mla v24.8h, v28.8h, v0.h[\i] + mla v25.8h, v29.8h, v0.h[\i] + mla v26.8h, v30.8h, v0.h[\i] + mla v27.8h, v31.8h, v0.h[\i] +.endr +.else // 8tap mul v24.8h, v16.8h, v0.h[0] mul v25.8h, v17.8h, v0.h[0] mul v26.8h, v20.8h, v0.h[0] @@ -1537,6 +1604,7 @@ L(\type\()_8tap_h): mla v26.8h, v30.8h, v0.h[\i] mla v27.8h, v31.8h, v0.h[\i] .endr +.endif srshr v24.8h, v24.8h, #2 srshr v25.8h, v25.8h, #2 srshr v26.8h, v26.8h, #2 @@ -1575,18 +1643,18 @@ L(\type\()_8tap_h): b.gt 161b ret -L(\type\()_8tap_h_tbl): - .hword L(\type\()_8tap_h_tbl) - 1280b - .hword L(\type\()_8tap_h_tbl) - 640b - .hword L(\type\()_8tap_h_tbl) - 320b - .hword L(\type\()_8tap_h_tbl) - 160b - .hword L(\type\()_8tap_h_tbl) - 80b - .hword L(\type\()_8tap_h_tbl) - 40b - .hword L(\type\()_8tap_h_tbl) - 20b +L(\type\()_\taps\()_h_tbl): + .hword L(\type\()_\taps\()_h_tbl) - 1280b + .hword L(\type\()_\taps\()_h_tbl) - 640b + .hword L(\type\()_\taps\()_h_tbl) - 320b + .hword L(\type\()_\taps\()_h_tbl) - 160b + .hword L(\type\()_\taps\()_h_tbl) - 80b + .hword L(\type\()_\taps\()_h_tbl) - 40b + .hword L(\type\()_\taps\()_h_tbl) - 20b .hword 0 -L(\type\()_8tap_v): +L(\type\()_\taps\()_v): cmp \h, #4 ubfx w9, \my, #7, #7 and \my, \my, #0x7f @@ -1595,7 +1663,7 @@ L(\type\()_8tap_v): 4: add \xmy, x10, \my, uxtw #3 - adr x9, L(\type\()_8tap_v_tbl) + adr x9, L(\type\()_\taps\()_v_tbl) ldrh w8, [x9, x8, lsl #1] sub x9, x9, w8, uxtw br x9 @@ -1620,7 +1688,7 @@ L(\type\()_8tap_v): interleave_1_h v1, v2, v3, v4, v5 b.gt 24f uxtl_b v1, v2, v3, v4 - mul_mla_4 v6, v1, v2, v3, v4, .4h + mul_mla_4tap v6, v1, v2, v3, v4, .4h sqrshrun_b 6, v6 st_h \d_strd, v6, 2 ret @@ -1630,7 +1698,7 @@ L(\type\()_8tap_v): interleave_1_h v5, v6, v7 interleave_2_s v1, v2, v3, v4, v5, v6 uxtl_b v1, v2, v3, v4 - mul_mla_4 v6, v1, v2, v3, v4, .8h + mul_mla_4tap v6, v1, v2, v3, v4, .8h sqrshrun_b 6, v6 st_h \d_strd, v6, 4 ret @@ -1655,7 +1723,7 @@ L(\type\()_8tap_v): interleave_1_h v7, v16, v17, v18, v19 interleave_2_s v5, v6, v7, v16, v17, v18 uxtl_b v5, v6, v7, v16 - mul_mla_8_0 v30, v1, v2, v3, v4, v5, v6, v7, v16 + mul_mla_\taps\()_0 v30, v1, v2, v3, v4, v5, v6, v7, v16 sqrshrun_b 6, v30 st_h \d_strd, v30, 4 b.le 0f @@ -1673,7 +1741,7 @@ L(\type\()_8tap_v): load_h \sr2, \src, \s_strd, v16, v17 interleave_1_h v7, v16, v17 uxtl_b v5, v6, v7, v16 - mul_mla_8_0_4h v30, v1, v2, v3, v4, v5, v6, v7, v16 + mul_mla_\taps\()_0_4h v30, v1, v2, v3, v4, v5, v6, v7, v16 sqrshrun_b 6, v30 st_h \d_strd, v30, 2 0: @@ -1698,13 +1766,13 @@ L(\type\()_8tap_v): load_s \src, \sr2, \s_strd, v1, v2, v3, v4, v5 interleave_1_s v1, v2, v3, v4, v5 uxtl_b v1, v2, v3, v4 - mul_mla_4 v6, v1, v2, v3, v4, .8h + mul_mla_4tap v6, v1, v2, v3, v4, .8h shift_store_4 \type, \d_strd, v6 b.le 0f load_s \sr2, \src, \s_strd, v6, v7 interleave_1_s v5, v6, v7 uxtl_b v5, v6 - mul_mla_4 v7, v3, v4, v5, v6, .8h + mul_mla_4tap v7, v3, v4, v5, v6, .8h shift_store_4 \type, \d_strd, v7 0: ret @@ -1729,28 +1797,28 @@ L(\type\()_8tap_v): load_s \sr2, \src, \s_strd, v23, v24, v25, v26 interleave_1_s v22, v23, v24, v25, v26 uxtl_b v22, v23, v24, v25 - mul_mla_8_2 v1, v2, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 + mul_mla_\taps\()_2 v1, v2, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 shift_store_4 \type, \d_strd, v1, v2 b.le 0f load_s \sr2, \src, \s_strd, v27, v16 subs \h, \h, #2 interleave_1_s v26, v27, v16 uxtl_b v26, v27 - mul_mla_8_0 v1, v20, v21, v22, v23, v24, v25, v26, v27 + mul_mla_\taps\()_0 v1, v20, v21, v22, v23, v24, v25, v26, v27 shift_store_4 \type, \d_strd, v1 b.le 0f load_s \sr2, \src, \s_strd, v17, v18 subs \h, \h, #2 interleave_1_s v16, v17, v18 uxtl_b v16, v17 - mul_mla_8_0 v2, v22, v23, v24, v25, v26, v27, v16, v17 + mul_mla_\taps\()_0 v2, v22, v23, v24, v25, v26, v27, v16, v17 shift_store_4 \type, \d_strd, v2 b.le 0f subs \h, \h, #4 load_s \sr2, \src, \s_strd, v19, v20, v21, v22 interleave_1_s v18, v19, v20, v21, v22 uxtl_b v18, v19, v20, v21 - mul_mla_8_2 v1, v2, v24, v25, v26, v27, v16, v17, v18, v19, v20, v21 + mul_mla_\taps\()_2 v1, v2, v24, v25, v26, v27, v16, v17, v18, v19, v20, v21 shift_store_4 \type, \d_strd, v1, v2 b.gt 48b 0: @@ -1773,14 +1841,14 @@ L(\type\()_8tap_v): load_8b \src, \sr2, \s_strd, v1, v2, v3, v4, v5 uxtl_b v1, v2, v3, v4, v5 - mul_mla_4 v6, v1, v2, v3, v4, .8h - mul_mla_4 v7, v2, v3, v4, v5, .8h + mul_mla_4tap v6, v1, v2, v3, v4, .8h + mul_mla_4tap v7, v2, v3, v4, v5, .8h shift_store_8 \type, \d_strd, v6, v7 b.le 0f load_8b \sr2, \src, \s_strd, v6, v7 uxtl_b v6, v7 - mul_mla_4 v1, v3, v4, v5, v6, .8h - mul_mla_4 v2, v4, v5, v6, v7, .8h + mul_mla_4tap v1, v3, v4, v5, v6, .8h + mul_mla_4tap v2, v4, v5, v6, v7, .8h shift_store_8 \type, \d_strd, v1, v2 0: ret @@ -1809,32 +1877,32 @@ L(\type\()_8tap_v): subs \h, \h, #2 load_8b \sr2, \src, \s_strd, v23, v24 uxtl_b v23, v24 - mul_mla_8_1 v1, v2, v16, v17, v18, v19, v20, v21, v22, v23, v24 + mul_mla_\taps\()_1 v1, v2, v16, v17, v18, v19, v20, v21, v22, v23, v24 shift_store_8 \type, \d_strd, v1, v2 b.le 9f subs \h, \h, #2 load_8b \sr2, \src, \s_strd, v25, v26 uxtl_b v25, v26 - mul_mla_8_1 v3, v4, v18, v19, v20, v21, v22, v23, v24, v25, v26 + mul_mla_\taps\()_1 v3, v4, v18, v19, v20, v21, v22, v23, v24, v25, v26 shift_store_8 \type, \d_strd, v3, v4 b.le 9f subs \h, \h, #2 load_8b \sr2, \src, \s_strd, v27, v16 uxtl_b v27, v16 - mul_mla_8_1 v1, v2, v20, v21, v22, v23, v24, v25, v26, v27, v16 + mul_mla_\taps\()_1 v1, v2, v20, v21, v22, v23, v24, v25, v26, v27, v16 shift_store_8 \type, \d_strd, v1, v2 b.le 9f subs \h, \h, #2 load_8b \sr2, \src, \s_strd, v17, v18 uxtl_b v17, v18 - mul_mla_8_1 v3, v4, v22, v23, v24, v25, v26, v27, v16, v17, v18 + mul_mla_\taps\()_1 v3, v4, v22, v23, v24, v25, v26, v27, v16, v17, v18 shift_store_8 \type, \d_strd, v3, v4 b.le 9f subs \h, \h, #4 load_8b \sr2, \src, \s_strd, v19, v20, v21, v22 uxtl_b v19, v20, v21, v22 - mul_mla_8_1 v1, v2, v24, v25, v26, v27, v16, v17, v18, v19, v20 - mul_mla_8_1 v3, v4, v26, v27, v16, v17, v18, v19, v20, v21, v22 + mul_mla_\taps\()_1 v1, v2, v24, v25, v26, v27, v16, v17, v18, v19, v20 + mul_mla_\taps\()_1 v3, v4, v26, v27, v16, v17, v18, v19, v20, v21, v22 shift_store_8 \type, \d_strd, v1, v2, v3, v4 b.gt 88b 9: @@ -1882,10 +1950,10 @@ L(\type\()_8tap_v): uxtl2 v25.8h, v3.16b uxtl2 v26.8h, v4.16b uxtl2 v27.8h, v5.16b - mul_mla_4 v1, v16, v17, v18, v19, .8h - mul_mla_4 v16, v17, v18, v19, v20, .8h - mul_mla_4 v2, v23, v24, v25, v26, .8h - mul_mla_4 v17, v24, v25, v26, v27, .8h + mul_mla_4tap v1, v16, v17, v18, v19, .8h + mul_mla_4tap v16, v17, v18, v19, v20, .8h + mul_mla_4tap v2, v23, v24, v25, v26, .8h + mul_mla_4tap v17, v24, v25, v26, v27, .8h shift_store_16 \type, \d_strd, v1, v2, v16, v17 b.le 0f load_16b \sr2, \src, \s_strd, v6, v7 @@ -1893,25 +1961,25 @@ L(\type\()_8tap_v): uxtl v22.8h, v7.8b uxtl2 v28.8h, v6.16b uxtl2 v29.8h, v7.16b - mul_mla_4 v1, v18, v19, v20, v21, .8h - mul_mla_4 v3, v19, v20, v21, v22, .8h - mul_mla_4 v2, v25, v26, v27, v28, .8h - mul_mla_4 v4, v26, v27, v28, v29, .8h + mul_mla_4tap v1, v18, v19, v20, v21, .8h + mul_mla_4tap v3, v19, v20, v21, v22, .8h + mul_mla_4tap v2, v25, v26, v27, v28, .8h + mul_mla_4tap v4, v26, v27, v28, v29, .8h shift_store_16 \type, \d_strd, v1, v2, v3, v4 0: ret -L(\type\()_8tap_v_tbl): - .hword L(\type\()_8tap_v_tbl) - 1280b - .hword L(\type\()_8tap_v_tbl) - 640b - .hword L(\type\()_8tap_v_tbl) - 320b - .hword L(\type\()_8tap_v_tbl) - 160b - .hword L(\type\()_8tap_v_tbl) - 80b - .hword L(\type\()_8tap_v_tbl) - 40b - .hword L(\type\()_8tap_v_tbl) - 20b +L(\type\()_\taps\()_v_tbl): + .hword L(\type\()_\taps\()_v_tbl) - 1280b + .hword L(\type\()_\taps\()_v_tbl) - 640b + .hword L(\type\()_\taps\()_v_tbl) - 320b + .hword L(\type\()_\taps\()_v_tbl) - 160b + .hword L(\type\()_\taps\()_v_tbl) - 80b + .hword L(\type\()_\taps\()_v_tbl) - 40b + .hword L(\type\()_\taps\()_v_tbl) - 20b .hword 0 -L(\type\()_8tap_hv): +L(\type\()_\taps\()_hv): cmp \h, #4 ubfx w9, \my, #7, #7 and \my, \my, #0x7f @@ -1920,7 +1988,7 @@ L(\type\()_8tap_hv): 4: add \xmy, x10, \my, uxtw #3 - adr x9, L(\type\()_8tap_hv_tbl) + adr x9, L(\type\()_\taps\()_hv_tbl) ldrh w8, [x9, x8, lsl #1] sub x9, x9, w8, uxtw br x9 @@ -1952,13 +2020,13 @@ L(\type\()_8tap_hv): addp v28.4h, v28.4h, v29.4h addp v16.4h, v28.4h, v28.4h srshr v16.4h, v16.4h, #2 - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) trn1 v16.2s, v16.2s, v28.2s mov v17.8b, v28.8b 2: - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) ext v18.8b, v17.8b, v28.8b, #4 smull v2.4s, v16.4h, v1.h[0] @@ -1997,19 +2065,27 @@ L(\type\()_8tap_hv): addp v16.4h, v28.4h, v28.4h srshr v16.4h, v16.4h, #2 - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) trn1 v16.2s, v16.2s, v28.2s mov v17.8b, v28.8b - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) ext v18.8b, v17.8b, v28.8b, #4 mov v19.8b, v28.8b - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) ext v20.8b, v19.8b, v28.8b, #4 mov v21.8b, v28.8b 28: - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) ext v22.8b, v21.8b, v28.8b, #4 +.ifc \taps, 6tap + smull v2.4s, v17.4h, v1.h[1] + smlal v2.4s, v18.4h, v1.h[2] + smlal v2.4s, v19.4h, v1.h[3] + smlal v2.4s, v20.4h, v1.h[4] + smlal v2.4s, v21.4h, v1.h[5] + smlal v2.4s, v22.4h, v1.h[6] +.else // 8tap smull v2.4s, v16.4h, v1.h[0] smlal v2.4s, v17.4h, v1.h[1] smlal v2.4s, v18.4h, v1.h[2] @@ -2018,6 +2094,7 @@ L(\type\()_8tap_hv): smlal v2.4s, v21.4h, v1.h[5] smlal v2.4s, v22.4h, v1.h[6] smlal v2.4s, v28.4h, v1.h[7] +.endif sqrshrn v2.4h, v2.4s, #\shift_hv sqxtun v2.8b, v2.8h @@ -2036,7 +2113,7 @@ L(\type\()_8tap_hv): 0: ret x15 -L(\type\()_8tap_filter_2): +L(\type\()_\taps\()_filter_2): ld1 {v28.8b}, [\sr2], \s_strd ld1 {v30.8b}, [\src], \s_strd uxtl v28.8h, v28.8b @@ -2083,12 +2160,12 @@ L(\type\()_8tap_filter_2): mla v31.4h, v30.4h, v0.h[3] srshr v16.4h, v31.4h, #2 - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) mov v17.8b, v28.8b mov v18.8b, v29.8b 4: - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) // Interleaving the mul/mla chains actually hurts performance // significantly on Cortex A53, thus keeping mul/mla tightly // chained like this. @@ -2121,8 +2198,13 @@ L(\type\()_8tap_filter_2): 480: // 4x8, 4x16, 4x32 hv ld1 {v1.8b}, [\xmy] sub \src, \src, #1 +.ifc \taps, 6tap + sub \sr2, \src, \s_strd + sub \src, \src, \s_strd, lsl #1 +.else sub \sr2, \src, \s_strd, lsl #1 sub \src, \sr2, \s_strd +.endif add \ds2, \dst, \d_strd lsl \s_strd, \s_strd, #1 lsl \d_strd, \d_strd, #1 @@ -2139,20 +2221,38 @@ L(\type\()_8tap_filter_2): mla v31.4h, v28.4h, v0.h[1] mla v31.4h, v29.4h, v0.h[2] mla v31.4h, v30.4h, v0.h[3] +.ifc \taps, 6tap + srshr v18.4h, v31.4h, #2 +.else srshr v16.4h, v31.4h, #2 - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) mov v17.8b, v28.8b mov v18.8b, v29.8b - bl L(\type\()_8tap_filter_4) +.endif + bl L(\type\()_\taps\()_filter_4) mov v19.8b, v28.8b mov v20.8b, v29.8b - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) mov v21.8b, v28.8b mov v22.8b, v29.8b 48: - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) +.ifc \taps, 6tap + smull v2.4s, v18.4h, v1.h[1] + smlal v2.4s, v19.4h, v1.h[2] + smlal v2.4s, v20.4h, v1.h[3] + smlal v2.4s, v21.4h, v1.h[4] + smlal v2.4s, v22.4h, v1.h[5] + smlal v2.4s, v28.4h, v1.h[6] + smull v3.4s, v19.4h, v1.h[1] + smlal v3.4s, v20.4h, v1.h[2] + smlal v3.4s, v21.4h, v1.h[3] + smlal v3.4s, v22.4h, v1.h[4] + smlal v3.4s, v28.4h, v1.h[5] + smlal v3.4s, v29.4h, v1.h[6] +.else // 8tap smull v2.4s, v16.4h, v1.h[0] smlal v2.4s, v17.4h, v1.h[1] smlal v2.4s, v18.4h, v1.h[2] @@ -2169,6 +2269,7 @@ L(\type\()_8tap_filter_2): smlal v3.4s, v22.4h, v1.h[5] smlal v3.4s, v28.4h, v1.h[6] smlal v3.4s, v29.4h, v1.h[7] +.endif sqrshrn v2.4h, v2.4s, #\shift_hv sqrshrn v3.4h, v3.4s, #\shift_hv subs \h, \h, #2 @@ -2182,8 +2283,10 @@ L(\type\()_8tap_filter_2): st1 {v3.4h}, [\ds2], \d_strd .endif b.le 0f +.ifc \taps, 8tap mov v16.8b, v18.8b mov v17.8b, v19.8b +.endif mov v18.8b, v20.8b mov v19.8b, v21.8b mov v20.8b, v22.8b @@ -2193,7 +2296,7 @@ L(\type\()_8tap_filter_2): 0: ret x15 -L(\type\()_8tap_filter_4): +L(\type\()_\taps\()_filter_4): ld1 {v26.8b}, [\sr2], \s_strd ld1 {v27.8b}, [\src], \s_strd uxtl v26.8h, v26.8b @@ -2237,15 +2340,15 @@ L(\type\()_8tap_filter_4): lsl \d_strd, \d_strd, #1 lsl \s_strd, \s_strd, #1 - bl L(\type\()_8tap_filter_8_first) - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8_first) + bl L(\type\()_\taps\()_filter_8) mov v17.16b, v24.16b mov v18.16b, v25.16b 8: smull v2.4s, v16.4h, v1.h[0] smull2 v3.4s, v16.8h, v1.h[0] - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8) smull v4.4s, v17.4h, v1.h[0] smull2 v5.4s, v17.8h, v1.h[0] smlal v2.4s, v17.4h, v1.h[1] @@ -2303,7 +2406,9 @@ L(\type\()_8tap_filter_4): ld1 {v0.8b}, [\xmx] ld1 {v1.8b}, [\xmy] sub \src, \src, #3 +.ifc \taps, 8tap sub \src, \src, \s_strd +.endif sub \src, \src, \s_strd, lsl #1 sxtl v0.8h, v0.8b sxtl v1.8h, v1.8b @@ -2316,21 +2421,52 @@ L(\type\()_8tap_filter_4): lsl \d_strd, \d_strd, #1 lsl \s_strd, \s_strd, #1 - bl L(\type\()_8tap_filter_8_first) - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8_first) +.ifc \taps, 6tap + mov v18.16b, v16.16b +.else + bl L(\type\()_\taps\()_filter_8) mov v17.16b, v24.16b mov v18.16b, v25.16b - bl L(\type\()_8tap_filter_8) +.endif + bl L(\type\()_\taps\()_filter_8) mov v19.16b, v24.16b mov v20.16b, v25.16b - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8) mov v21.16b, v24.16b mov v22.16b, v25.16b 88: +.ifc \taps, 6tap + smull v2.4s, v18.4h, v1.h[1] + smull2 v3.4s, v18.8h, v1.h[1] + bl L(\type\()_\taps\()_filter_8) + smull v4.4s, v19.4h, v1.h[1] + smull2 v5.4s, v19.8h, v1.h[1] + smlal v2.4s, v19.4h, v1.h[2] + smlal2 v3.4s, v19.8h, v1.h[2] + smlal v4.4s, v20.4h, v1.h[2] + smlal2 v5.4s, v20.8h, v1.h[2] + smlal v2.4s, v20.4h, v1.h[3] + smlal2 v3.4s, v20.8h, v1.h[3] + smlal v4.4s, v21.4h, v1.h[3] + smlal2 v5.4s, v21.8h, v1.h[3] + smlal v2.4s, v21.4h, v1.h[4] + smlal2 v3.4s, v21.8h, v1.h[4] + smlal v4.4s, v22.4h, v1.h[4] + smlal2 v5.4s, v22.8h, v1.h[4] + smlal v2.4s, v22.4h, v1.h[5] + smlal2 v3.4s, v22.8h, v1.h[5] + smlal v4.4s, v24.4h, v1.h[5] + smlal2 v5.4s, v24.8h, v1.h[5] + smlal v2.4s, v24.4h, v1.h[6] + smlal2 v3.4s, v24.8h, v1.h[6] + smlal v4.4s, v25.4h, v1.h[6] + smlal2 v5.4s, v25.8h, v1.h[6] +.else // 8tap smull v2.4s, v16.4h, v1.h[0] smull2 v3.4s, v16.8h, v1.h[0] - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8) smull v4.4s, v17.4h, v1.h[0] smull2 v5.4s, v17.8h, v1.h[0] smlal v2.4s, v17.4h, v1.h[1] @@ -2361,6 +2497,7 @@ L(\type\()_8tap_filter_4): smlal2 v3.4s, v24.8h, v1.h[7] smlal v4.4s, v25.4h, v1.h[7] smlal2 v5.4s, v25.8h, v1.h[7] +.endif sqrshrn v2.4h, v2.4s, #\shift_hv sqrshrn2 v2.8h, v3.4s, #\shift_hv sqrshrn v4.4h, v4.4s, #\shift_hv @@ -2376,8 +2513,10 @@ L(\type\()_8tap_filter_4): st1 {v4.8h}, [\ds2], \d_strd .endif b.le 9f +.ifc \taps, 8tap mov v16.16b, v18.16b mov v17.16b, v19.16b +.endif mov v18.16b, v20.16b mov v19.16b, v21.16b mov v20.16b, v22.16b @@ -2398,15 +2537,33 @@ L(\type\()_8tap_filter_4): add \dst, \dst, #8 .else add \dst, \dst, #16 +.endif +.ifc \taps, 6tap + add \src, \src, \s_strd, lsl #1 .endif b 168b 0: ret x15 -L(\type\()_8tap_filter_8_first): +L(\type\()_\taps\()_filter_8_first): ld1 {v28.8b, v29.8b}, [\src], \s_strd uxtl v28.8h, v28.8b uxtl v29.8h, v29.8b +.ifc \taps, 6tap + ext v24.16b, v28.16b, v29.16b, #(2*1) + ext v25.16b, v28.16b, v29.16b, #(2*2) + ext v26.16b, v28.16b, v29.16b, #(2*3) + ext v27.16b, v28.16b, v29.16b, #(2*4) + mul v16.8h, v24.8h, v0.h[1] + mla v16.8h, v25.8h, v0.h[2] + mla v16.8h, v26.8h, v0.h[3] + mla v16.8h, v27.8h, v0.h[4] + ext v24.16b, v28.16b, v29.16b, #(2*5) + ext v25.16b, v28.16b, v29.16b, #(2*6) + ext v26.16b, v28.16b, v29.16b, #(2*7) + mla v16.8h, v24.8h, v0.h[5] + mla v16.8h, v25.8h, v0.h[6] +.else // 8tap mul v16.8h, v28.8h, v0.h[0] ext v24.16b, v28.16b, v29.16b, #(2*1) ext v25.16b, v28.16b, v29.16b, #(2*2) @@ -2422,16 +2579,29 @@ L(\type\()_8tap_filter_8_first): mla v16.8h, v24.8h, v0.h[5] mla v16.8h, v25.8h, v0.h[6] mla v16.8h, v26.8h, v0.h[7] +.endif srshr v16.8h, v16.8h, #2 ret -L(\type\()_8tap_filter_8): +L(\type\()_\taps\()_filter_8): ld1 {v28.8b, v29.8b}, [\sr2], \s_strd ld1 {v30.8b, v31.8b}, [\src], \s_strd uxtl v28.8h, v28.8b uxtl v29.8h, v29.8b uxtl v30.8h, v30.8b uxtl v31.8h, v31.8b +.ifc \taps, 6tap + ext v26.16b, v28.16b, v29.16b, #2 + ext v27.16b, v30.16b, v31.16b, #2 + mul v24.8h, v26.8h, v0.h[1] + mul v25.8h, v27.8h, v0.h[1] +.irpc i, 23456 + ext v26.16b, v28.16b, v29.16b, #(2*\i) + ext v27.16b, v30.16b, v31.16b, #(2*\i) + mla v24.8h, v26.8h, v0.h[\i] + mla v25.8h, v27.8h, v0.h[\i] +.endr +.else // 8tap mul v24.8h, v28.8h, v0.h[0] mul v25.8h, v30.8h, v0.h[0] .irpc i, 1234567 @@ -2440,22 +2610,25 @@ L(\type\()_8tap_filter_8): mla v24.8h, v26.8h, v0.h[\i] mla v25.8h, v27.8h, v0.h[\i] .endr +.endif srshr v24.8h, v24.8h, #2 srshr v25.8h, v25.8h, #2 ret -L(\type\()_8tap_hv_tbl): - .hword L(\type\()_8tap_hv_tbl) - 1280b - .hword L(\type\()_8tap_hv_tbl) - 640b - .hword L(\type\()_8tap_hv_tbl) - 320b - .hword L(\type\()_8tap_hv_tbl) - 160b - .hword L(\type\()_8tap_hv_tbl) - 80b - .hword L(\type\()_8tap_hv_tbl) - 40b - .hword L(\type\()_8tap_hv_tbl) - 20b +L(\type\()_\taps\()_hv_tbl): + .hword L(\type\()_\taps\()_hv_tbl) - 1280b + .hword L(\type\()_\taps\()_hv_tbl) - 640b + .hword L(\type\()_\taps\()_hv_tbl) - 320b + .hword L(\type\()_\taps\()_hv_tbl) - 160b + .hword L(\type\()_\taps\()_hv_tbl) - 80b + .hword L(\type\()_\taps\()_hv_tbl) - 40b + .hword L(\type\()_\taps\()_hv_tbl) - 20b .hword 0 endfunc +.endm +.macro filter_bilin_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, ds2, sr2, shift_hv function \type\()_bilin_8bpc_neon, export=1 dup v1.16b, \mx dup v3.16b, \my @@ -2987,8 +3160,34 @@ L(\type\()_bilin_hv_tbl): endfunc .endm -filter_fn put, x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, x8, x9, 10 -filter_fn prep, x0, x7, x1, x2, w3, w4, w5, x5, w6, x6, x8, x9, 6 +make_8tap_fn put, regular_sharp, REGULAR, SHARP, 8tap +make_8tap_fn put, smooth_sharp, SMOOTH, SHARP, 8tap +make_8tap_fn put, sharp, SHARP, SHARP, 8tap +make_8tap_fn put, sharp_regular, SHARP, REGULAR, 8tap +make_8tap_fn put, sharp_smooth, SHARP, SMOOTH, 8tap +filter_fn put, x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, x8, x9, 10, 8tap + +make_8tap_fn put, regular, REGULAR, REGULAR, 6tap +make_8tap_fn put, regular_smooth, REGULAR, SMOOTH, 6tap +make_8tap_fn put, smooth, SMOOTH, SMOOTH, 6tap +make_8tap_fn put, smooth_regular, SMOOTH, REGULAR, 6tap +filter_fn put, x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, x8, x9, 10, 6tap +filter_bilin_fn put, x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, x8, x9, 10 + +make_8tap_fn prep, regular_sharp, REGULAR, SHARP, 8tap +make_8tap_fn prep, smooth_sharp, SMOOTH, SHARP, 8tap +make_8tap_fn prep, sharp, SHARP, SHARP, 8tap +make_8tap_fn prep, sharp_regular, SHARP, REGULAR, 8tap +make_8tap_fn prep, sharp_smooth, SHARP, SMOOTH, 8tap +filter_fn prep, x0, x7, x1, x2, w3, w4, w5, x5, w6, x6, x8, x9, 6, 8tap + +make_8tap_fn prep, regular, REGULAR, REGULAR, 6tap +make_8tap_fn prep, regular_smooth, REGULAR, SMOOTH, 6tap +make_8tap_fn prep, smooth, SMOOTH, SMOOTH, 6tap +make_8tap_fn prep, smooth_regular, SMOOTH, REGULAR, 6tap +filter_fn prep, x0, x7, x1, x2, w3, w4, w5, x5, w6, x6, x8, x9, 6, 6tap +filter_bilin_fn prep, x0, x7, x1, x2, w3, w4, w5, x5, w6, x6, x8, x9, 6 + .macro load_filter_row dst, src, inc asr w13, \src, #10 diff --git a/third_party/dav1d/src/arm/64/mc16.S b/third_party/dav1d/src/arm/64/mc16.S index 1bfb12ebb3..576fab158a 100644 --- a/third_party/dav1d/src/arm/64/mc16.S +++ b/third_party/dav1d/src/arm/64/mc16.S @@ -1374,19 +1374,35 @@ endfunc sub \r3\wd, \r3\wd, \c\wd .endif .endm -.macro smull_smlal_4 d, s0, s1, s2, s3 +.macro smull_smlal_4tap d, s0, s1, s2, s3 smull \d\().4s, \s0\().4h, v0.h[0] smlal \d\().4s, \s1\().4h, v0.h[1] smlal \d\().4s, \s2\().4h, v0.h[2] smlal \d\().4s, \s3\().4h, v0.h[3] .endm -.macro smull2_smlal2_4 d, s0, s1, s2, s3 +.macro smull2_smlal2_4tap d, s0, s1, s2, s3 smull2 \d\().4s, \s0\().8h, v0.h[0] smlal2 \d\().4s, \s1\().8h, v0.h[1] smlal2 \d\().4s, \s2\().8h, v0.h[2] smlal2 \d\().4s, \s3\().8h, v0.h[3] .endm -.macro smull_smlal_8 d, s0, s1, s2, s3, s4, s5, s6, s7 +.macro smull_smlal_6tap d, s0, s1, s2, s3, s4, s5, s6, s7 + smull \d\().4s, \s1\().4h, v0.h[1] + smlal \d\().4s, \s2\().4h, v0.h[2] + smlal \d\().4s, \s3\().4h, v0.h[3] + smlal \d\().4s, \s4\().4h, v0.h[4] + smlal \d\().4s, \s5\().4h, v0.h[5] + smlal \d\().4s, \s6\().4h, v0.h[6] +.endm +.macro smull2_smlal2_6tap d, s0, s1, s2, s3, s4, s5, s6, s7 + smull2 \d\().4s, \s1\().8h, v0.h[1] + smlal2 \d\().4s, \s2\().8h, v0.h[2] + smlal2 \d\().4s, \s3\().8h, v0.h[3] + smlal2 \d\().4s, \s4\().8h, v0.h[4] + smlal2 \d\().4s, \s5\().8h, v0.h[5] + smlal2 \d\().4s, \s6\().8h, v0.h[6] +.endm +.macro smull_smlal_8tap d, s0, s1, s2, s3, s4, s5, s6, s7 smull \d\().4s, \s0\().4h, v0.h[0] smlal \d\().4s, \s1\().4h, v0.h[1] smlal \d\().4s, \s2\().4h, v0.h[2] @@ -1396,7 +1412,7 @@ endfunc smlal \d\().4s, \s6\().4h, v0.h[6] smlal \d\().4s, \s7\().4h, v0.h[7] .endm -.macro smull2_smlal2_8 d, s0, s1, s2, s3, s4, s5, s6, s7 +.macro smull2_smlal2_8tap d, s0, s1, s2, s3, s4, s5, s6, s7 smull2 \d\().4s, \s0\().8h, v0.h[0] smlal2 \d\().4s, \s1\().8h, v0.h[1] smlal2 \d\().4s, \s2\().8h, v0.h[2] @@ -1499,11 +1515,11 @@ endfunc st1 {\r0\().8h, \r1\().8h}, [\dst], \strd .endm -.macro make_8tap_fn op, type, type_h, type_v +.macro make_8tap_fn op, type, type_h, type_v, taps function \op\()_8tap_\type\()_16bpc_neon, export=1 mov w9, \type_h mov w10, \type_v - b \op\()_8tap_neon + b \op\()_\taps\()_neon endfunc .endm @@ -1512,18 +1528,8 @@ endfunc #define SMOOTH ((1*15<<7)|4*15) #define SHARP ((2*15<<7)|3*15) -.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, bdmax, ds2, sr2 -make_8tap_fn \type, regular, REGULAR, REGULAR -make_8tap_fn \type, regular_smooth, REGULAR, SMOOTH -make_8tap_fn \type, regular_sharp, REGULAR, SHARP -make_8tap_fn \type, smooth, SMOOTH, SMOOTH -make_8tap_fn \type, smooth_regular, SMOOTH, REGULAR -make_8tap_fn \type, smooth_sharp, SMOOTH, SHARP -make_8tap_fn \type, sharp, SHARP, SHARP -make_8tap_fn \type, sharp_regular, SHARP, REGULAR -make_8tap_fn \type, sharp_smooth, SHARP, SMOOTH - -function \type\()_8tap_neon +.macro filter_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, bdmax, ds2, sr2, taps +function \type\()_\taps\()_neon .ifc \bdmax, w8 ldr w8, [sp] .endif @@ -1547,12 +1553,12 @@ function \type\()_8tap_neon add w13, w12, \bdmax // 6 + intermediate_bits sub w12, w12, \bdmax // 6 - intermediate_bits movrel x11, X(mc_subpel_filters), -8 - b.ne L(\type\()_8tap_h) + b.ne L(\type\()_\taps\()_h) tst \my, #(0x7f << 14) - b.ne L(\type\()_8tap_v) + b.ne L(\type\()_\taps\()_v) b \type\()_neon -L(\type\()_8tap_h): +L(\type\()_\taps\()_h): cmp \w, #4 ubfx w10, \mx, #7, #7 and \mx, \mx, #0x7f @@ -1561,9 +1567,9 @@ L(\type\()_8tap_h): 4: tst \my, #(0x7f << 14) add \xmx, x11, \mx, uxtw #3 - b.ne L(\type\()_8tap_hv) + b.ne L(\type\()_\taps\()_hv) - adr x10, L(\type\()_8tap_h_tbl) + adr x10, L(\type\()_\taps\()_h_tbl) dup v30.4s, w12 // 6 - intermediate_bits ldrh w9, [x10, x9, lsl #1] neg v30.4s, v30.4s // -(6-intermediate_bits) @@ -1682,6 +1688,22 @@ L(\type\()_8tap_h): mov \mx, \w 8: +.ifc \taps, 6tap + ext v24.16b, v16.16b, v17.16b, #2 + ext v25.16b, v20.16b, v21.16b, #2 + smull v18.4s, v24.4h, v0.h[1] + smull2 v19.4s, v24.8h, v0.h[1] + smull v22.4s, v25.4h, v0.h[1] + smull2 v23.4s, v25.8h, v0.h[1] +.irpc i, 23456 + ext v24.16b, v16.16b, v17.16b, #(2*\i) + ext v25.16b, v20.16b, v21.16b, #(2*\i) + smlal v18.4s, v24.4h, v0.h[\i] + smlal2 v19.4s, v24.8h, v0.h[\i] + smlal v22.4s, v25.4h, v0.h[\i] + smlal2 v23.4s, v25.8h, v0.h[\i] +.endr +.else // 8tap smull v18.4s, v16.4h, v0.h[0] smull2 v19.4s, v16.8h, v0.h[0] smull v22.4s, v20.4h, v0.h[0] @@ -1694,6 +1716,7 @@ L(\type\()_8tap_h): smlal v22.4s, v25.4h, v0.h[\i] smlal2 v23.4s, v25.8h, v0.h[\i] .endr +.endif subs \mx, \mx, #8 srshl v18.4s, v18.4s, v30.4s // -(6-intermediate_bits) srshl v19.4s, v19.4s, v30.4s // -(6-intermediate_bits) @@ -1734,18 +1757,18 @@ L(\type\()_8tap_h): b.gt 81b ret -L(\type\()_8tap_h_tbl): - .hword L(\type\()_8tap_h_tbl) - 1280b - .hword L(\type\()_8tap_h_tbl) - 640b - .hword L(\type\()_8tap_h_tbl) - 320b - .hword L(\type\()_8tap_h_tbl) - 160b - .hword L(\type\()_8tap_h_tbl) - 80b - .hword L(\type\()_8tap_h_tbl) - 40b - .hword L(\type\()_8tap_h_tbl) - 20b +L(\type\()_\taps\()_h_tbl): + .hword L(\type\()_\taps\()_h_tbl) - 1280b + .hword L(\type\()_\taps\()_h_tbl) - 640b + .hword L(\type\()_\taps\()_h_tbl) - 320b + .hword L(\type\()_\taps\()_h_tbl) - 160b + .hword L(\type\()_\taps\()_h_tbl) - 80b + .hword L(\type\()_\taps\()_h_tbl) - 40b + .hword L(\type\()_\taps\()_h_tbl) - 20b .hword 0 -L(\type\()_8tap_v): +L(\type\()_\taps\()_v): cmp \h, #4 ubfx w10, \my, #7, #7 and \my, \my, #0x7f @@ -1758,7 +1781,7 @@ L(\type\()_8tap_v): dup v30.4s, w12 // 6 - intermediate_bits movi v29.8h, #(PREP_BIAS >> 8), lsl #8 .endif - adr x10, L(\type\()_8tap_v_tbl) + adr x10, L(\type\()_\taps\()_v_tbl) ldrh w9, [x10, x9, lsl #1] .ifc \type, prep neg v30.4s, v30.4s // -(6-intermediate_bits) @@ -1785,7 +1808,7 @@ L(\type\()_8tap_v): load_s \src, \sr2, \s_strd, v1, v2, v3, v4, v5 interleave_1_s v1, v2, v3, v4, v5 b.gt 24f - smull_smlal_4 v6, v1, v2, v3, v4 + smull_smlal_4tap v6, v1, v2, v3, v4 sqrshrun_h 6, v6 umin_h v31, .8h, v6 st_s \d_strd, v6, 2 @@ -1794,8 +1817,8 @@ L(\type\()_8tap_v): 24: // 2x4 v load_s \sr2, \src, \s_strd, v6, v7 interleave_1_s v5, v6, v7 - smull_smlal_4 v16, v1, v2, v3, v4 - smull_smlal_4 v17, v3, v4, v5, v6 + smull_smlal_4tap v16, v1, v2, v3, v4 + smull_smlal_4tap v17, v3, v4, v5, v6 sqrshrun_h 6, v16, v17 umin_h v31, .8h, v16 st_s \d_strd, v16, 4 @@ -1817,8 +1840,8 @@ L(\type\()_8tap_v): subs \h, \h, #4 load_s \sr2, \src, \s_strd, v16, v17, v18, v19 interleave_1_s v7, v16, v17, v18, v19 - smull_smlal_8 v24, v1, v2, v3, v4, v5, v6, v7, v16 - smull_smlal_8 v25, v3, v4, v5, v6, v7, v16, v17, v18 + smull_smlal_\taps v24, v1, v2, v3, v4, v5, v6, v7, v16 + smull_smlal_\taps v25, v3, v4, v5, v6, v7, v16, v17, v18 sqrshrun_h 6, v24, v25 umin_h v31, .8h, v24 st_s \d_strd, v24, 4 @@ -1836,7 +1859,7 @@ L(\type\()_8tap_v): 26: load_s \sr2, \src, \s_strd, v16, v17 interleave_1_s v7, v16, v17 - smull_smlal_8 v24, v1, v2, v3, v4, v5, v6, v7, v16 + smull_smlal_\taps v24, v1, v2, v3, v4, v5, v6, v7, v16 sqrshrun_h 6, v24 umin_h v31, .4h, v24 st_s \d_strd, v24, 2 @@ -1860,13 +1883,13 @@ L(\type\()_8tap_v): sxtl v0.8h, v0.8b load_4h \src, \sr2, \s_strd, v1, v2, v3, v4, v5 - smull_smlal_4 v6, v1, v2, v3, v4 - smull_smlal_4 v7, v2, v3, v4, v5 + smull_smlal_4tap v6, v1, v2, v3, v4 + smull_smlal_4tap v7, v2, v3, v4, v5 shift_store_4 \type, \d_strd, v6, v7 b.le 0f load_4h \sr2, \src, \s_strd, v6, v7 - smull_smlal_4 v1, v3, v4, v5, v6 - smull_smlal_4 v2, v4, v5, v6, v7 + smull_smlal_4tap v1, v3, v4, v5, v6 + smull_smlal_4tap v2, v4, v5, v6, v7 shift_store_4 \type, \d_strd, v1, v2 0: ret @@ -1885,10 +1908,10 @@ L(\type\()_8tap_v): 48: subs \h, \h, #4 load_4h \sr2, \src, \s_strd, v23, v24, v25, v26 - smull_smlal_8 v1, v16, v17, v18, v19, v20, v21, v22, v23 - smull_smlal_8 v2, v17, v18, v19, v20, v21, v22, v23, v24 - smull_smlal_8 v3, v18, v19, v20, v21, v22, v23, v24, v25 - smull_smlal_8 v4, v19, v20, v21, v22, v23, v24, v25, v26 + smull_smlal_\taps v1, v16, v17, v18, v19, v20, v21, v22, v23 + smull_smlal_\taps v2, v17, v18, v19, v20, v21, v22, v23, v24 + smull_smlal_\taps v3, v18, v19, v20, v21, v22, v23, v24, v25 + smull_smlal_\taps v4, v19, v20, v21, v22, v23, v24, v25, v26 shift_store_4 \type, \d_strd, v1, v2, v3, v4 b.le 0f cmp \h, #2 @@ -1903,8 +1926,8 @@ L(\type\()_8tap_v): b 48b 46: load_4h \sr2, \src, \s_strd, v23, v24 - smull_smlal_8 v1, v16, v17, v18, v19, v20, v21, v22, v23 - smull_smlal_8 v2, v17, v18, v19, v20, v21, v22, v23, v24 + smull_smlal_\taps v1, v16, v17, v18, v19, v20, v21, v22, v23 + smull_smlal_\taps v2, v17, v18, v19, v20, v21, v22, v23, v24 shift_store_4 \type, \d_strd, v1, v2 0: ret @@ -1925,17 +1948,17 @@ L(\type\()_8tap_v): sxtl v0.8h, v0.8b load_8h \src, \sr2, \s_strd, v1, v2, v3, v4, v5 - smull_smlal_4 v16, v1, v2, v3, v4 - smull2_smlal2_4 v17, v1, v2, v3, v4 - smull_smlal_4 v18, v2, v3, v4, v5 - smull2_smlal2_4 v19, v2, v3, v4, v5 + smull_smlal_4tap v16, v1, v2, v3, v4 + smull2_smlal2_4tap v17, v1, v2, v3, v4 + smull_smlal_4tap v18, v2, v3, v4, v5 + smull2_smlal2_4tap v19, v2, v3, v4, v5 shift_store_8 \type, \d_strd, v16, v17, v18, v19 b.le 0f load_8h \sr2, \src, \s_strd, v6, v7 - smull_smlal_4 v16, v3, v4, v5, v6 - smull2_smlal2_4 v17, v3, v4, v5, v6 - smull_smlal_4 v18, v4, v5, v6, v7 - smull2_smlal2_4 v19, v4, v5, v6, v7 + smull_smlal_4tap v16, v3, v4, v5, v6 + smull2_smlal2_4tap v17, v3, v4, v5, v6 + smull_smlal_4tap v18, v4, v5, v6, v7 + smull2_smlal2_4tap v19, v4, v5, v6, v7 shift_store_8 \type, \d_strd, v16, v17, v18, v19 0: ret @@ -1962,18 +1985,18 @@ L(\type\()_8tap_v): 88: subs \h, \h, #2 load_8h \sr2, \src, \s_strd, v23, v24 - smull_smlal_8 v1, v16, v17, v18, v19, v20, v21, v22, v23 - smull2_smlal2_8 v2, v16, v17, v18, v19, v20, v21, v22, v23 - smull_smlal_8 v3, v17, v18, v19, v20, v21, v22, v23, v24 - smull2_smlal2_8 v4, v17, v18, v19, v20, v21, v22, v23, v24 + smull_smlal_\taps v1, v16, v17, v18, v19, v20, v21, v22, v23 + smull2_smlal2_\taps v2, v16, v17, v18, v19, v20, v21, v22, v23 + smull_smlal_\taps v3, v17, v18, v19, v20, v21, v22, v23, v24 + smull2_smlal2_\taps v4, v17, v18, v19, v20, v21, v22, v23, v24 shift_store_8 \type, \d_strd, v1, v2, v3, v4 b.le 9f subs \h, \h, #2 load_8h \sr2, \src, \s_strd, v25, v26 - smull_smlal_8 v1, v18, v19, v20, v21, v22, v23, v24, v25 - smull2_smlal2_8 v2, v18, v19, v20, v21, v22, v23, v24, v25 - smull_smlal_8 v3, v19, v20, v21, v22, v23, v24, v25, v26 - smull2_smlal2_8 v4, v19, v20, v21, v22, v23, v24, v25, v26 + smull_smlal_\taps v1, v18, v19, v20, v21, v22, v23, v24, v25 + smull2_smlal2_\taps v2, v18, v19, v20, v21, v22, v23, v24, v25 + smull_smlal_\taps v3, v19, v20, v21, v22, v23, v24, v25, v26 + smull2_smlal2_\taps v4, v19, v20, v21, v22, v23, v24, v25, v26 shift_store_8 \type, \d_strd, v1, v2, v3, v4 b.le 9f mov v16.16b, v20.16b @@ -2013,10 +2036,10 @@ L(\type\()_8tap_v): 16: load_16h \src, \src, \s_strd, v22, v23 subs \h, \h, #1 - smull_smlal_4 v1, v16, v18, v20, v22 - smull2_smlal2_4 v2, v16, v18, v20, v22 - smull_smlal_4 v3, v17, v19, v21, v23 - smull2_smlal2_4 v4, v17, v19, v21, v23 + smull_smlal_4tap v1, v16, v18, v20, v22 + smull2_smlal2_4tap v2, v16, v18, v20, v22 + smull_smlal_4tap v3, v17, v19, v21, v23 + smull2_smlal2_4tap v4, v17, v19, v21, v23 shift_store_16 \type, \d_strd, x0, v1, v2, v3, v4 b.le 0f mov v16.16b, v18.16b @@ -2029,17 +2052,17 @@ L(\type\()_8tap_v): 0: ret -L(\type\()_8tap_v_tbl): - .hword L(\type\()_8tap_v_tbl) - 1280b - .hword L(\type\()_8tap_v_tbl) - 640b - .hword L(\type\()_8tap_v_tbl) - 320b - .hword L(\type\()_8tap_v_tbl) - 160b - .hword L(\type\()_8tap_v_tbl) - 80b - .hword L(\type\()_8tap_v_tbl) - 40b - .hword L(\type\()_8tap_v_tbl) - 20b +L(\type\()_\taps\()_v_tbl): + .hword L(\type\()_\taps\()_v_tbl) - 1280b + .hword L(\type\()_\taps\()_v_tbl) - 640b + .hword L(\type\()_\taps\()_v_tbl) - 320b + .hword L(\type\()_\taps\()_v_tbl) - 160b + .hword L(\type\()_\taps\()_v_tbl) - 80b + .hword L(\type\()_\taps\()_v_tbl) - 40b + .hword L(\type\()_\taps\()_v_tbl) - 20b .hword 0 -L(\type\()_8tap_hv): +L(\type\()_\taps\()_hv): cmp \h, #4 ubfx w10, \my, #7, #7 and \my, \my, #0x7f @@ -2048,7 +2071,7 @@ L(\type\()_8tap_hv): 4: add \xmy, x11, \my, uxtw #3 - adr x10, L(\type\()_8tap_hv_tbl) + adr x10, L(\type\()_\taps\()_hv_tbl) dup v30.4s, w12 // 6 - intermediate_bits ldrh w9, [x10, x9, lsl #1] neg v30.4s, v30.4s // -(6-intermediate_bits) @@ -2089,7 +2112,7 @@ L(\type\()_8tap_hv): addp v27.4s, v27.4s, v28.4s addp v16.4s, v27.4s, v27.4s srshl v16.2s, v16.2s, v30.2s // -(6-intermediate_bits) - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) // The intermediates from the horizontal pass fit in 16 bit without // any bias; we could just as well keep them as .4s, but narrowing // them to .4h gives a significant speedup on out of order cores @@ -2100,7 +2123,7 @@ L(\type\()_8tap_hv): mov v17.8b, v24.8b 2: - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) ext v18.8b, v17.8b, v24.8b, #4 smull v2.4s, v16.4h, v1.h[0] @@ -2143,20 +2166,28 @@ L(\type\()_8tap_hv): // them to .4h gives a significant speedup on out of order cores // (at the cost of a smaller slowdown on in-order cores such as A53). - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) xtn v16.4h, v16.4s trn1 v16.2s, v16.2s, v24.2s mov v17.8b, v24.8b - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) ext v18.8b, v17.8b, v24.8b, #4 mov v19.8b, v24.8b - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) ext v20.8b, v19.8b, v24.8b, #4 mov v21.8b, v24.8b 28: - bl L(\type\()_8tap_filter_2) + bl L(\type\()_\taps\()_filter_2) ext v22.8b, v21.8b, v24.8b, #4 +.ifc \taps, 6tap + smull v3.4s, v17.4h, v1.h[1] + smlal v3.4s, v18.4h, v1.h[2] + smlal v3.4s, v19.4h, v1.h[3] + smlal v3.4s, v20.4h, v1.h[4] + smlal v3.4s, v21.4h, v1.h[5] + smlal v3.4s, v22.4h, v1.h[6] +.else // 8tap smull v3.4s, v16.4h, v1.h[0] smlal v3.4s, v17.4h, v1.h[1] smlal v3.4s, v18.4h, v1.h[2] @@ -2165,6 +2196,7 @@ L(\type\()_8tap_hv): smlal v3.4s, v21.4h, v1.h[5] smlal v3.4s, v22.4h, v1.h[6] smlal v3.4s, v24.4h, v1.h[7] +.endif srshl v3.4s, v3.4s, v29.4s // -(6+intermediate_bits) sqxtun v3.4h, v3.4s @@ -2184,7 +2216,7 @@ L(\type\()_8tap_hv): 0: ret x15 -L(\type\()_8tap_filter_2): +L(\type\()_\taps\()_filter_2): ld1 {v25.8h}, [\sr2], \s_strd ld1 {v27.8h}, [\src], \s_strd ext v26.16b, v25.16b, v25.16b, #2 @@ -2234,12 +2266,12 @@ L(\type\()_8tap_filter_2): // (at the cost of a smaller slowdown on in-order cores such as A53). xtn v16.4h, v16.4s - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) mov v17.8b, v24.8b mov v18.8b, v25.8b 4: - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) smull v2.4s, v16.4h, v1.h[0] smlal v2.4s, v17.4h, v1.h[1] smlal v2.4s, v18.4h, v1.h[2] @@ -2272,8 +2304,13 @@ L(\type\()_8tap_filter_2): 480: // 4x8, 4x16, 4x32 hv ld1 {v1.8b}, [\xmy] sub \src, \src, #2 +.ifc \taps, 6tap + sub \sr2, \src, \s_strd + sub \src, \src, \s_strd, lsl #1 +.else sub \sr2, \src, \s_strd, lsl #1 sub \src, \sr2, \s_strd +.endif add \ds2, \dst, \d_strd lsl \s_strd, \s_strd, #1 lsl \d_strd, \d_strd, #1 @@ -2294,20 +2331,38 @@ L(\type\()_8tap_filter_2): // any bias; we could just as well keep them as .4s, but narrowing // them to .4h gives a significant speedup on out of order cores // (at the cost of a smaller slowdown on in-order cores such as A53). +.ifc \taps, 6tap + xtn v18.4h, v16.4s +.else xtn v16.4h, v16.4s - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) mov v17.8b, v24.8b mov v18.8b, v25.8b - bl L(\type\()_8tap_filter_4) +.endif + bl L(\type\()_\taps\()_filter_4) mov v19.8b, v24.8b mov v20.8b, v25.8b - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) mov v21.8b, v24.8b mov v22.8b, v25.8b 48: - bl L(\type\()_8tap_filter_4) + bl L(\type\()_\taps\()_filter_4) +.ifc \taps, 6tap + smull v3.4s, v18.4h, v1.h[1] + smlal v3.4s, v19.4h, v1.h[2] + smlal v3.4s, v20.4h, v1.h[3] + smlal v3.4s, v21.4h, v1.h[4] + smlal v3.4s, v22.4h, v1.h[5] + smlal v3.4s, v24.4h, v1.h[6] + smull v4.4s, v19.4h, v1.h[1] + smlal v4.4s, v20.4h, v1.h[2] + smlal v4.4s, v21.4h, v1.h[3] + smlal v4.4s, v22.4h, v1.h[4] + smlal v4.4s, v24.4h, v1.h[5] + smlal v4.4s, v25.4h, v1.h[6] +.else // 8tap smull v3.4s, v16.4h, v1.h[0] smlal v3.4s, v17.4h, v1.h[1] smlal v3.4s, v18.4h, v1.h[2] @@ -2324,6 +2379,7 @@ L(\type\()_8tap_filter_2): smlal v4.4s, v22.4h, v1.h[5] smlal v4.4s, v24.4h, v1.h[6] smlal v4.4s, v25.4h, v1.h[7] +.endif .ifc \type, put srshl v3.4s, v3.4s, v29.4s // -(6+intermediate_bits) srshl v4.4s, v4.4s, v29.4s // -(6+intermediate_bits) @@ -2339,8 +2395,10 @@ L(\type\()_8tap_filter_2): st1 {v3.d}[0], [\dst], \d_strd st1 {v3.d}[1], [\ds2], \d_strd b.le 0f +.ifc \taps, 8tap mov v16.8b, v18.8b mov v17.8b, v19.8b +.endif mov v18.8b, v20.8b mov v19.8b, v21.8b mov v20.8b, v22.8b @@ -2350,7 +2408,7 @@ L(\type\()_8tap_filter_2): 0: ret x15 -L(\type\()_8tap_filter_4): +L(\type\()_\taps\()_filter_4): ld1 {v24.8h}, [\sr2], \s_strd ld1 {v25.8h}, [\src], \s_strd ext v26.16b, v24.16b, v24.16b, #2 @@ -2411,14 +2469,14 @@ L(\type\()_8tap_filter_4): // and conserves register space (no need to clobber v8-v15). uzp1 v16.8h, v24.8h, v25.8h // Same as xtn, xtn2 - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8) mov v17.16b, v23.16b mov v18.16b, v24.16b 8: smull v2.4s, v16.4h, v1.h[0] smull2 v3.4s, v16.8h, v1.h[0] - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8) smull v4.4s, v17.4h, v1.h[0] smull2 v5.4s, v17.8h, v1.h[0] smlal v2.4s, v17.4h, v1.h[1] @@ -2480,7 +2538,9 @@ L(\type\()_8tap_filter_4): ld1 {v0.8b}, [\xmx] ld1 {v1.8b}, [\xmy] sub \src, \src, #6 +.ifc \taps, 8tap sub \src, \src, \s_strd +.endif sub \src, \src, \s_strd, lsl #1 sxtl v0.8h, v0.8b sxtl v1.8h, v1.8b @@ -2494,6 +2554,16 @@ L(\type\()_8tap_filter_4): lsl \s_strd, \s_strd, #1 ld1 {v27.8h, v28.8h}, [\src], \s_strd +.ifc \taps, 6tap + ext v26.16b, v27.16b, v28.16b, #2 + smull v24.4s, v26.4h, v0.h[1] + smull2 v25.4s, v26.8h, v0.h[1] +.irpc i, 23456 + ext v26.16b, v27.16b, v28.16b, #(2*\i) + smlal v24.4s, v26.4h, v0.h[\i] + smlal2 v25.4s, v26.8h, v0.h[\i] +.endr +.else // 8tap smull v24.4s, v27.4h, v0.h[0] smull2 v25.4s, v27.8h, v0.h[0] .irpc i, 1234567 @@ -2501,6 +2571,7 @@ L(\type\()_8tap_filter_4): smlal v24.4s, v26.4h, v0.h[\i] smlal2 v25.4s, v26.8h, v0.h[\i] .endr +.endif srshl v24.4s, v24.4s, v30.4s // -(6-intermediate_bits) srshl v25.4s, v25.4s, v30.4s // -(6-intermediate_bits) // The intermediates from the horizontal pass fit in 16 bit without @@ -2508,22 +2579,53 @@ L(\type\()_8tap_filter_4): // them to .4h gives a significant speedup on out of order cores // (at the cost of a smaller slowdown on in-order cores such as A53), // and conserves register space (no need to clobber v8-v15). +.ifc \taps, 6tap + uzp1 v18.8h, v24.8h, v25.8h // Same as xtn, xtn2 +.else uzp1 v16.8h, v24.8h, v25.8h // Same as xtn, xtn2 - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8) mov v17.16b, v23.16b mov v18.16b, v24.16b - bl L(\type\()_8tap_filter_8) +.endif + bl L(\type\()_\taps\()_filter_8) mov v19.16b, v23.16b mov v20.16b, v24.16b - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8) mov v21.16b, v23.16b mov v22.16b, v24.16b 88: +.ifc \taps, 6tap + smull v2.4s, v18.4h, v1.h[1] + smull2 v3.4s, v18.8h, v1.h[1] + bl L(\type\()_\taps\()_filter_8) + smull v4.4s, v19.4h, v1.h[1] + smull2 v5.4s, v19.8h, v1.h[1] + smlal v2.4s, v19.4h, v1.h[2] + smlal2 v3.4s, v19.8h, v1.h[2] + smlal v4.4s, v20.4h, v1.h[2] + smlal2 v5.4s, v20.8h, v1.h[2] + smlal v2.4s, v20.4h, v1.h[3] + smlal2 v3.4s, v20.8h, v1.h[3] + smlal v4.4s, v21.4h, v1.h[3] + smlal2 v5.4s, v21.8h, v1.h[3] + smlal v2.4s, v21.4h, v1.h[4] + smlal2 v3.4s, v21.8h, v1.h[4] + smlal v4.4s, v22.4h, v1.h[4] + smlal2 v5.4s, v22.8h, v1.h[4] + smlal v2.4s, v22.4h, v1.h[5] + smlal2 v3.4s, v22.8h, v1.h[5] + smlal v4.4s, v23.4h, v1.h[5] + smlal2 v5.4s, v23.8h, v1.h[5] + smlal v2.4s, v23.4h, v1.h[6] + smlal2 v3.4s, v23.8h, v1.h[6] + smlal v4.4s, v24.4h, v1.h[6] + smlal2 v5.4s, v24.8h, v1.h[6] +.else // 8tap smull v2.4s, v16.4h, v1.h[0] smull2 v3.4s, v16.8h, v1.h[0] - bl L(\type\()_8tap_filter_8) + bl L(\type\()_\taps\()_filter_8) smull v4.4s, v17.4h, v1.h[0] smull2 v5.4s, v17.8h, v1.h[0] smlal v2.4s, v17.4h, v1.h[1] @@ -2554,6 +2656,7 @@ L(\type\()_8tap_filter_4): smlal2 v3.4s, v23.8h, v1.h[7] smlal v4.4s, v24.4h, v1.h[7] smlal2 v5.4s, v24.8h, v1.h[7] +.endif .ifc \type, put srshl v2.4s, v2.4s, v29.4s // -(6+intermediate_bits) srshl v3.4s, v3.4s, v29.4s // -(6+intermediate_bits) @@ -2577,8 +2680,10 @@ L(\type\()_8tap_filter_4): st1 {v2.8h}, [\dst], \d_strd st1 {v3.8h}, [\ds2], \d_strd b.le 9f +.ifc \taps, 8tap mov v16.16b, v18.16b mov v17.16b, v19.16b +.endif mov v18.16b, v20.16b mov v19.16b, v21.16b mov v20.16b, v22.16b @@ -2596,13 +2701,32 @@ L(\type\()_8tap_filter_4): mov \h, \my add \src, \src, #16 add \dst, \dst, #16 +.ifc \taps, 6tap + add \src, \src, \s_strd, lsl #1 +.endif b 168b 0: ret x15 -L(\type\()_8tap_filter_8): +L(\type\()_\taps\()_filter_8): ld1 {v4.8h, v5.8h}, [\sr2], \s_strd ld1 {v6.8h, v7.8h}, [\src], \s_strd +.ifc \taps, 6tap + ext v23.16b, v4.16b, v5.16b, #2 + ext v24.16b, v6.16b, v7.16b, #2 + smull v25.4s, v23.4h, v0.h[1] + smull2 v26.4s, v23.8h, v0.h[1] + smull v27.4s, v24.4h, v0.h[1] + smull2 v28.4s, v24.8h, v0.h[1] +.irpc i, 23456 + ext v23.16b, v4.16b, v5.16b, #(2*\i) + ext v24.16b, v6.16b, v7.16b, #(2*\i) + smlal v25.4s, v23.4h, v0.h[\i] + smlal2 v26.4s, v23.8h, v0.h[\i] + smlal v27.4s, v24.4h, v0.h[\i] + smlal2 v28.4s, v24.8h, v0.h[\i] +.endr +.else // 8tap smull v25.4s, v4.4h, v0.h[0] smull2 v26.4s, v4.8h, v0.h[0] smull v27.4s, v6.4h, v0.h[0] @@ -2615,6 +2739,7 @@ L(\type\()_8tap_filter_8): smlal v27.4s, v24.4h, v0.h[\i] smlal2 v28.4s, v24.8h, v0.h[\i] .endr +.endif srshl v25.4s, v25.4s, v30.4s // -(6-intermediate_bits) srshl v26.4s, v26.4s, v30.4s // -(6-intermediate_bits) srshl v27.4s, v27.4s, v30.4s // -(6-intermediate_bits) @@ -2623,18 +2748,20 @@ L(\type\()_8tap_filter_8): uzp1 v24.8h, v27.8h, v28.8h // Ditto ret -L(\type\()_8tap_hv_tbl): - .hword L(\type\()_8tap_hv_tbl) - 1280b - .hword L(\type\()_8tap_hv_tbl) - 640b - .hword L(\type\()_8tap_hv_tbl) - 320b - .hword L(\type\()_8tap_hv_tbl) - 160b - .hword L(\type\()_8tap_hv_tbl) - 80b - .hword L(\type\()_8tap_hv_tbl) - 40b - .hword L(\type\()_8tap_hv_tbl) - 20b +L(\type\()_\taps\()_hv_tbl): + .hword L(\type\()_\taps\()_hv_tbl) - 1280b + .hword L(\type\()_\taps\()_hv_tbl) - 640b + .hword L(\type\()_\taps\()_hv_tbl) - 320b + .hword L(\type\()_\taps\()_hv_tbl) - 160b + .hword L(\type\()_\taps\()_hv_tbl) - 80b + .hword L(\type\()_\taps\()_hv_tbl) - 40b + .hword L(\type\()_\taps\()_hv_tbl) - 20b .hword 0 endfunc +.endm +.macro filter_bilin_fn type, dst, d_strd, src, s_strd, w, h, mx, xmx, my, xmy, bdmax, ds2, sr2 function \type\()_bilin_16bpc_neon, export=1 .ifc \bdmax, w8 ldr w8, [sp] @@ -3236,8 +3363,34 @@ L(\type\()_bilin_hv_tbl): endfunc .endm -filter_fn put, x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, w8, x9, x10 -filter_fn prep, x0, x8, x1, x2, w3, w4, w5, x5, w6, x6, w7, x9, x10 +make_8tap_fn put, regular_sharp, REGULAR, SHARP, 8tap +make_8tap_fn put, smooth_sharp, SMOOTH, SHARP, 8tap +make_8tap_fn put, sharp, SHARP, SHARP, 8tap +make_8tap_fn put, sharp_regular, SHARP, REGULAR, 8tap +make_8tap_fn put, sharp_smooth, SHARP, SMOOTH, 8tap +filter_fn put, x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, w8, x9, x10, 8tap + +make_8tap_fn put, regular, REGULAR, REGULAR, 6tap +make_8tap_fn put, regular_smooth, REGULAR, SMOOTH, 6tap +make_8tap_fn put, smooth, SMOOTH, SMOOTH, 6tap +make_8tap_fn put, smooth_regular, SMOOTH, REGULAR, 6tap +filter_fn put, x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, w8, x9, x10, 6tap +filter_bilin_fn put, x0, x1, x2, x3, w4, w5, w6, x6, w7, x7, w8, x9, x10 + +make_8tap_fn prep, regular_sharp, REGULAR, SHARP, 8tap +make_8tap_fn prep, smooth_sharp, SMOOTH, SHARP, 8tap +make_8tap_fn prep, sharp, SHARP, SHARP, 8tap +make_8tap_fn prep, sharp_regular, SHARP, REGULAR, 8tap +make_8tap_fn prep, sharp_smooth, SHARP, SMOOTH, 8tap +filter_fn prep, x0, x8, x1, x2, w3, w4, w5, x5, w6, x6, w7, x9, x10, 8tap + +make_8tap_fn prep, regular, REGULAR, REGULAR, 6tap +make_8tap_fn prep, regular_smooth, REGULAR, SMOOTH, 6tap +make_8tap_fn prep, smooth, SMOOTH, SMOOTH, 6tap +make_8tap_fn prep, smooth_regular, SMOOTH, REGULAR, 6tap +filter_fn prep, x0, x8, x1, x2, w3, w4, w5, x5, w6, x6, w7, x9, x10, 6tap +filter_bilin_fn prep, x0, x8, x1, x2, w3, w4, w5, x5, w6, x6, w7, x9, x10 + .macro load_filter_row dst, src, inc asr w13, \src, #10 diff --git a/third_party/dav1d/src/arm/64/msac.S b/third_party/dav1d/src/arm/64/msac.S index 3a6cf900a9..7bef9243fb 100644 --- a/third_party/dav1d/src/arm/64/msac.S +++ b/third_party/dav1d/src/arm/64/msac.S @@ -208,60 +208,66 @@ L(renorm): sub w4, w4, w3 // rng = u - v clz w5, w4 // clz(rng) eor w5, w5, #16 // d = clz(rng) ^ 16 - mvn x7, x7 // ~dif - add x7, x7, x3, lsl #48 // ~dif + (v << 48) + sub x7, x7, x3, lsl #48 // dif - (v << 48) L(renorm2): lsl w4, w4, w5 // rng << d subs w6, w6, w5 // cnt -= d - lsl x7, x7, x5 // (~dif + (v << 48)) << d + lsl x7, x7, x5 // (dif - (v << 48)) << d str w4, [x0, #RNG] - mvn x7, x7 // ~dif - b.hs 9f + b.hs 4f // refill ldp x3, x4, [x0] // BUF_POS, BUF_END add x5, x3, #8 - cmp x5, x4 - b.gt 2f - - ldr x3, [x3] // next_bits - add w8, w6, #23 // shift_bits = cnt + 23 - add w6, w6, #16 // cnt += 16 - rev x3, x3 // next_bits = bswap(next_bits) - sub x5, x5, x8, lsr #3 // buf_pos -= shift_bits >> 3 - and w8, w8, #24 // shift_bits &= 24 - lsr x3, x3, x8 // next_bits >>= shift_bits - sub w8, w8, w6 // shift_bits -= 16 + cnt - str x5, [x0, #BUF_POS] - lsl x3, x3, x8 // next_bits <<= shift_bits - mov w4, #48 - sub w6, w4, w8 // cnt = cnt + 64 - shift_bits - eor x7, x7, x3 // dif ^= next_bits - b 9f - -2: // refill_eob - mov w14, #40 - sub w5, w14, w6 // c = 40 - cnt -3: - cmp x3, x4 - b.ge 4f - ldrb w8, [x3], #1 - lsl x8, x8, x5 - eor x7, x7, x8 - subs w5, w5, #8 - b.ge 3b - -4: // refill_eob_end + subs x5, x5, x4 + b.hi 6f + + ldr x8, [x3] // next_bits + add w4, w6, #-48 // shift_bits = cnt + 16 (- 64) + mvn x8, x8 + neg w5, w4 + rev x8, x8 // next_bits = bswap(next_bits) + lsr w5, w5, #3 // num_bytes_read + lsr x8, x8, x4 // next_bits >>= (shift_bits & 63) + +2: // refill_end + add x3, x3, x5 + add w6, w6, w5, lsl #3 // cnt += num_bits_read str x3, [x0, #BUF_POS] - sub w6, w14, w5 // cnt = 40 - c -9: +3: // refill_end2 + orr x7, x7, x8 // dif |= next_bits + +4: // end str w6, [x0, #CNT] str x7, [x0, #DIF] mov w0, w15 add sp, sp, #48 ret + +5: // pad_with_ones + add w8, w6, #-16 + ror x8, x8, x8 + b 3b + +6: // refill_eob + cmp x3, x4 + b.hs 5b + + ldr x8, [x4, #-8] + lsl w5, w5, #3 + lsr x8, x8, x5 + add w5, w6, #-48 + mvn x8, x8 + sub w4, w4, w3 // num_bytes_left + rev x8, x8 + lsr x8, x8, x5 + neg w5, w5 + lsr w5, w5, #3 + cmp w5, w4 + csel w5, w5, w4, lo // num_bytes_read + b 2b endfunc function msac_decode_symbol_adapt8_neon, export=1 @@ -334,54 +340,37 @@ function msac_decode_hi_tok_neon, export=1 sub w4, w4, w3 // rng = u - v clz w5, w4 // clz(rng) eor w5, w5, #16 // d = clz(rng) ^ 16 - mvn x7, x7 // ~dif - add x7, x7, x3, lsl #48 // ~dif + (v << 48) + sub x7, x7, x3, lsl #48 // dif - (v << 48) lsl w4, w4, w5 // rng << d subs w6, w6, w5 // cnt -= d - lsl x7, x7, x5 // (~dif + (v << 48)) << d + lsl x7, x7, x5 // (dif - (v << 48)) << d str w4, [x0, #RNG] dup v3.4h, w4 - mvn x7, x7 // ~dif - b.hs 9f + b.hs 5f // refill ldp x3, x4, [x0] // BUF_POS, BUF_END add x5, x3, #8 - cmp x5, x4 - b.gt 2f - - ldr x3, [x3] // next_bits - add w8, w6, #23 // shift_bits = cnt + 23 - add w6, w6, #16 // cnt += 16 - rev x3, x3 // next_bits = bswap(next_bits) - sub x5, x5, x8, lsr #3 // buf_pos -= shift_bits >> 3 - and w8, w8, #24 // shift_bits &= 24 - lsr x3, x3, x8 // next_bits >>= shift_bits - sub w8, w8, w6 // shift_bits -= 16 + cnt - str x5, [x0, #BUF_POS] - lsl x3, x3, x8 // next_bits <<= shift_bits - mov w4, #48 - sub w6, w4, w8 // cnt = cnt + 64 - shift_bits - eor x7, x7, x3 // dif ^= next_bits - b 9f - -2: // refill_eob - mov w14, #40 - sub w5, w14, w6 // c = 40 - cnt -3: - cmp x3, x4 - b.ge 4f - ldrb w8, [x3], #1 - lsl x8, x8, x5 - eor x7, x7, x8 - subs w5, w5, #8 - b.ge 3b - -4: // refill_eob_end + subs x5, x5, x4 + b.hi 7f + + ldr x8, [x3] // next_bits + add w4, w6, #-48 // shift_bits = cnt + 16 (- 64) + mvn x8, x8 + neg w5, w4 + rev x8, x8 // next_bits = bswap(next_bits) + lsr w5, w5, #3 // num_bytes_read + lsr x8, x8, x4 // next_bits >>= (shift_bits & 63) + +3: // refill_end + add x3, x3, x5 + add w6, w6, w5, lsl #3 // cnt += num_bits_read str x3, [x0, #BUF_POS] - sub w6, w14, w5 // cnt = 40 - c -9: +4: // refill_end2 + orr x7, x7, x8 // dif |= next_bits + +5: // end lsl w15, w15, #1 sub w15, w15, #5 lsr x12, x7, #48 @@ -394,6 +383,29 @@ function msac_decode_hi_tok_neon, export=1 str x7, [x0, #DIF] lsr w0, w13, #1 ret + +6: // pad_with_ones + add w8, w6, #-16 + ror x8, x8, x8 + b 4b + +7: // refill_eob + cmp x3, x4 + b.hs 6b + + ldr x8, [x4, #-8] + lsl w5, w5, #3 + lsr x8, x8, x5 + add w5, w6, #-48 + mvn x8, x8 + sub w4, w4, w3 // num_bytes_left + rev x8, x8 + lsr x8, x8, x5 + neg w5, w5 + lsr w5, w5, #3 + cmp w5, w4 + csel w5, w5, w4, lo // num_bytes_read + b 3b endfunc function msac_decode_bool_equi_neon, export=1 @@ -410,7 +422,6 @@ function msac_decode_bool_equi_neon, export=1 csel x7, x8, x7, hs // if (ret) dif = dif - vw; clz w5, w4 // clz(rng) - mvn x7, x7 // ~dif eor w5, w5, #16 // d = clz(rng) ^ 16 b L(renorm2) endfunc @@ -431,7 +442,6 @@ function msac_decode_bool_neon, export=1 csel x7, x8, x7, hs // if (ret) dif = dif - vw; clz w5, w4 // clz(rng) - mvn x7, x7 // ~dif eor w5, w5, #16 // d = clz(rng) ^ 16 b L(renorm2) endfunc @@ -455,7 +465,6 @@ function msac_decode_bool_adapt_neon, export=1 ldr w10, [x0, #ALLOW_UPDATE_CDF] clz w5, w4 // clz(rng) - mvn x7, x7 // ~dif eor w5, w5, #16 // d = clz(rng) ^ 16 cbz w10, L(renorm2) diff --git a/third_party/dav1d/src/arm/64/util.S b/third_party/dav1d/src/arm/64/util.S index 9013fd4b1e..1b3f319ce5 100644 --- a/third_party/dav1d/src/arm/64/util.S +++ b/third_party/dav1d/src/arm/64/util.S @@ -32,6 +32,10 @@ #include "config.h" #include "src/arm/asm.S" +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + .macro movrel rd, val, offset=0 #if defined(__APPLE__) .if \offset < 0 @@ -51,6 +55,10 @@ adrp \rd, \val+(\offset) add \rd, \rd, :lo12:\val+(\offset) .endif +#elif __has_feature(hwaddress_sanitizer) + adrp \rd, :pg_hi21_nc:\val+(\offset) + movk \rd, #:prel_g3:\val+0x100000000 + add \rd, \rd, :lo12:\val+(\offset) #elif defined(PIC) adrp \rd, \val+(\offset) add \rd, \rd, :lo12:\val+(\offset) @@ -149,6 +157,35 @@ trn2 \r7\().2d, \t9\().2d, \r7\().2d .endm +.macro transpose_8x8h_mov r0, r1, r2, r3, r4, r5, r6, r7, t8, t9, o0, o1, o2, o3, o4, o5, o6, o7 + trn1 \t8\().8h, \r0\().8h, \r1\().8h + trn2 \t9\().8h, \r0\().8h, \r1\().8h + trn1 \r1\().8h, \r2\().8h, \r3\().8h + trn2 \r3\().8h, \r2\().8h, \r3\().8h + trn1 \r0\().8h, \r4\().8h, \r5\().8h + trn2 \r5\().8h, \r4\().8h, \r5\().8h + trn1 \r2\().8h, \r6\().8h, \r7\().8h + trn2 \r7\().8h, \r6\().8h, \r7\().8h + + trn1 \r4\().4s, \r0\().4s, \r2\().4s + trn2 \r2\().4s, \r0\().4s, \r2\().4s + trn1 \r6\().4s, \r5\().4s, \r7\().4s + trn2 \r7\().4s, \r5\().4s, \r7\().4s + trn1 \r5\().4s, \t9\().4s, \r3\().4s + trn2 \t9\().4s, \t9\().4s, \r3\().4s + trn1 \r3\().4s, \t8\().4s, \r1\().4s + trn2 \t8\().4s, \t8\().4s, \r1\().4s + + trn1 \o0\().2d, \r3\().2d, \r4\().2d + trn2 \o4\().2d, \r3\().2d, \r4\().2d + trn1 \o1\().2d, \r5\().2d, \r6\().2d + trn2 \o5\().2d, \r5\().2d, \r6\().2d + trn2 \o6\().2d, \t8\().2d, \r2\().2d + trn1 \o2\().2d, \t8\().2d, \r2\().2d + trn1 \o3\().2d, \t9\().2d, \r7\().2d + trn2 \o7\().2d, \t9\().2d, \r7\().2d +.endm + .macro transpose_8x16b r0, r1, r2, r3, r4, r5, r6, r7, t8, t9 trn1 \t8\().16b, \r0\().16b, \r1\().16b trn2 \t9\().16b, \r0\().16b, \r1\().16b @@ -226,4 +263,16 @@ trn2 \r3\().4s, \t5\().4s, \t7\().4s .endm +.macro transpose_4x8h_mov r0, r1, r2, r3, t4, t5, t6, t7, o0, o1, o2, o3 + trn1 \t4\().8h, \r0\().8h, \r1\().8h + trn2 \t5\().8h, \r0\().8h, \r1\().8h + trn1 \t6\().8h, \r2\().8h, \r3\().8h + trn2 \t7\().8h, \r2\().8h, \r3\().8h + + trn1 \o0\().4s, \t4\().4s, \t6\().4s + trn2 \o2\().4s, \t4\().4s, \t6\().4s + trn1 \o1\().4s, \t5\().4s, \t7\().4s + trn2 \o3\().4s, \t5\().4s, \t7\().4s +.endm + #endif /* DAV1D_SRC_ARM_64_UTIL_S */ diff --git a/third_party/dav1d/src/arm/asm.S b/third_party/dav1d/src/arm/asm.S index dc50415f1f..fed73b3048 100644 --- a/third_party/dav1d/src/arm/asm.S +++ b/third_party/dav1d/src/arm/asm.S @@ -34,6 +34,50 @@ #define x18 do_not_use_x18 #define w18 do_not_use_w18 +#if HAVE_AS_ARCH_DIRECTIVE + .arch AS_ARCH_LEVEL +#endif + +#if HAVE_AS_ARCHEXT_DOTPROD_DIRECTIVE +#define ENABLE_DOTPROD .arch_extension dotprod +#define DISABLE_DOTPROD .arch_extension nodotprod +#else +#define ENABLE_DOTPROD +#define DISABLE_DOTPROD +#endif +#if HAVE_AS_ARCHEXT_I8MM_DIRECTIVE +#define ENABLE_I8MM .arch_extension i8mm +#define DISABLE_I8MM .arch_extension noi8mm +#else +#define ENABLE_I8MM +#define DISABLE_I8MM +#endif +#if HAVE_AS_ARCHEXT_SVE_DIRECTIVE +#define ENABLE_SVE .arch_extension sve +#define DISABLE_SVE .arch_extension nosve +#else +#define ENABLE_SVE +#define DISABLE_SVE +#endif +#if HAVE_AS_ARCHEXT_SVE2_DIRECTIVE +#define ENABLE_SVE2 .arch_extension sve2 +#define DISABLE_SVE2 .arch_extension nosve2 +#else +#define ENABLE_SVE2 +#define DISABLE_SVE2 +#endif + +/* If we do support the .arch_extension directives, disable support for all + * the extensions that we may use, in case they were implicitly enabled by + * the .arch level. This makes it clear if we try to assemble an instruction + * from an unintended extension set; we only allow assmbling such instructions + * within regions where we explicitly enable those extensions. */ +DISABLE_DOTPROD +DISABLE_I8MM +DISABLE_SVE +DISABLE_SVE2 + + /* Support macros for * - Armv8.3-A Pointer Authentication and * - Armv8.5-A Branch Target Identification diff --git a/third_party/dav1d/src/arm/cpu.c b/third_party/dav1d/src/arm/cpu.c index b7a0d3adbc..d9b1751a6a 100644 --- a/third_party/dav1d/src/arm/cpu.c +++ b/third_party/dav1d/src/arm/cpu.c @@ -31,22 +31,95 @@ #include "src/arm/cpu.h" -#if defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32) || ARCH_AARCH64 -// NEON is always available; runtime tests are not needed. -#elif defined(HAVE_GETAUXVAL) && ARCH_ARM +#if defined(HAVE_GETAUXVAL) || defined(HAVE_ELF_AUX_INFO) #include +#if ARCH_AARCH64 + +#define HWCAP_AARCH64_ASIMDDP (1 << 20) +#define HWCAP_AARCH64_SVE (1 << 22) +#define HWCAP2_AARCH64_SVE2 (1 << 1) +#define HWCAP2_AARCH64_I8MM (1 << 13) + +COLD unsigned dav1d_get_cpu_flags_arm(void) { +#ifdef HAVE_GETAUXVAL + unsigned long hw_cap = getauxval(AT_HWCAP); + unsigned long hw_cap2 = getauxval(AT_HWCAP2); +#else + unsigned long hw_cap = 0; + unsigned long hw_cap2 = 0; + elf_aux_info(AT_HWCAP, &hw_cap, sizeof(hw_cap)); + elf_aux_info(AT_HWCAP2, &hw_cap2, sizeof(hw_cap2)); +#endif + + unsigned flags = DAV1D_ARM_CPU_FLAG_NEON; + flags |= (hw_cap & HWCAP_AARCH64_ASIMDDP) ? DAV1D_ARM_CPU_FLAG_DOTPROD : 0; + flags |= (hw_cap2 & HWCAP2_AARCH64_I8MM) ? DAV1D_ARM_CPU_FLAG_I8MM : 0; + flags |= (hw_cap & HWCAP_AARCH64_SVE) ? DAV1D_ARM_CPU_FLAG_SVE : 0; + flags |= (hw_cap2 & HWCAP2_AARCH64_SVE2) ? DAV1D_ARM_CPU_FLAG_SVE2 : 0; + return flags; +} +#else /* !ARCH_AARCH64 */ + #ifndef HWCAP_ARM_NEON -#define HWCAP_ARM_NEON (1 << 12) +#define HWCAP_ARM_NEON (1 << 12) #endif -#define NEON_HWCAP HWCAP_ARM_NEON +#define HWCAP_ARM_ASIMDDP (1 << 24) +#define HWCAP_ARM_I8MM (1 << 27) -#elif defined(HAVE_ELF_AUX_INFO) && ARCH_ARM -#include +COLD unsigned dav1d_get_cpu_flags_arm(void) { +#ifdef HAVE_GETAUXVAL + unsigned long hw_cap = getauxval(AT_HWCAP); +#else + unsigned long hw_cap = 0; + elf_aux_info(AT_HWCAP, &hw_cap, sizeof(hw_cap)); +#endif + + unsigned flags = (hw_cap & HWCAP_ARM_NEON) ? DAV1D_ARM_CPU_FLAG_NEON : 0; + flags |= (hw_cap & HWCAP_ARM_ASIMDDP) ? DAV1D_ARM_CPU_FLAG_DOTPROD : 0; + flags |= (hw_cap & HWCAP_ARM_I8MM) ? DAV1D_ARM_CPU_FLAG_I8MM : 0; + return flags; +} +#endif /* ARCH_AARCH64 */ + +#elif defined(__APPLE__) +#include + +static int have_feature(const char *feature) { + int supported = 0; + size_t size = sizeof(supported); + if (sysctlbyname(feature, &supported, &size, NULL, 0) != 0) { + return 0; + } + return supported; +} + +COLD unsigned dav1d_get_cpu_flags_arm(void) { + unsigned flags = DAV1D_ARM_CPU_FLAG_NEON; + if (have_feature("hw.optional.arm.FEAT_DotProd")) + flags |= DAV1D_ARM_CPU_FLAG_DOTPROD; + if (have_feature("hw.optional.arm.FEAT_I8MM")) + flags |= DAV1D_ARM_CPU_FLAG_I8MM; + /* No SVE and SVE2 feature detection available on Apple platforms. */ + return flags; +} + +#elif defined(_WIN32) +#include -#define NEON_HWCAP HWCAP_NEON +COLD unsigned dav1d_get_cpu_flags_arm(void) { + unsigned flags = DAV1D_ARM_CPU_FLAG_NEON; +#ifdef PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE + if (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)) + flags |= DAV1D_ARM_CPU_FLAG_DOTPROD; +#endif + /* No I8MM or SVE feature detection available on Windows at the time of + * writing. */ + return flags; +} #elif defined(__ANDROID__) +#include #include #include @@ -58,18 +131,25 @@ static unsigned parse_proc_cpuinfo(const char *flag) { char line_buffer[120]; const char *line; + size_t flaglen = strlen(flag); while ((line = fgets(line_buffer, sizeof(line_buffer), file))) { - if (strstr(line, flag)) { - fclose(file); - return 1; + // check all occurances as whole words + const char *found = line; + while ((found = strstr(found, flag))) { + if ((found == line_buffer || !isgraph(found[-1])) && + (isspace(found[flaglen]) || feof(file))) { + fclose(file); + return 1; + } + found += flaglen; } // if line is incomplete seek back to avoid splitting the search // string into two buffers - if (!strchr(line, '\n') && strlen(line) > strlen(flag)) { + if (!strchr(line, '\n') && strlen(line) > flaglen) { // use fseek since the 64 bit fseeko is only available since // Android API level 24 and meson defines _FILE_OFFSET_BITS // by default 64 - if (fseek(file, -strlen(flag), SEEK_CUR)) + if (fseek(file, -flaglen, SEEK_CUR)) break; } } @@ -78,22 +158,23 @@ static unsigned parse_proc_cpuinfo(const char *flag) { return 0; } -#endif COLD unsigned dav1d_get_cpu_flags_arm(void) { - unsigned flags = 0; -#if defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32) || ARCH_AARCH64 - flags |= DAV1D_ARM_CPU_FLAG_NEON; -#elif defined(HAVE_GETAUXVAL) && ARCH_ARM - unsigned long hw_cap = getauxval(AT_HWCAP); - flags |= (hw_cap & NEON_HWCAP) ? DAV1D_ARM_CPU_FLAG_NEON : 0; -#elif defined(HAVE_ELF_AUX_INFO) && ARCH_ARM - unsigned long hw_cap = 0; - elf_aux_info(AT_HWCAP, &hw_cap, sizeof(hw_cap)); - flags |= (hw_cap & NEON_HWCAP) ? DAV1D_ARM_CPU_FLAG_NEON : 0; -#elif defined(__ANDROID__) - flags |= parse_proc_cpuinfo("neon") ? DAV1D_ARM_CPU_FLAG_NEON : 0; -#endif - + unsigned flags = parse_proc_cpuinfo("neon") ? DAV1D_ARM_CPU_FLAG_NEON : 0; + flags |= parse_proc_cpuinfo("asimd") ? DAV1D_ARM_CPU_FLAG_NEON : 0; + flags |= parse_proc_cpuinfo("asimddp") ? DAV1D_ARM_CPU_FLAG_DOTPROD : 0; + flags |= parse_proc_cpuinfo("i8mm") ? DAV1D_ARM_CPU_FLAG_I8MM : 0; +#if ARCH_AARCH64 + flags |= parse_proc_cpuinfo("sve") ? DAV1D_ARM_CPU_FLAG_SVE : 0; + flags |= parse_proc_cpuinfo("sve2") ? DAV1D_ARM_CPU_FLAG_SVE2 : 0; +#endif /* ARCH_AARCH64 */ return flags; } + +#else /* Unsupported OS */ + +COLD unsigned dav1d_get_cpu_flags_arm(void) { + return 0; +} + +#endif diff --git a/third_party/dav1d/src/arm/cpu.h b/third_party/dav1d/src/arm/cpu.h index 8c10a1b6b0..de9bde6ccf 100644 --- a/third_party/dav1d/src/arm/cpu.h +++ b/third_party/dav1d/src/arm/cpu.h @@ -30,6 +30,10 @@ enum CpuFlags { DAV1D_ARM_CPU_FLAG_NEON = 1 << 0, + DAV1D_ARM_CPU_FLAG_DOTPROD = 1 << 1, + DAV1D_ARM_CPU_FLAG_I8MM = 1 << 2, + DAV1D_ARM_CPU_FLAG_SVE = 1 << 3, + DAV1D_ARM_CPU_FLAG_SVE2 = 1 << 4, }; unsigned dav1d_get_cpu_flags_arm(void); diff --git a/third_party/dav1d/src/arm/itx.h b/third_party/dav1d/src/arm/itx.h index 2ecd086b3b..17234e027a 100644 --- a/third_party/dav1d/src/arm/itx.h +++ b/third_party/dav1d/src/arm/itx.h @@ -117,9 +117,11 @@ static ALWAYS_INLINE void itx_dsp_init_arm(Dav1dInvTxfmDSPContext *const c, int if (!(flags & DAV1D_ARM_CPU_FLAG_NEON)) return; + assign_itx_fn( , 4, 4, wht_wht, WHT_WHT, neon); + if (BITDEPTH == 16 && bpc != 10) return; - assign_itx17_fn( , 4, 4, neon); + assign_itx16_fn( , 4, 4, neon); assign_itx16_fn(R, 4, 8, neon); assign_itx16_fn(R, 4, 16, neon); assign_itx16_fn(R, 8, 4, neon); diff --git a/third_party/dav1d/src/arm/msac.h b/third_party/dav1d/src/arm/msac.h index 9db0bf86ae..6eee0da424 100644 --- a/third_party/dav1d/src/arm/msac.h +++ b/third_party/dav1d/src/arm/msac.h @@ -39,7 +39,7 @@ unsigned dav1d_msac_decode_bool_adapt_neon(MsacContext *s, uint16_t *cdf); unsigned dav1d_msac_decode_bool_equi_neon(MsacContext *s); unsigned dav1d_msac_decode_bool_neon(MsacContext *s, unsigned f); -#if ARCH_AARCH64 || defined(__ARM_NEON) +#if defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32) || ARCH_AARCH64 #define dav1d_msac_decode_symbol_adapt4 dav1d_msac_decode_symbol_adapt4_neon #define dav1d_msac_decode_symbol_adapt8 dav1d_msac_decode_symbol_adapt8_neon #define dav1d_msac_decode_symbol_adapt16 dav1d_msac_decode_symbol_adapt16_neon diff --git a/third_party/dav1d/src/cpu.h b/third_party/dav1d/src/cpu.h index c9009c7778..d20c5f0168 100644 --- a/third_party/dav1d/src/cpu.h +++ b/third_party/dav1d/src/cpu.h @@ -64,6 +64,20 @@ static ALWAYS_INLINE unsigned dav1d_get_cpu_flags(void) { #if defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32) || ARCH_AARCH64 flags |= DAV1D_ARM_CPU_FLAG_NEON; #endif +#ifdef __ARM_FEATURE_DOTPROD + flags |= DAV1D_ARM_CPU_FLAG_DOTPROD; +#endif +#ifdef __ARM_FEATURE_MATMUL_INT8 + flags |= DAV1D_ARM_CPU_FLAG_I8MM; +#endif +#if ARCH_AARCH64 +#ifdef __ARM_FEATURE_SVE + flags |= DAV1D_ARM_CPU_FLAG_SVE; +#endif +#ifdef __ARM_FEATURE_SVE2 + flags |= DAV1D_ARM_CPU_FLAG_SVE2; +#endif +#endif /* ARCH_AARCH64 */ #elif ARCH_PPC64LE #if defined(__VSX__) flags |= DAV1D_PPC_CPU_FLAG_VSX; diff --git a/third_party/dav1d/src/ext/x86/x86inc.asm b/third_party/dav1d/src/ext/x86/x86inc.asm index 68b1f74f4b..d2bd758e67 100644 --- a/third_party/dav1d/src/ext/x86/x86inc.asm +++ b/third_party/dav1d/src/ext/x86/x86inc.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* x86inc.asm: x86 abstraction layer ;***************************************************************************** -;* Copyright (C) 2005-2022 x264 project +;* Copyright (C) 2005-2024 x264 project ;* ;* Authors: Loren Merritt ;* Henrik Gramner @@ -104,7 +104,7 @@ %endif %define HAVE_PRIVATE_EXTERN 1 -%ifdef __NASM_VER__ +%ifdef __NASM_VERSION_ID__ %use smartalign %if __NASM_VERSION_ID__ < 0x020e0000 ; 2.14 %define HAVE_PRIVATE_EXTERN 0 @@ -386,7 +386,24 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %endif %endmacro -%macro ALLOC_STACK 0-2 0, 0 ; stack_size, n_xmm_regs (for win64 only) +%macro RESET_STACK_STATE 0 + %ifidn rstk, rsp + %assign stack_offset stack_offset - stack_size_padded + %else + %xdefine rstk rsp + %endif + %assign stack_size 0 + %assign stack_size_padded 0 + %assign xmm_regs_used 0 +%endmacro + +%macro ALLOC_STACK 0-2 0, 0 ; stack_size, n_xmm_regs + RESET_STACK_STATE + %ifnum %2 + %if mmsize != 8 + %assign xmm_regs_used %2 + %endif + %endif %ifnum %1 %if %1 != 0 %assign %%pad 0 @@ -396,11 +413,8 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %endif %if WIN64 %assign %%pad %%pad + 32 ; shadow space - %if mmsize != 8 - %assign xmm_regs_used %2 - %if xmm_regs_used > 8 - %assign %%pad %%pad + (xmm_regs_used-8)*16 ; callee-saved xmm registers - %endif + %if xmm_regs_used > 8 + %assign %%pad %%pad + (xmm_regs_used-8)*16 ; callee-saved xmm registers %endif %endif %if required_stack_alignment <= STACK_ALIGNMENT @@ -496,35 +510,62 @@ DECLARE_REG 14, R13, 120 %endif %endmacro -%macro WIN64_PUSH_XMM 0 - ; Use the shadow space to store XMM6 and XMM7, the rest needs stack space allocated. - %if xmm_regs_used > 6 + high_mm_regs - movaps [rstk + stack_offset + 8], xmm6 - %endif - %if xmm_regs_used > 7 + high_mm_regs - movaps [rstk + stack_offset + 24], xmm7 - %endif - %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 - %if %%xmm_regs_on_stack > 0 - %assign %%i 8 - %rep %%xmm_regs_on_stack - movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i - %assign %%i %%i+1 - %endrep +; Push XMM registers to the stack. If no argument is specified all used register +; will be pushed, otherwise only push previously unpushed registers. +%macro WIN64_PUSH_XMM 0-2 ; new_xmm_regs_used, xmm_regs_pushed + %if mmsize != 8 + %if %0 == 2 + %assign %%pushed %2 + %assign xmm_regs_used %1 + %elif %0 == 1 + %assign %%pushed xmm_regs_used + %assign xmm_regs_used %1 + %else + %assign %%pushed 0 + %endif + ; Use the shadow space to store XMM6 and XMM7, the rest needs stack space allocated. + %if %%pushed <= 6 + high_mm_regs && xmm_regs_used > 6 + high_mm_regs + movaps [rstk + stack_offset + 8], xmm6 + %endif + %if %%pushed <= 7 + high_mm_regs && xmm_regs_used > 7 + high_mm_regs + movaps [rstk + stack_offset + 24], xmm7 + %endif + %assign %%pushed %%pushed - high_mm_regs - 8 + %if %%pushed < 0 + %assign %%pushed 0 + %endif + %assign %%regs_to_push xmm_regs_used - %%pushed - high_mm_regs - 8 + %if %%regs_to_push > 0 + ASSERT (%%regs_to_push + %%pushed) * 16 <= stack_size_padded - stack_size - 32 + %assign %%i %%pushed + 8 + %rep %%regs_to_push + movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i + %assign %%i %%i+1 + %endrep + %endif %endif %endmacro -%macro WIN64_SPILL_XMM 1 - %assign xmm_regs_used %1 - ASSERT xmm_regs_used <= 16 + high_mm_regs - %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 - %if %%xmm_regs_on_stack > 0 - ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack. - %assign %%pad %%xmm_regs_on_stack*16 + 32 - %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) - SUB rsp, stack_size_padded +; Allocated stack space for XMM registers and push all, or a subset, of those +%macro WIN64_SPILL_XMM 1-2 ; xmm_regs_used, xmm_regs_reserved + RESET_STACK_STATE + %if mmsize != 8 + %assign xmm_regs_used %1 + ASSERT xmm_regs_used <= 16 + high_mm_regs + %if %0 == 2 + ASSERT %2 >= %1 + %assign %%xmm_regs_on_stack %2 - high_mm_regs - 8 + %else + %assign %%xmm_regs_on_stack %1 - high_mm_regs - 8 + %endif + %if %%xmm_regs_on_stack > 0 + ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack. + %assign %%pad %%xmm_regs_on_stack*16 + 32 + %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) + SUB rsp, stack_size_padded + %endif + WIN64_PUSH_XMM %endif - WIN64_PUSH_XMM %endmacro %macro WIN64_RESTORE_XMM_INTERNAL 0 @@ -555,9 +596,7 @@ DECLARE_REG 14, R13, 120 %macro WIN64_RESTORE_XMM 0 WIN64_RESTORE_XMM_INTERNAL - %assign stack_offset (stack_offset-stack_size_padded) - %assign stack_size_padded 0 - %assign xmm_regs_used 0 + RESET_STACK_STATE %endmacro %define has_epilogue regs_used > 7 || stack_size > 0 || vzeroupper_required || xmm_regs_used > 6+high_mm_regs @@ -592,12 +631,11 @@ DECLARE_REG 14, R13, 72 %macro PROLOGUE 2-5+ 0, 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... %assign num_args %1 %assign regs_used %2 - %assign xmm_regs_used %3 ASSERT regs_used >= num_args SETUP_STACK_POINTER %4 ASSERT regs_used <= 15 PUSH_IF_USED 9, 10, 11, 12, 13, 14 - ALLOC_STACK %4 + ALLOC_STACK %4, %3 LOAD_IF_USED 6, 7, 8, 9, 10, 11, 12, 13, 14 %if %0 > 4 %ifnum %4 @@ -661,7 +699,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 SETUP_STACK_POINTER %4 ASSERT regs_used <= 7 PUSH_IF_USED 3, 4, 5, 6 - ALLOC_STACK %4 + ALLOC_STACK %4, %3 LOAD_IF_USED 0, 1, 2, 3, 4, 5, 6 %if %0 > 4 %ifnum %4 @@ -694,13 +732,19 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %endif ;====================================================================== %if WIN64 == 0 - %macro WIN64_SPILL_XMM 1 - %assign xmm_regs_used %1 + %macro WIN64_SPILL_XMM 1-2 + RESET_STACK_STATE + %if mmsize != 8 + %assign xmm_regs_used %1 + %endif %endmacro %macro WIN64_RESTORE_XMM 0 - %assign xmm_regs_used 0 + RESET_STACK_STATE %endmacro - %macro WIN64_PUSH_XMM 0 + %macro WIN64_PUSH_XMM 0-2 + %if mmsize != 8 && %0 >= 1 + %assign xmm_regs_used %1 + %endif %endmacro %endif @@ -845,9 +889,26 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %1: %2 %endmacro -; This is needed for ELF, otherwise the GNU linker assumes the stack is executable by default. %if FORMAT_ELF + ; The GNU linker assumes the stack is executable by default. [SECTION .note.GNU-stack noalloc noexec nowrite progbits] + + %ifdef __NASM_VERSION_ID__ + %if __NASM_VERSION_ID__ >= 0x020e0300 ; 2.14.03 + %if ARCH_X86_64 + ; Control-flow Enforcement Technology (CET) properties. + [SECTION .note.gnu.property alloc noexec nowrite note align=gprsize] + dd 0x00000004 ; n_namesz + dd gprsize + 8 ; n_descsz + dd 0x00000005 ; n_type = NT_GNU_PROPERTY_TYPE_0 + db "GNU",0 ; n_name + dd 0xc0000002 ; pr_type = GNU_PROPERTY_X86_FEATURE_1_AND + dd 0x00000004 ; pr_datasz + dd 0x00000002 ; pr_data = GNU_PROPERTY_X86_FEATURE_1_SHSTK + dd 0x00000000 ; pr_padding + %endif + %endif + %endif %endif ; Tell debuggers how large the function was. @@ -883,21 +944,22 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign cpuflags_sse4 (1<<10) | cpuflags_ssse3 %assign cpuflags_sse42 (1<<11) | cpuflags_sse4 %assign cpuflags_aesni (1<<12) | cpuflags_sse42 -%assign cpuflags_gfni (1<<13) | cpuflags_sse42 -%assign cpuflags_avx (1<<14) | cpuflags_sse42 -%assign cpuflags_xop (1<<15) | cpuflags_avx -%assign cpuflags_fma4 (1<<16) | cpuflags_avx -%assign cpuflags_fma3 (1<<17) | cpuflags_avx -%assign cpuflags_bmi1 (1<<18) | cpuflags_avx|cpuflags_lzcnt -%assign cpuflags_bmi2 (1<<19) | cpuflags_bmi1 -%assign cpuflags_avx2 (1<<20) | cpuflags_fma3|cpuflags_bmi2 -%assign cpuflags_avx512 (1<<21) | cpuflags_avx2 ; F, CD, BW, DQ, VL -%assign cpuflags_avx512icl (1<<22) | cpuflags_avx512|cpuflags_gfni ; VNNI, IFMA, VBMI, VBMI2, VPOPCNTDQ, BITALG, VAES, VPCLMULQDQ - -%assign cpuflags_cache32 (1<<23) -%assign cpuflags_cache64 (1<<24) -%assign cpuflags_aligned (1<<25) ; not a cpu feature, but a function variant -%assign cpuflags_atom (1<<26) +%assign cpuflags_clmul (1<<13) | cpuflags_sse42 +%assign cpuflags_gfni (1<<14) | cpuflags_aesni|cpuflags_clmul +%assign cpuflags_avx (1<<15) | cpuflags_sse42 +%assign cpuflags_xop (1<<16) | cpuflags_avx +%assign cpuflags_fma4 (1<<17) | cpuflags_avx +%assign cpuflags_fma3 (1<<18) | cpuflags_avx +%assign cpuflags_bmi1 (1<<19) | cpuflags_avx|cpuflags_lzcnt +%assign cpuflags_bmi2 (1<<20) | cpuflags_bmi1 +%assign cpuflags_avx2 (1<<21) | cpuflags_fma3|cpuflags_bmi2 +%assign cpuflags_avx512 (1<<22) | cpuflags_avx2 ; F, CD, BW, DQ, VL +%assign cpuflags_avx512icl (1<<23) | cpuflags_avx512|cpuflags_gfni ; VNNI, IFMA, VBMI, VBMI2, VPOPCNTDQ, BITALG, VAES, VPCLMULQDQ + +%assign cpuflags_cache32 (1<<24) +%assign cpuflags_cache64 (1<<25) +%assign cpuflags_aligned (1<<26) ; not a cpu feature, but a function variant +%assign cpuflags_atom (1<<27) ; Returns a boolean value expressing whether or not the specified cpuflag is enabled. %define cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1) @@ -939,13 +1001,13 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %endif %if ARCH_X86_64 || cpuflag(sse2) - %ifdef __NASM_VER__ + %ifdef __NASM_VERSION_ID__ ALIGNMODE p6 %else CPU amdnop %endif %else - %ifdef __NASM_VER__ + %ifdef __NASM_VERSION_ID__ ALIGNMODE nop %else CPU basicnop @@ -1035,6 +1097,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %if WIN64 AVX512_MM_PERMUTATION 6 ; Swap callee-saved registers with volatile registers %endif + %xdefine bcstw 1to8 %xdefine bcstd 1to4 %xdefine bcstq 1to2 %endmacro @@ -1050,6 +1113,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, INIT_CPUFLAGS %1 DEFINE_MMREGS ymm AVX512_MM_PERMUTATION + %xdefine bcstw 1to16 %xdefine bcstd 1to8 %xdefine bcstq 1to4 %endmacro @@ -1065,6 +1129,7 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, INIT_CPUFLAGS %1 DEFINE_MMREGS zmm AVX512_MM_PERMUTATION + %xdefine bcstw 1to32 %xdefine bcstd 1to16 %xdefine bcstq 1to8 %endmacro @@ -1607,11 +1672,11 @@ AVX_INSTR pavgb, mmx2, 0, 0, 1 AVX_INSTR pavgw, mmx2, 0, 0, 1 AVX_INSTR pblendvb, sse4, 0, 1, 0 ; last operand must be xmm0 with legacy encoding AVX_INSTR pblendw, sse4, 0, 1, 0 -AVX_INSTR pclmulhqhqdq, fnord, 0, 0, 0 -AVX_INSTR pclmulhqlqdq, fnord, 0, 0, 0 -AVX_INSTR pclmullqhqdq, fnord, 0, 0, 0 -AVX_INSTR pclmullqlqdq, fnord, 0, 0, 0 -AVX_INSTR pclmulqdq, fnord, 0, 1, 0 +AVX_INSTR pclmulhqhqdq, clmul, 0, 0, 0 +AVX_INSTR pclmulhqlqdq, clmul, 0, 0, 0 +AVX_INSTR pclmullqhqdq, clmul, 0, 0, 0 +AVX_INSTR pclmullqlqdq, clmul, 0, 0, 0 +AVX_INSTR pclmulqdq, clmul, 0, 1, 0 AVX_INSTR pcmpeqb, mmx, 0, 0, 1 AVX_INSTR pcmpeqd, mmx, 0, 0, 1 AVX_INSTR pcmpeqq, sse4, 0, 0, 1 @@ -1766,6 +1831,7 @@ GPR_INSTR blsi, bmi1 GPR_INSTR blsmsk, bmi1 GPR_INSTR blsr, bmi1 GPR_INSTR bzhi, bmi2 +GPR_INSTR crc32, sse42 GPR_INSTR mulx, bmi2 GPR_INSTR pdep, bmi2 GPR_INSTR pext, bmi2 diff --git a/third_party/dav1d/src/itx_1d.c b/third_party/dav1d/src/itx_1d.c index ca14fc8c41..8f75c653af 100644 --- a/third_party/dav1d/src/itx_1d.c +++ b/third_party/dav1d/src/itx_1d.c @@ -1016,6 +1016,10 @@ void dav1d_inv_identity32_1d_c(int32_t *const c, const ptrdiff_t stride, c[stride * i] *= 4; } +#if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \ + ARCH_AARCH64 || \ + (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \ +)) void dav1d_inv_wht4_1d_c(int32_t *const c, const ptrdiff_t stride) { assert(stride > 0); const int in0 = c[0 * stride], in1 = c[1 * stride]; @@ -1032,3 +1036,4 @@ void dav1d_inv_wht4_1d_c(int32_t *const c, const ptrdiff_t stride) { c[2 * stride] = t1; c[3 * stride] = t2 + t1; } +#endif diff --git a/third_party/dav1d/src/itx_tmpl.c b/third_party/dav1d/src/itx_tmpl.c index 8ff245a0de..a226223c96 100644 --- a/third_party/dav1d/src/itx_tmpl.c +++ b/third_party/dav1d/src/itx_tmpl.c @@ -159,6 +159,10 @@ inv_txfm_fn64(64, 16, 2) inv_txfm_fn64(64, 32, 1) inv_txfm_fn64(64, 64, 2) +#if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \ + ARCH_AARCH64 || \ + (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \ +)) static void inv_txfm_add_wht_wht_4x4_c(pixel *dst, const ptrdiff_t stride, coef *const coeff, const int eob HIGHBD_DECL_SUFFIX) @@ -179,6 +183,7 @@ static void inv_txfm_add_wht_wht_4x4_c(pixel *dst, const ptrdiff_t stride, for (int x = 0; x < 4; x++) dst[x] = iclip_pixel(dst[x] + *c++); } +#endif #if HAVE_ASM #if ARCH_AARCH64 || ARCH_ARM @@ -236,7 +241,12 @@ COLD void bitfn(dav1d_itx_dsp_init)(Dav1dInvTxfmDSPContext *const c, int bpc) { c->itxfm_add[pfx##TX_##w##X##h][V_ADST] = \ inv_txfm_add_identity_adst_##w##x##h##_c; \ +#if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \ + ARCH_AARCH64 || \ + (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \ +)) c->itxfm_add[TX_4X4][WHT_WHT] = inv_txfm_add_wht_wht_4x4_c; +#endif assign_itx_all_fn84( 4, 4, ); assign_itx_all_fn84( 4, 8, R); assign_itx_all_fn84( 4, 16, R); diff --git a/third_party/dav1d/src/loongarch/msac.S b/third_party/dav1d/src/loongarch/msac.S index c371eba4de..5bf18250a5 100644 --- a/third_party/dav1d/src/loongarch/msac.S +++ b/third_party/dav1d/src/loongarch/msac.S @@ -133,55 +133,58 @@ endconst slli.d t4, t4, 48 vpickve2gr.d t6, vr2, 0 sub.d t6, t6, t4 // dif - addi.d t6, t6, 1 clz.w t4, t5 // d xori t4, t4, 16 // d sll.d t6, t6, t4 - addi.d t6, t6, -1 // dif addi.d a5, a0, 28 // cnt - ld.w t7, a5, 0 - sub.w t7, t7, t4 // cnt-d + ld.w t0, a5, 0 sll.w t5, t5, t4 + sub.w t7, t0, t4 // cnt-d st.w t5, a4, 0 // store rng - bge t7, zero, 9f + bgeu t0, t4, 9f // refill ld.d t0, a0, 0 // buf_pos - addi.d t1, a0, 8 - ld.d t1, t1, 0 // buf_end + ld.d t1, a0, 8 // buf_end addi.d t2, t0, 8 - blt t1, t2, 1f + bltu t1, t2, 2f - ld.d t0, t0, 0 // next_bits - addi.w t3, t7, 23 // shift_bits = cnt + 23 - addi.w t7, t7, 16 // cnt += 16 - revb.d t0, t0 // next_bits = bswap(next_bits) - srli.w t4, t3, 3 - sub.d t2, t2, t4 // buf_pos -= shift_bits >> 3 - st.d t2, a0, 0 - andi t3, t3, 24 // shift_bits &= 24 - srl.d t0, t0, t3 // next_bits >>= shift_bits - sub.w t3, t3, t7 // shift_bits -= 16 + cnt - sll.d t0, t0, t3 // next_bits <<= shift_bits - li.w t5, 48 - sub.w t7, t5, t3 // cnt = cnt + 64 - shift_bits - xor t6, t6, t0 // dif ^= next_bits - b 9f + ld.d t3, t0, 0 // next_bits + addi.w t1, t7, -48 // shift_bits = cnt + 16 (- 64) + nor t3, t3, t3 + sub.w t2, zero, t1 + revb.d t3, t3 // next_bits = bswap(next_bits) + srli.w t2, t2, 3 // num_bytes_read + srl.d t3, t3, t1 // next_bits >>= (shift_bits & 63) + b 3f 1: - li.w t4, 40 - sub.w t5, t4, t7 // c = 40 - cnt + addi.w t3, t7, -48 + srl.d t3, t3, t3 // pad with ones + b 4f 2: - bge t0, t1, 3f - ld.bu t2, t0, 0 - addi.d t0, t0, 1 - sll.d t2, t2, t5 - xor t6, t6, t2 - addi.w t5, t5, -8 - bge t5, zero, 2b - // refill_eob_end + bgeu t0, t1, 1b + ld.d t3, t1, -8 // next_bits + sub.w t2, t2, t1 + sub.w t1, t1, t0 // num_bytes_left + slli.w t2, t2, 3 + srl.d t3, t3, t2 + addi.w t2, t7, -48 + nor t3, t3, t3 + sub.w t4, zero, t2 + revb.d t3, t3 + srli.w t4, t4, 3 + srl.d t3, t3, t2 + sltu t2, t1, t4 + maskeqz t1, t1, t2 + masknez t2, t4, t2 + or t2, t2, t1 // num_bytes_read 3: - st.d t0, a0, 0 // s->buf_pos = buf_pos - sub.w t7, t4, t5 // cnt = 40 - c + slli.w t1, t2, 3 + add.d t0, t0, t2 + add.w t7, t7, t1 // cnt += num_bits_read + st.d t0, a0, 0 +4: + or t6, t6, t3 // dif |= next_bits 9: st.w t7, a5, 0 // store cnt st.d t6, a6, 0 // store dif @@ -208,7 +211,6 @@ function msac_decode_bool_lsx srli.w t2, t0, 8 // r >> 8 mul.w t2, t2, a1 ld.w a5, a0, 28 // cnt - addi.d t1, t1, 1 // dif + 1 srli.w t2, t2, 1 addi.w t2, t2, 4 // v slli.d t3, t2, 48 // vw @@ -226,49 +228,53 @@ function msac_decode_bool_lsx clz.w t4, t5 // d xori t4, t4, 16 // d sll.d t6, t6, t4 - addi.d t6, t6, -1 // dif - sub.w t7, a5, t4 // cnt-d sll.w t5, t5, t4 + sub.w t7, a5, t4 // cnt-d st.w t5, a0, 24 // store rng - bge t7, zero, 9f + bgeu a5, t4, 9f // refill ld.d t0, a0, 0 // buf_pos - addi.d t1, a0, 8 - ld.d t1, t1, 0 // buf_end + ld.d t1, a0, 8 // buf_end addi.d t2, t0, 8 - blt t1, t2, 1f + bltu t1, t2, 2f - ld.d t0, t0, 0 // next_bits - addi.w t3, t7, 23 // shift_bits = cnt + 23 - addi.w t7, t7, 16 // cnt += 16 - revb.d t0, t0 // next_bits = bswap(next_bits) - srli.w t4, t3, 3 - sub.d t2, t2, t4 // buf_pos -= shift_bits >> 3 - st.d t2, a0, 0 - andi t3, t3, 24 // shift_bits &= 24 - srl.d t0, t0, t3 // next_bits >>= shift_bits - sub.w t3, t3, t7 // shift_bits -= 16 + cnt - sll.d t0, t0, t3 // next_bits <<= shift_bits - li.w t5, 48 - sub.w t7, t5, t3 // cnt = cnt + 64 - shift_bits - xor t6, t6, t0 // dif ^= next_bits - b 9f + ld.d t3, t0, 0 // next_bits + addi.w t1, t7, -48 // shift_bits = cnt + 16 (- 64) + nor t3, t3, t3 + sub.w t2, zero, t1 + revb.d t3, t3 // next_bits = bswap(next_bits) + srli.w t2, t2, 3 // num_bytes_read + srl.d t3, t3, t1 // next_bits >>= (shift_bits & 63) + b 3f 1: - li.w t4, 40 - sub.w t5, t4, t7 // c = 40 - cnt + addi.w t3, t7, -48 + srl.d t3, t3, t3 // pad with ones + b 4f 2: - bge t0, t1, 3f - ld.bu t2, t0, 0 - addi.d t0, t0, 1 - sll.d t2, t2, t5 - xor t6, t6, t2 - addi.w t5, t5, -8 - bge t5, zero, 2b - // refill_eob_end + bgeu t0, t1, 1b + ld.d t3, t1, -8 // next_bits + sub.w t2, t2, t1 + sub.w t1, t1, t0 // num_bytes_left + slli.w t2, t2, 3 + srl.d t3, t3, t2 + addi.w t2, t7, -48 + nor t3, t3, t3 + sub.w t4, zero, t2 + revb.d t3, t3 + srli.w t4, t4, 3 + srl.d t3, t3, t2 + sltu t2, t1, t4 + maskeqz t1, t1, t2 + masknez t2, t4, t2 + or t2, t2, t1 // num_bytes_read 3: - st.d t0, a0, 0 // s->buf_pos = buf_pos - sub.w t7, t4, t5 // cnt = 40 - c + slli.w t1, t2, 3 + add.d t0, t0, t2 + add.w t7, t7, t1 // cnt += num_bits_read + st.d t0, a0, 0 +4: + or t6, t6, t3 // dif |= next_bits 9: st.w t7, a0, 28 // store cnt st.d t6, a0, 16 // store dif @@ -313,54 +319,56 @@ function msac_decode_bool_adapt_lsx st.h t0, a1, 2 .renorm: - // renorm - addi.d t6, t6, 1 clz.w t4, t5 // d xori t4, t4, 16 // d sll.d t6, t6, t4 - addi.d t6, t6, -1 // dif - sub.w t7, a5, t4 // cnt-d sll.w t5, t5, t4 + sub.w t7, a5, t4 // cnt-d st.w t5, a0, 24 // store rng - bge t7, zero, 9f + bgeu a5, t4, 9f // refill ld.d t0, a0, 0 // buf_pos - addi.d t1, a0, 8 - ld.d t1, t1, 0 // buf_end + ld.d t1, a0, 8 // buf_end addi.d t2, t0, 8 - blt t1, t2, 1f + bltu t1, t2, 2f - ld.d t0, t0, 0 // next_bits - addi.w t3, t7, 23 // shift_bits = cnt + 23 - addi.w t7, t7, 16 // cnt += 16 - revb.d t0, t0 // next_bits = bswap(next_bits) - srli.w t4, t3, 3 - sub.d t2, t2, t4 // buf_pos -= shift_bits >> 3 - st.d t2, a0, 0 - andi t3, t3, 24 // shift_bits &= 24 - srl.d t0, t0, t3 // next_bits >>= shift_bits - sub.w t3, t3, t7 // shift_bits -= 16 + cnt - sll.d t0, t0, t3 // next_bits <<= shift_bits - li.w t5, 48 - sub.w t7, t5, t3 // cnt = cnt + 64 - shift_bits - xor t6, t6, t0 // dif ^= next_bits - b 9f + ld.d t3, t0, 0 // next_bits + addi.w t1, t7, -48 // shift_bits = cnt + 16 (- 64) + nor t3, t3, t3 + sub.w t2, zero, t1 + revb.d t3, t3 // next_bits = bswap(next_bits) + srli.w t2, t2, 3 // num_bytes_read + srl.d t3, t3, t1 // next_bits >>= (shift_bits & 63) + b 3f 1: - li.w t4, 40 - sub.w t5, t4, t7 // c = 40 - cnt + addi.w t3, t7, -48 + srl.d t3, t3, t3 // pad with ones + b 4f 2: - bge t0, t1, 3f - ld.bu t2, t0, 0 - addi.d t0, t0, 1 - sll.d t2, t2, t5 - xor t6, t6, t2 - addi.w t5, t5, -8 - bge t5, zero, 2b - // refill_eob_end + bgeu t0, t1, 1b + ld.d t3, t1, -8 // next_bits + sub.w t2, t2, t1 + sub.w t1, t1, t0 // num_bytes_left + slli.w t2, t2, 3 + srl.d t3, t3, t2 + addi.w t2, t7, -48 + nor t3, t3, t3 + sub.w t4, zero, t2 + revb.d t3, t3 + srli.w t4, t4, 3 + srl.d t3, t3, t2 + sltu t2, t1, t4 + maskeqz t1, t1, t2 + masknez t2, t4, t2 + or t2, t2, t1 // num_bytes_read 3: - st.d t0, a0, 0 // s->buf_pos = buf_pos - sub.w t7, t4, t5 // cnt = 40 - c + slli.w t1, t2, 3 + add.d t0, t0, t2 + add.w t7, t7, t1 // cnt += num_bits_read + st.d t0, a0, 0 +4: + or t6, t6, t3 // dif |= next_bits 9: st.w t7, a0, 28 // store cnt st.d t6, a0, 16 // store dif diff --git a/third_party/dav1d/src/msac.c b/third_party/dav1d/src/msac.c index 43d8ae5d07..971ba85e29 100644 --- a/third_party/dav1d/src/msac.c +++ b/third_party/dav1d/src/msac.c @@ -43,15 +43,40 @@ static inline void ctx_refill(MsacContext *const s) { const uint8_t *buf_end = s->buf_end; int c = EC_WIN_SIZE - s->cnt - 24; ec_win dif = s->dif; - while (c >= 0 && buf_pos < buf_end) { - dif ^= ((ec_win)*buf_pos++) << c; + do { + if (buf_pos >= buf_end) { + // set remaining bits to 1; + dif |= ~(~(ec_win)0xff << c); + break; + } + dif |= (ec_win)(*buf_pos++ ^ 0xff) << c; c -= 8; - } + } while (c >= 0); s->dif = dif; s->cnt = EC_WIN_SIZE - c - 24; s->buf_pos = buf_pos; } +int dav1d_msac_decode_subexp(MsacContext *const s, const int ref, + const int n, unsigned k) +{ + assert(n >> k == 8); + + unsigned a = 0; + if (dav1d_msac_decode_bool_equi(s)) { + if (dav1d_msac_decode_bool_equi(s)) + k += dav1d_msac_decode_bool_equi(s) + 1; + a = 1 << k; + } + const unsigned v = dav1d_msac_decode_bools(s, k) + a; + return ref * 2 <= n ? inv_recenter(ref, v) : + n - 1 - inv_recenter(n - 1 - ref, v); +} + +#if !(HAVE_ASM && TRIM_DSP_FUNCTIONS && ( \ + ARCH_AARCH64 || \ + (ARCH_ARM && (defined(__ARM_NEON) || defined(__APPLE__) || defined(_WIN32))) \ +)) /* Takes updated dif and range values, renormalizes them so that * 32768 <= rng < 65536 (reading more bytes from the stream into dif if * necessary), and stores them back in the decoder context. @@ -61,11 +86,13 @@ static inline void ctx_norm(MsacContext *const s, const ec_win dif, const unsigned rng) { const int d = 15 ^ (31 ^ clz(rng)); + const int cnt = s->cnt; assert(rng <= 65535U); - s->cnt -= d; - s->dif = ((dif + 1) << d) - 1; /* Shift in 1s in the LSBs */ + s->dif = dif << d; s->rng = rng << d; - if (s->cnt < 0) + s->cnt = cnt - d; + // unsigned compare avoids redundant refills at eob + if ((unsigned)cnt < (unsigned)d) ctx_refill(s); } @@ -100,22 +127,6 @@ unsigned dav1d_msac_decode_bool_c(MsacContext *const s, const unsigned f) { return !ret; } -int dav1d_msac_decode_subexp(MsacContext *const s, const int ref, - const int n, unsigned k) -{ - assert(n >> k == 8); - - unsigned a = 0; - if (dav1d_msac_decode_bool_equi(s)) { - if (dav1d_msac_decode_bool_equi(s)) - k += dav1d_msac_decode_bool_equi(s) + 1; - a = 1 << k; - } - const unsigned v = dav1d_msac_decode_bools(s, k) + a; - return ref * 2 <= n ? inv_recenter(ref, v) : - n - 1 - inv_recenter(n - 1 - ref, v); -} - /* Decodes a symbol given an inverse cumulative distribution function (CDF) * table in Q15. */ unsigned dav1d_msac_decode_symbol_adapt_c(MsacContext *const s, @@ -188,13 +199,14 @@ unsigned dav1d_msac_decode_hi_tok_c(MsacContext *const s, uint16_t *const cdf) { } return tok; } +#endif void dav1d_msac_init(MsacContext *const s, const uint8_t *const data, const size_t sz, const int disable_cdf_update_flag) { s->buf_pos = data; s->buf_end = data + sz; - s->dif = ((ec_win)1 << (EC_WIN_SIZE - 1)) - 1; + s->dif = 0; s->rng = 0x8000; s->cnt = -15; s->allow_update_cdf = !disable_cdf_update_flag; diff --git a/third_party/dav1d/src/ppc/cdef_tmpl.c b/third_party/dav1d/src/ppc/cdef_tmpl.c index e2e759810f..6ef87ad448 100644 --- a/third_party/dav1d/src/ppc/cdef_tmpl.c +++ b/third_party/dav1d/src/ppc/cdef_tmpl.c @@ -29,11 +29,10 @@ #if BITDEPTH == 8 static inline i16x8 vconstrain(const i16x8 diff, const int16_t threshold, - const int damping) + const uint16_t shift) { const i16x8 zero = vec_splat_s16(0); if (!threshold) return zero; - const uint16_t shift = imax(0, damping - ulog2(threshold)); const i16x8 abs_diff = vec_abs(diff); const b16x8 mask = vec_cmplt(diff, zero); const i16x8 thr = vec_splats(threshold); @@ -44,7 +43,7 @@ static inline i16x8 vconstrain(const i16x8 diff, const int16_t threshold, return vec_sel(min, neg, mask); } -static inline void copy4xN(uint16_t *tmp, const ptrdiff_t tmp_stride, +static inline void copy4xN(uint16_t *tmp, const uint8_t *src, const ptrdiff_t src_stride, const uint8_t (*left)[2], const uint8_t *const top, const uint8_t *const bottom, const int w, const int h, @@ -114,7 +113,7 @@ static inline void copy4xN(uint16_t *tmp, const ptrdiff_t tmp_stride, } } -static inline void copy8xN(uint16_t *tmp, const ptrdiff_t tmp_stride, +static inline void copy8xN(uint16_t *tmp, const uint8_t *src, const ptrdiff_t src_stride, const uint8_t (*left)[2], const uint8_t *const top, const uint8_t *const bottom, const int w, const int h, @@ -218,16 +217,12 @@ static inline i16x8 max_mask(i16x8 a, i16x8 b) { #define LOAD_PIX(addr) \ const i16x8 px = (i16x8)vec_vsx_ld(0, addr); \ - i16x8 max = px; \ - i16x8 min = px; \ i16x8 sum = vec_splat_s16(0); #define LOAD_PIX4(addr) \ const i16x8 a = (i16x8)vec_vsx_ld(0, addr); \ - const i16x8 b = (i16x8)vec_vsx_ld(0, addr + tmp_stride); \ + const i16x8 b = (i16x8)vec_vsx_ld(0, addr + 8); \ const i16x8 px = vec_xxpermdi(a, b, 0); \ - i16x8 max = px; \ - i16x8 min = px; \ i16x8 sum = vec_splat_s16(0); #define LOAD_DIR(p, addr, o0, o1) \ @@ -238,22 +233,26 @@ static inline i16x8 max_mask(i16x8 a, i16x8 b) { #define LOAD_DIR4(p, addr, o0, o1) \ LOAD_DIR(p ## a, addr, o0, o1) \ - LOAD_DIR(p ## b, addr + tmp_stride, o0, o1) \ + LOAD_DIR(p ## b, addr + 8, o0, o1) \ const i16x8 p ## 0 = vec_xxpermdi(p ## a ## 0, p ## b ## 0, 0); \ const i16x8 p ## 1 = vec_xxpermdi(p ## a ## 1, p ## b ## 1, 0); \ const i16x8 p ## 2 = vec_xxpermdi(p ## a ## 2, p ## b ## 2, 0); \ const i16x8 p ## 3 = vec_xxpermdi(p ## a ## 3, p ## b ## 3, 0); -#define CONSTRAIN(p, strength) \ +#define CONSTRAIN(p, strength, shift) \ const i16x8 p ## _d0 = vec_sub(p ## 0, px); \ const i16x8 p ## _d1 = vec_sub(p ## 1, px); \ const i16x8 p ## _d2 = vec_sub(p ## 2, px); \ const i16x8 p ## _d3 = vec_sub(p ## 3, px); \ \ - i16x8 p ## _c0 = vconstrain(p ## _d0, strength, damping); \ - i16x8 p ## _c1 = vconstrain(p ## _d1, strength, damping); \ - i16x8 p ## _c2 = vconstrain(p ## _d2, strength, damping); \ - i16x8 p ## _c3 = vconstrain(p ## _d3, strength, damping); + i16x8 p ## _c0 = vconstrain(p ## _d0, strength, shift); \ + i16x8 p ## _c1 = vconstrain(p ## _d1, strength, shift); \ + i16x8 p ## _c2 = vconstrain(p ## _d2, strength, shift); \ + i16x8 p ## _c3 = vconstrain(p ## _d3, strength, shift); + +#define SETUP_MINMAX \ + i16x8 max = px; \ + i16x8 min = px; \ #define MIN_MAX(p) \ max = max_mask(p ## 0, max); \ @@ -265,19 +264,16 @@ static inline i16x8 max_mask(i16x8 a, i16x8 b) { max = max_mask(p ## 3, max); \ min = vec_min(p ## 3, min); -#define PRI_0(p) \ - p ## _c0 = vec_add(vec_sl(p ## _c0, vec_splat_u16(1)), vec_sl(p ## _c0, vec_splats(tap_even))); \ - p ## _c1 = vec_add(vec_sl(p ## _c1, vec_splat_u16(1)), vec_sl(p ## _c1, vec_splats(tap_even))); +#define MAKE_TAPS \ + const int16_t tap_odd = (pri_strength >> bitdepth_min_8) & 1; \ + const i16x8 tap0 = vec_splats((int16_t)(4 - tap_odd)); \ + const i16x8 tap1 = vec_splats((int16_t)(2 + tap_odd)); -#define PRI_1(p) \ - p ## _c2 = vec_sub(vec_sl(p ## _c2, vec_splat_u16(2)), vec_sl(p ## _c2, vec_splats(tap_even))); \ - p ## _c3 = vec_sub(vec_sl(p ## _c3, vec_splat_u16(2)), vec_sl(p ## _c3, vec_splats(tap_even))); - -#define SEC_0(p) \ - p ## _c0 = vec_sl(p ## _c0, vec_splat_u16(1)); \ - p ## _c1 = vec_sl(p ## _c1, vec_splat_u16(1)); \ - p ## _c2 = vec_sl(p ## _c2, vec_splat_u16(1)); \ - p ## _c3 = vec_sl(p ## _c3, vec_splat_u16(1)); +#define PRI_0_UPDATE_SUM(p) \ + sum = vec_madd(tap0, p ## _c0, sum); \ + sum = vec_madd(tap0, p ## _c1, sum); \ + sum = vec_madd(tap1, p ## _c2, sum); \ + sum = vec_madd(tap1, p ## _c3, sum); #define UPDATE_SUM(p) \ const i16x8 p ## sum0 = vec_add(p ## _c0, p ## _c1); \ @@ -285,92 +281,198 @@ static inline i16x8 max_mask(i16x8 a, i16x8 b) { sum = vec_add(sum, p ## sum0); \ sum = vec_add(sum, p ## sum1); +#define SEC_0_UPDATE_SUM(p) \ + sum = vec_madd(vec_splat_s16(2), p ## _c0, sum); \ + sum = vec_madd(vec_splat_s16(2), p ## _c1, sum); \ + sum = vec_madd(vec_splat_s16(2), p ## _c2, sum); \ + sum = vec_madd(vec_splat_s16(2), p ## _c3, sum); + +#define BIAS \ + i16x8 bias = vec_and((i16x8)vec_cmplt(sum, vec_splat_s16(0)), vec_splat_s16(1)); \ + bias = vec_sub(vec_splat_s16(8), bias); \ + +#define STORE4 \ + dst[0] = vdst[0]; \ + dst[1] = vdst[1]; \ + dst[2] = vdst[2]; \ + dst[3] = vdst[3]; \ +\ + tmp += 8; \ + dst += PXSTRIDE(dst_stride); \ + dst[0] = vdst[4]; \ + dst[1] = vdst[5]; \ + dst[2] = vdst[6]; \ + dst[3] = vdst[7]; \ +\ + tmp += 8; \ + dst += PXSTRIDE(dst_stride); + +#define STORE4_CLAMPED \ + BIAS \ + i16x8 unclamped = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); \ + i16x8 vdst = vec_max(vec_min(unclamped, max), min); \ + STORE4 + +#define STORE4_UNCLAMPED \ + BIAS \ + i16x8 vdst = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); \ + STORE4 + +#define STORE8 \ + dst[0] = vdst[0]; \ + dst[1] = vdst[1]; \ + dst[2] = vdst[2]; \ + dst[3] = vdst[3]; \ + dst[4] = vdst[4]; \ + dst[5] = vdst[5]; \ + dst[6] = vdst[6]; \ + dst[7] = vdst[7]; \ +\ + tmp += 16; \ + dst += PXSTRIDE(dst_stride); + +#define STORE8_CLAMPED \ + BIAS \ + i16x8 unclamped = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); \ + i16x8 vdst = vec_max(vec_min(unclamped, max), min); \ + STORE8 + +#define STORE8_UNCLAMPED \ + BIAS \ + i16x8 vdst = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); \ + STORE8 + +#define DIRECTIONS(w, tmp_stride) \ + static const int8_t cdef_directions##w[8 /* dir */][2 /* pass */] = { \ + { -1 * tmp_stride + 1, -2 * tmp_stride + 2 }, \ + { 0 * tmp_stride + 1, -1 * tmp_stride + 2 }, \ + { 0 * tmp_stride + 1, 0 * tmp_stride + 2 }, \ + { 0 * tmp_stride + 1, 1 * tmp_stride + 2 }, \ + { 1 * tmp_stride + 1, 2 * tmp_stride + 2 }, \ + { 1 * tmp_stride + 0, 2 * tmp_stride + 1 }, \ + { 1 * tmp_stride + 0, 2 * tmp_stride + 0 }, \ + { 1 * tmp_stride + 0, 2 * tmp_stride - 1 } \ + }; + +DIRECTIONS(4, 8) +DIRECTIONS(8, 16) + static inline void filter_4xN(pixel *dst, const ptrdiff_t dst_stride, const pixel (*left)[2], const pixel *const top, const pixel *const bottom, const int w, const int h, const int pri_strength, const int sec_strength, const int dir, - const int damping, const enum CdefEdgeFlags edges, - const ptrdiff_t tmp_stride, uint16_t *tmp) + const int pri_shift, const int sec_shift, + const enum CdefEdgeFlags edges, uint16_t *tmp) { - const int8_t cdef_directions[8 /* dir */][2 /* pass */] = { - { -1 * tmp_stride + 1, -2 * tmp_stride + 2 }, - { 0 * tmp_stride + 1, -1 * tmp_stride + 2 }, - { 0 * tmp_stride + 1, 0 * tmp_stride + 2 }, - { 0 * tmp_stride + 1, 1 * tmp_stride + 2 }, - { 1 * tmp_stride + 1, 2 * tmp_stride + 2 }, - { 1 * tmp_stride + 0, 2 * tmp_stride + 1 }, - { 1 * tmp_stride + 0, 2 * tmp_stride + 0 }, - { 1 * tmp_stride + 0, 2 * tmp_stride - 1 } - }; const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8; - const uint16_t tap_even = !((pri_strength >> bitdepth_min_8) & 1); - const int off1 = cdef_directions[dir][0]; - const int off1_1 = cdef_directions[dir][1]; + const int off1 = cdef_directions4[dir][0]; + const int off1_1 = cdef_directions4[dir][1]; - const int off2 = cdef_directions[(dir + 2) & 7][0]; - const int off3 = cdef_directions[(dir + 6) & 7][0]; + const int off2 = cdef_directions4[(dir + 2) & 7][0]; + const int off3 = cdef_directions4[(dir + 6) & 7][0]; - const int off2_1 = cdef_directions[(dir + 2) & 7][1]; - const int off3_1 = cdef_directions[(dir + 6) & 7][1]; + const int off2_1 = cdef_directions4[(dir + 2) & 7][1]; + const int off3_1 = cdef_directions4[(dir + 6) & 7][1]; - copy4xN(tmp - 2, tmp_stride, dst, dst_stride, left, top, bottom, w, h, edges); + MAKE_TAPS for (int y = 0; y < h / 2; y++) { LOAD_PIX4(tmp) + SETUP_MINMAX + // Primary pass LOAD_DIR4(p, tmp, off1, off1_1) - CONSTRAIN(p, pri_strength) + CONSTRAIN(p, pri_strength, pri_shift) MIN_MAX(p) - PRI_0(p) - PRI_1(p) - - UPDATE_SUM(p) + PRI_0_UPDATE_SUM(p) // Secondary pass 1 LOAD_DIR4(s, tmp, off2, off3) - CONSTRAIN(s, sec_strength) + CONSTRAIN(s, sec_strength, sec_shift) MIN_MAX(s) - SEC_0(s) - - UPDATE_SUM(s) + SEC_0_UPDATE_SUM(s) // Secondary pass 2 LOAD_DIR4(s2, tmp, off2_1, off3_1) - CONSTRAIN(s2, sec_strength) + CONSTRAIN(s2, sec_strength, sec_shift) MIN_MAX(s2) UPDATE_SUM(s2) // Store - i16x8 bias = vec_and((i16x8)vec_cmplt(sum, vec_splat_s16(0)), vec_splat_s16(1)); - bias = vec_sub(vec_splat_s16(8), bias); - i16x8 unclamped = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); - i16x8 vdst = vec_max(vec_min(unclamped, max), min); - - dst[0] = vdst[0]; - dst[1] = vdst[1]; - dst[2] = vdst[2]; - dst[3] = vdst[3]; - - tmp += tmp_stride; - dst += PXSTRIDE(dst_stride); - dst[0] = vdst[4]; - dst[1] = vdst[5]; - dst[2] = vdst[6]; - dst[3] = vdst[7]; - - tmp += tmp_stride; - dst += PXSTRIDE(dst_stride); + STORE4_CLAMPED + } +} + +static inline void +filter_4xN_pri(pixel *dst, const ptrdiff_t dst_stride, + const pixel (*left)[2], const pixel *const top, + const pixel *const bottom, const int w, const int h, + const int pri_strength, const int dir, + const int pri_shift, const enum CdefEdgeFlags edges, + uint16_t *tmp) +{ + const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8; + const int off1 = cdef_directions4[dir][0]; + const int off1_1 = cdef_directions4[dir][1]; + + MAKE_TAPS + + for (int y = 0; y < h / 2; y++) { + LOAD_PIX4(tmp) + + // Primary pass + LOAD_DIR4(p, tmp, off1, off1_1) + + CONSTRAIN(p, pri_strength, pri_shift) + + PRI_0_UPDATE_SUM(p) + + STORE4_UNCLAMPED + } +} + +static inline void +filter_4xN_sec(pixel *dst, const ptrdiff_t dst_stride, + const pixel (*left)[2], const pixel *const top, + const pixel *const bottom, const int w, const int h, + const int sec_strength, const int dir, + const int sec_shift, const enum CdefEdgeFlags edges, + uint16_t *tmp) +{ + const int off2 = cdef_directions4[(dir + 2) & 7][0]; + const int off3 = cdef_directions4[(dir + 6) & 7][0]; + + const int off2_1 = cdef_directions4[(dir + 2) & 7][1]; + const int off3_1 = cdef_directions4[(dir + 6) & 7][1]; + + for (int y = 0; y < h / 2; y++) { + LOAD_PIX4(tmp) + // Secondary pass 1 + LOAD_DIR4(s, tmp, off2, off3) + + CONSTRAIN(s, sec_strength, sec_shift) + + SEC_0_UPDATE_SUM(s) + + // Secondary pass 2 + LOAD_DIR4(s2, tmp, off2_1, off3_1) + + CONSTRAIN(s2, sec_strength, sec_shift) + + UPDATE_SUM(s2) + + STORE4_UNCLAMPED } } @@ -379,88 +481,121 @@ filter_8xN(pixel *dst, const ptrdiff_t dst_stride, const pixel (*left)[2], const pixel *const top, const pixel *const bottom, const int w, const int h, const int pri_strength, const int sec_strength, const int dir, - const int damping, const enum CdefEdgeFlags edges, - const ptrdiff_t tmp_stride, uint16_t *tmp) + const int pri_shift, const int sec_shift, const enum CdefEdgeFlags edges, + uint16_t *tmp) { - const int8_t cdef_directions[8 /* dir */][2 /* pass */] = { - { -1 * tmp_stride + 1, -2 * tmp_stride + 2 }, - { 0 * tmp_stride + 1, -1 * tmp_stride + 2 }, - { 0 * tmp_stride + 1, 0 * tmp_stride + 2 }, - { 0 * tmp_stride + 1, 1 * tmp_stride + 2 }, - { 1 * tmp_stride + 1, 2 * tmp_stride + 2 }, - { 1 * tmp_stride + 0, 2 * tmp_stride + 1 }, - { 1 * tmp_stride + 0, 2 * tmp_stride + 0 }, - { 1 * tmp_stride + 0, 2 * tmp_stride - 1 } - }; const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8; + const int off1 = cdef_directions8[dir][0]; + const int off1_1 = cdef_directions8[dir][1]; - const uint16_t tap_even = !((pri_strength >> bitdepth_min_8) & 1); - const int off1 = cdef_directions[dir][0]; - const int off1_1 = cdef_directions[dir][1]; + const int off2 = cdef_directions8[(dir + 2) & 7][0]; + const int off3 = cdef_directions8[(dir + 6) & 7][0]; - const int off2 = cdef_directions[(dir + 2) & 7][0]; - const int off3 = cdef_directions[(dir + 6) & 7][0]; + const int off2_1 = cdef_directions8[(dir + 2) & 7][1]; + const int off3_1 = cdef_directions8[(dir + 6) & 7][1]; - const int off2_1 = cdef_directions[(dir + 2) & 7][1]; - const int off3_1 = cdef_directions[(dir + 6) & 7][1]; - - copy8xN(tmp - 2, tmp_stride, dst, dst_stride, left, top, bottom, w, h, edges); + MAKE_TAPS for (int y = 0; y < h; y++) { LOAD_PIX(tmp) + SETUP_MINMAX + // Primary pass LOAD_DIR(p, tmp, off1, off1_1) - CONSTRAIN(p, pri_strength) + CONSTRAIN(p, pri_strength, pri_shift) MIN_MAX(p) - PRI_0(p) - PRI_1(p) - - UPDATE_SUM(p) + PRI_0_UPDATE_SUM(p) // Secondary pass 1 LOAD_DIR(s, tmp, off2, off3) - CONSTRAIN(s, sec_strength) + CONSTRAIN(s, sec_strength, sec_shift) MIN_MAX(s) - SEC_0(s) - - UPDATE_SUM(s) + SEC_0_UPDATE_SUM(s) // Secondary pass 2 LOAD_DIR(s2, tmp, off2_1, off3_1) - CONSTRAIN(s2, sec_strength) + CONSTRAIN(s2, sec_strength, sec_shift) MIN_MAX(s2) UPDATE_SUM(s2) // Store - i16x8 bias = vec_and((i16x8)vec_cmplt(sum, vec_splat_s16(0)), vec_splat_s16(1)); - bias = vec_sub(vec_splat_s16(8), bias); - i16x8 unclamped = vec_add(px, vec_sra(vec_add(sum, bias), vec_splat_u16(4))); - i16x8 vdst = vec_max(vec_min(unclamped, max), min); - - dst[0] = vdst[0]; - dst[1] = vdst[1]; - dst[2] = vdst[2]; - dst[3] = vdst[3]; - dst[4] = vdst[4]; - dst[5] = vdst[5]; - dst[6] = vdst[6]; - dst[7] = vdst[7]; - - tmp += tmp_stride; - dst += PXSTRIDE(dst_stride); + STORE8_CLAMPED + } + +} + +static inline void +filter_8xN_pri(pixel *dst, const ptrdiff_t dst_stride, + const pixel (*left)[2], const pixel *const top, + const pixel *const bottom, const int w, const int h, + const int pri_strength, const int dir, + const int pri_shift, const enum CdefEdgeFlags edges, + uint16_t *tmp) +{ + const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8; + const int off1 = cdef_directions8[dir][0]; + const int off1_1 = cdef_directions8[dir][1]; + + MAKE_TAPS + + for (int y = 0; y < h; y++) { + LOAD_PIX(tmp) + + // Primary pass + LOAD_DIR(p, tmp, off1, off1_1) + + CONSTRAIN(p, pri_strength, pri_shift) + + PRI_0_UPDATE_SUM(p) + + STORE8_UNCLAMPED } +} + +static inline void +filter_8xN_sec(pixel *dst, const ptrdiff_t dst_stride, + const pixel (*left)[2], const pixel *const top, + const pixel *const bottom, const int w, const int h, + const int sec_strength, const int dir, + const int sec_shift, const enum CdefEdgeFlags edges, + uint16_t *tmp) +{ + const int off2 = cdef_directions8[(dir + 2) & 7][0]; + const int off3 = cdef_directions8[(dir + 6) & 7][0]; + + const int off2_1 = cdef_directions8[(dir + 2) & 7][1]; + const int off3_1 = cdef_directions8[(dir + 6) & 7][1]; + + for (int y = 0; y < h; y++) { + LOAD_PIX(tmp) + + // Secondary pass 1 + LOAD_DIR(s, tmp, off2, off3) + CONSTRAIN(s, sec_strength, sec_shift) + + SEC_0_UPDATE_SUM(s) + + // Secondary pass 2 + LOAD_DIR(s2, tmp, off2_1, off3_1) + + CONSTRAIN(s2, sec_strength, sec_shift) + + UPDATE_SUM(s2) + + STORE8_UNCLAMPED + } } #define cdef_fn(w, h, tmp_stride) \ @@ -477,8 +612,22 @@ void dav1d_cdef_filter_##w##x##h##_vsx(pixel *const dst, \ { \ ALIGN_STK_16(uint16_t, tmp_buf, 12 * tmp_stride + 8,); \ uint16_t *tmp = tmp_buf + 2 * tmp_stride + 2; \ - filter_##w##xN(dst, dst_stride, left, top, bottom, w, h, pri_strength, \ - sec_strength, dir, damping, edges, tmp_stride, tmp); \ + copy##w##xN(tmp - 2, dst, dst_stride, left, top, bottom, w, h, edges); \ + if (pri_strength) { \ + const int pri_shift = imax(0, damping - ulog2(pri_strength)); \ + if (sec_strength) { \ + const int sec_shift = damping - ulog2(sec_strength); \ + filter_##w##xN(dst, dst_stride, left, top, bottom, w, h, pri_strength, \ + sec_strength, dir, pri_shift, sec_shift, edges, tmp); \ + } else { \ + filter_##w##xN_pri(dst, dst_stride, left, top, bottom, w, h, pri_strength, \ + dir, pri_shift, edges, tmp); \ + } \ + } else { \ + const int sec_shift = damping - ulog2(sec_strength); \ + filter_##w##xN_sec(dst, dst_stride, left, top, bottom, w, h, sec_strength, \ + dir, sec_shift, edges, tmp); \ + } \ } cdef_fn(4, 4, 8); diff --git a/third_party/dav1d/src/riscv/64/itx.S b/third_party/dav1d/src/riscv/64/itx.S index 60d045150d..dfec548e40 100644 --- a/third_party/dav1d/src/riscv/64/itx.S +++ b/third_party/dav1d/src/riscv/64/itx.S @@ -163,48 +163,48 @@ endfunc vssub.vv \o3, v16, v20 .endm -.macro iadst_4 o0, o1, o2, o3 +.macro iadst_4 o0, o1, o2, o3, lm2, lm li t1, 1321 li t2, 3803 li t3, 2482 - vwmul.vx v4, v0, t1 - vwmul.vx v5, v0, t3 + vwmul.vx v16, v0, t1 + vwmul.vx v18, v0, t3 neg t1, t1 - vwmacc.vx v4, t2, v2 - vwmacc.vx v5, t1, v2 + vwmacc.vx v16, t2, v2 + vwmacc.vx v18, t1, v2 neg t2, t2 - vwmacc.vx v4, t3, v3 - vwmacc.vx v5, t2, v3 + vwmacc.vx v16, t3, v3 + vwmacc.vx v18, t2, v3 - vwsub.vv v6, v0, v2 - vwadd.wv v6, v6, v3 + vwsub.vv v20, v0, v2 + vwadd.wv v20, v20, v3 li t1, 3344 - vwmul.vx v7, v1, t1 + vwmul.vx v22, v1, t1 - vsetvli zero, zero, e32, m1, ta, ma + vsetvli zero, zero, e32, \lm2, ta, ma - vmul.vx v6, v6, t1 + vmul.vx v20, v20, t1 - vadd.vv v8, v4, v5 - vadd.vv v4, v4, v7 - vadd.vv v5, v5, v7 - vsub.vv v7, v8, v7 + vadd.vv v24, v16, v18 + vadd.vv v16, v16, v22 + vadd.vv v18, v18, v22 + vsub.vv v22, v24, v22 li t1, 2048 - vadd.vx v4, v4, t1 - vadd.vx v5, v5, t1 - vadd.vx v6, v6, t1 - vadd.vx v7, v7, t1 + vadd.vx v16, v16, t1 + vadd.vx v18, v18, t1 + vadd.vx v20, v20, t1 + vadd.vx v22, v22, t1 - vsetvli zero, zero, e16, mf2, ta, ma + vsetvli zero, zero, e16, \lm, ta, ma - vnsra.wi \o0, v4, 12 - vnsra.wi \o1, v5, 12 - vnsra.wi \o2, v6, 12 - vnsra.wi \o3, v7, 12 + vnsra.wi \o0, v16, 12 + vnsra.wi \o1, v18, 12 + vnsra.wi \o2, v20, 12 + vnsra.wi \o3, v22, 12 .endm function inv_dct_e16_x4_rvv, export=1, ext=v @@ -213,12 +213,22 @@ function inv_dct_e16_x4_rvv, export=1, ext=v endfunc function inv_adst_e16_x4_rvv, export=1, ext=v - iadst_4 v0, v1, v2, v3 + iadst_4 v0, v1, v2, v3, m1, mf2 jr t0 endfunc function inv_flipadst_e16_x4_rvv, export=1, ext=v - iadst_4 v3, v2, v1, v0 + iadst_4 v3, v2, v1, v0, m1, mf2 + jr t0 +endfunc + +function inv_adst_e16_x4w_rvv, export=1, ext=v + iadst_4 v0, v1, v2, v3, m2, m1 + jr t0 +endfunc + +function inv_flipadst_e16_x4w_rvv, export=1, ext=v + iadst_4 v3, v2, v1, v0, m2, m1 jr t0 endfunc @@ -328,6 +338,8 @@ function inv_txfm_\variant\()add_8x8_rvv, export=1, ext=v .ifc \variant, identity_ // The identity vsadd.vv and downshift vssra.vi 1 cancel out + + j L(itx_8x8_epilog) .else jalr t0, a4 @@ -339,8 +351,8 @@ function inv_txfm_\variant\()add_8x8_rvv, export=1, ext=v vssra.vi v5, v5, 1 vssra.vi v6, v6, 1 vssra.vi v7, v7, 1 -.endif +L(itx_8x8_epilog): vsseg8e16.v v0, (a2) vle16.v v0, (a2) addi t0, a2, 16 @@ -374,9 +386,7 @@ function inv_txfm_\variant\()add_8x8_rvv, export=1, ext=v vmv.v.x v8, zero vse16.v v8, (a2) -.ifc \variant, identity_ itx_8x8_end: -.endif vsetivli zero, 8, e8, mf2, ta, ma vle8.v v8, (a0) add t0, a0, a1 @@ -441,11 +451,12 @@ itx_8x8_end: vse8.v v15, (a0) ret +.endif endfunc .endm -def_fn_8x8_base def_fn_8x8_base identity_ +def_fn_8x8_base function inv_identity_e16_x8_rvv, export=1, ext=v vsadd.vv v0, v0, v0 @@ -530,23 +541,23 @@ endfunc li t5, 2598 li t6, 3166 - vwmul.vx v8, v7, t1 + vwmul.vx v16, v7, t1 neg t1, t1 - vwmul.vx v10, v7, t2 - vwmacc.vx v8, t2, v0 - vwmacc.vx v10, t1, v0 + vwmul.vx v18, v7, t2 + vwmacc.vx v16, t2, v0 + vwmacc.vx v18, t1, v0 - vwmul.vx v12, v5, t3 + vwmul.vx v20, v5, t3 neg t3, t3 - vwmul.vx v14, v5, t4 - vwmacc.vx v12, t4, v2 - vwmacc.vx v14, t3, v2 + vwmul.vx v22, v5, t4 + vwmacc.vx v20, t4, v2 + vwmacc.vx v22, t3, v2 - vwmul.vx v16, v3, t5 + vwmul.vx v24, v3, t5 neg t5, t5 - vwmul.vx v18, v3, t6 - vwmacc.vx v16, t6, v4 - vwmacc.vx v18, t5, v4 + vwmul.vx v26, v3, t6 + vwmacc.vx v24, t6, v4 + vwmacc.vx v26, t5, v4 li t1, 2048 li t2, 1189 @@ -555,95 +566,95 @@ endfunc li t5, 3784 li t6, 2896 - vwmul.vx v20, v1, t2 + vwmul.vx v28, v1, t2 neg t2, t2 - vwmul.vx v22, v1, t3 - vwmacc.vx v20, t3, v6 - vwmacc.vx v22, t2, v6 - - vwadd.wx v8, v8, t1 - vwadd.wx v10, v10, t1 - vwadd.wx v12, v12, t1 - vwadd.wx v14, v14, t1 + vwmul.vx v30, v1, t3 + vwmacc.vx v28, t3, v6 + vwmacc.vx v30, t2, v6 + vwadd.wx v16, v16, t1 vwadd.wx v18, v18, t1 vwadd.wx v20, v20, t1 vwadd.wx v22, v22, t1 + vwadd.wx v24, v24, t1 + vwadd.wx v26, v26, t1 + vwadd.wx v28, v28, t1 + vwadd.wx v30, v30, t1 - vnsra.wi v8, v8, 12 - vnsra.wi v10, v10, 12 - vnsra.wi v12, v12, 12 - vnsra.wi v14, v14, 12 vnsra.wi v16, v16, 12 vnsra.wi v18, v18, 12 vnsra.wi v20, v20, 12 vnsra.wi v22, v22, 12 + vnsra.wi v24, v24, 12 + vnsra.wi v26, v26, 12 + vnsra.wi v28, v28, 12 + vnsra.wi v30, v30, 12 - vssub.vv v4, v8, v16 - vsadd.vv v8, v8, v16 - vsadd.vv v1, v10, v18 - vsadd.vv v2, v12, v20 - vsadd.vv v3, v14, v22 - vssub.vv v5, v10, v18 - vssub.vv v6, v12, v20 - vssub.vv v22, v14, v22 - - vsadd.vv \o0, v8, v2 - vsadd.vv \o7, v1, v3 - vssub.vv v2, v8, v2 - vssub.vv v3, v1, v3 - - vwmul.vx v8, v4, t5 - vwmul.vx v10, v4, t4 - vwmul.vx v12, v22, t5 - vwmul.vx v14, v22, t4 - vwmacc.vx v8, t4, v5 + vssub.vv v4, v16, v24 + vsadd.vv v16, v16, v24 + vsadd.vv v1, v18, v26 + vsadd.vv v2, v20, v28 + vsadd.vv v3, v22, v30 + vssub.vv v5, v18, v26 + vssub.vv v6, v20, v28 + vssub.vv v30, v22, v30 + + vsadd.vv \o0, v16, v2 + vsadd.vv \o7, v1, v3 + vssub.vv v2, v16, v2 + vssub.vv v3, v1, v3 + + vwmul.vx v16, v4, t5 + vwmul.vx v18, v4, t4 + vwmul.vx v20, v30, t5 + vwmul.vx v22, v30, t4 + vwmacc.vx v16, t4, v5 neg t4, t4 - vwmacc.vx v14, t5, v6 + vwmacc.vx v22, t5, v6 neg t5, t5 - vwmacc.vx v12, t4, v6 - vwmacc.vx v10, t5, v5 - - vwadd.wx v8, v8, t1 - vwadd.wx v10, v10, t1 - vwadd.wx v12, v12, t1 - vwadd.wx v14, v14, t1 - - vnsra.wi v8, v8, 12 - vnsra.wi v10, v10, 12 - vnsra.wi v12, v12, 12 - vnsra.wi v14, v14, 12 - - vsadd.vv \o1, v8, v12 - vsadd.vv \o6, v10, v14 - vssub.vv v8, v8, v12 - vssub.vv v9, v10, v14 - - vwmul.vx v10, v2, t6 - vwmul.vx v12, v2, t6 - vwmul.vx v14, v8, t6 - vwmul.vx v16, v8, t6 - vwmacc.vx v10, t6, v3 - vwmacc.vx v14, t6, v9 - neg t6, t6 - vwmacc.vx v12, t6, v3 - vwmacc.vx v16, t6, v9 + vwmacc.vx v20, t4, v6 + vwmacc.vx v18, t5, v5 - vwadd.wx v10, v10, t1 - vwadd.wx v12, v12, t1 - vwadd.wx v14, v14, t1 vwadd.wx v16, v16, t1 + vwadd.wx v18, v18, t1 + vwadd.wx v20, v20, t1 + vwadd.wx v22, v22, t1 - vnsra.wi \o3, v10, 12 - vnsra.wi \o4, v12, 12 - vnsra.wi \o2, v14, 12 - vnsra.wi \o5, v16, 12 + vnsra.wi v16, v16, 12 + vnsra.wi v18, v18, 12 + vnsra.wi v20, v20, 12 + vnsra.wi v22, v22, 12 - vmv.v.x v8, zero - vssub.vv \o1, v8, \o1 - vssub.vv \o3, v8, \o3 - vssub.vv \o5, v8, \o5 - vssub.vv \o7, v8, \o7 + vsadd.vv \o1, v16, v20 + vsadd.vv \o6, v18, v22 + vssub.vv v16, v16, v20 + vssub.vv v17, v18, v22 + + vwmul.vx v18, v2, t6 + vwmul.vx v20, v2, t6 + vwmul.vx v22, v16, t6 + vwmul.vx v24, v16, t6 + vwmacc.vx v18, t6, v3 + vwmacc.vx v22, t6, v17 + neg t6, t6 + vwmacc.vx v20, t6, v3 + vwmacc.vx v24, t6, v17 + + vwadd.wx v18, v18, t1 + vwadd.wx v20, v20, t1 + vwadd.wx v22, v22, t1 + vwadd.wx v24, v24, t1 + + vnsra.wi \o3, v18, 12 + vnsra.wi \o4, v20, 12 + vnsra.wi \o2, v22, 12 + vnsra.wi \o5, v24, 12 + + vmv.v.x v16, zero + vssub.vv \o1, v16, \o1 + vssub.vv \o3, v16, \o3 + vssub.vv \o5, v16, \o5 + vssub.vv \o7, v16, \o7 .endm function inv_dct_e16_x8_rvv, export=1, ext=v @@ -714,6 +725,206 @@ def_fn_8x8 flipadst, identity def_fn_8x8 identity, adst def_fn_8x8 identity, flipadst +function inv_txfm_add_4x8_rvv, export=1, ext=v + csrw vxrm, zero + + vsetivli zero, 8, e16, m1, ta, ma + vle16.v v0, (a2) + addi t0, a2, 16 + vle16.v v1, (t0) + addi t0, t0, 16 + vle16.v v2, (t0) + addi t0, t0, 16 + vle16.v v3, (t0) + + li t1, 2896*8 +.irp i, 0, 1, 2, 3 + vsmul.vx v\i, v\i, t1 +.endr + + jalr t0, a4 + + vsseg4e16.v v0, (a2) + + vsetivli zero, 4, e16, mf2, ta, ma + vmv.v.x v8, zero + vle16.v v0, (a2) + vse16.v v8, (a2) +.irp i, 1, 2, 3, 4, 5, 6, 7 + addi a2, a2, 8 + vle16.v v\i, (a2) + vse16.v v8, (a2) +.endr + + jalr t0, a5 + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + vssra.vi v\i, v\i, 4 +.endr + + vsetvli zero, zero, e8, mf4, ta, ma + vle8.v v8, (a0) + add t0, a0, a1 + vle8.v v9, (t0) +.irp i, 10, 11, 12, 13, 14, 15 + add t0, t0, a1 + vle8.v v\i, (t0) +.endr + + vwaddu.wv v0, v0, v8 + vwaddu.wv v1, v1, v9 + vwaddu.wv v2, v2, v10 + vwaddu.wv v3, v3, v11 + vwaddu.wv v4, v4, v12 + vwaddu.wv v5, v5, v13 + vwaddu.wv v6, v6, v14 + vwaddu.wv v7, v7, v15 + + vsetvli zero, zero, e16, mf2, ta, ma +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + vmax.vx v\i, v\i, zero +.endr + + vsetvli zero, zero, e8, mf4, ta, ma + + vnclipu.wi v8, v0, 0 + vnclipu.wi v9, v1, 0 + vnclipu.wi v10, v2, 0 + vnclipu.wi v11, v3, 0 + vnclipu.wi v12, v4, 0 + vnclipu.wi v13, v5, 0 + vnclipu.wi v14, v6, 0 + vnclipu.wi v15, v7, 0 + + vse8.v v8, (a0) +.irp i, 9, 10, 11, 12, 13, 14, 15 + add a0, a0, a1 + vse8.v v\i, (a0) +.endr + + ret +endfunc + +function inv_txfm_add_8x4_rvv, export=1, ext=v + csrw vxrm, zero + + vsetivli zero, 4, e16, mf2, ta, ma + vle16.v v0, (a2) + addi t0, a2, 8 + vle16.v v1, (t0) +.irp i, 2, 3, 4, 5, 6, 7 + addi t0, t0, 8 + vle16.v v\i, (t0) +.endr + + li t1, 2896*8 +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + vsmul.vx v\i, v\i, t1 +.endr + + jalr t0, a4 + + vsseg8e16.v v0, (a2) + + vsetivli zero, 8, e16, m1, ta, ma + vmv.v.x v4, zero + vle16.v v0, (a2) + vse16.v v4, (a2) +.irp i, 1, 2, 3 + addi a2, a2, 16 + vle16.v v\i, (a2) + vse16.v v4, (a2) +.endr + + jalr t0, a5 + + vssra.vi v0, v0, 4 + vssra.vi v1, v1, 4 + vssra.vi v2, v2, 4 + vssra.vi v3, v3, 4 + + vsetvli zero, zero, e8, mf2, ta, ma + vle8.v v4, (a0) + add t0, a0, a1 + vle8.v v5, (t0) + add t0, t0, a1 + vle8.v v6, (t0) + add t0, t0, a1 + vle8.v v7, (t0) + + vwaddu.wv v0, v0, v4 + vwaddu.wv v1, v1, v5 + vwaddu.wv v2, v2, v6 + vwaddu.wv v3, v3, v7 + + vsetvli zero, zero, e16, m1, ta, ma + vmax.vx v0, v0, zero + vmax.vx v1, v1, zero + vmax.vx v2, v2, zero + vmax.vx v3, v3, zero + + vsetvli zero, zero, e8, mf2, ta, ma + + vnclipu.wi v4, v0, 0 + vnclipu.wi v5, v1, 0 + vnclipu.wi v6, v2, 0 + vnclipu.wi v7, v3, 0 + + vse8.v v4, (a0) + add a0, a0, a1 + vse8.v v5, (a0) + add a0, a0, a1 + vse8.v v6, (a0) + add a0, a0, a1 + vse8.v v7, (a0) + + ret +endfunc + +/* Define symbols added in .if statement */ +.equ dct, 1 +.equ identity, 2 +.equ adst, 3 +.equ flipadst, 4 + +.macro def_fn_48 w, h, txfm1, txfm2 +function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_rvv, export=1 +.if \w == 4 && (\txfm1 == adst || \txfm1 == flipadst) + la a4, inv_\txfm1\()_e16_x\w\()w_rvv +.else + la a4, inv_\txfm1\()_e16_x\w\()_rvv +.endif +.if \h == 4 && (\txfm2 == adst || \txfm2 == flipadst) + la a5, inv_\txfm2\()_e16_x\h\()w_rvv +.else + la a5, inv_\txfm2\()_e16_x\h\()_rvv +.endif + j inv_txfm_add_\w\()x\h\()_rvv +endfunc +.endm + +.macro def_fns_48 w, h +def_fn_48 \w, \h, dct, dct +def_fn_48 \w, \h, identity, identity +def_fn_48 \w, \h, dct, adst +def_fn_48 \w, \h, dct, flipadst +def_fn_48 \w, \h, dct, identity +def_fn_48 \w, \h, adst, dct +def_fn_48 \w, \h, adst, adst +def_fn_48 \w, \h, adst, flipadst +def_fn_48 \w, \h, flipadst, dct +def_fn_48 \w, \h, flipadst, adst +def_fn_48 \w, \h, flipadst, flipadst +def_fn_48 \w, \h, identity, dct +def_fn_48 \w, \h, adst, identity +def_fn_48 \w, \h, flipadst, identity +def_fn_48 \w, \h, identity, adst +def_fn_48 \w, \h, identity, flipadst +.endm + +def_fns_48 4, 8 +def_fns_48 8, 4 + function inv_identity_e16_x16_rvv, export=1, ext=v li t1, 2*(5793-4096)*8 .irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 @@ -1196,10 +1407,12 @@ endfunc .macro def_horz_16 variant function inv_txfm_horz\variant\()_16x8_rvv, export=1, ext=v vmv.v.x v16, zero -.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - vle16.v v\i, (t4) + vle16.v v0, (t4) vse16.v v16, (t4) +.irp i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 add t4, t4, t6 + vle16.v v\i, (t4) + vse16.v v16, (t4) .endr .ifc \variant, _identity li t1, 2*(5793-4096)*8 @@ -1208,29 +1421,35 @@ function inv_txfm_horz\variant\()_16x8_rvv, export=1, ext=v vsra.vi v16, v16, 1 vaadd.vv v\i, v\i, v16 .endr + j L(horz_16x8_epilog) .else jalr t0, a4 .irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 vssra.vi v\i, v\i, 2 .endr -.endif -.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - vsse16.v v\i, (t5), t6 +L(horz_16x8_epilog): + vsse16.v v0, (t5), t6 +.irp i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 addi t5, t5, 2 + vsse16.v v\i, (t5), t6 .endr jr a7 +.endif endfunc .endm -def_horz_16 def_horz_16 _identity +def_horz_16 function inv_txfm_add_vert_8x16_rvv, export=1, ext=v vsetivli zero, 8, e16, m1, ta, ma -.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - vle16.v v\i, (t4) + + vle16.v v0, (t4) +.irp i, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 add t4, t4, t6 + vle16.v v\i, (t4) .endr + jalr t0, a5 .irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 @@ -1238,10 +1457,13 @@ function inv_txfm_add_vert_8x16_rvv, export=1, ext=v .endr vsetivli zero, 8, e8, mf2, ta, ma - mv t0, t5 -.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 - vle8.v v\i, (t0) + + vle8.v v16, (t5) + add t0, t5, a1 + vle8.v v17, (t0) +.irp i, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 add t0, t0, a1 + vle8.v v\i, (t0) .endr vwaddu.wv v0, v0, v16 @@ -1284,9 +1506,10 @@ function inv_txfm_add_vert_8x16_rvv, export=1, ext=v vnclipu.wi v30, v14, 0 vnclipu.wi v31, v15, 0 -.irp i, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 - vse8.v v\i, (t5) + vse8.v v16, (t5) +.irp i, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 add t5, t5, a1 + vse8.v v\i, (t5) .endr jr a7 @@ -1296,11 +1519,26 @@ function inv_txfm_add_16x16_rvv, export=1, ext=v csrw vxrm, zero vsetivli zero, 8, e16, m1, ta, ma addi sp, sp, -16*32 -.irp i, 0, 8 +.irp i, 8, 0 addi t4, a2, \i*2 addi t5, sp, \i*16*2 +.if \i == 8 + blt a3, a7, 1f +.endif li t6, 16*2 jalr a7, a6 +.if \i == 8 + j 2f +1: + li t1, 64 + vsetvli zero, t1, e16, m8, ta, ma + vmv.v.x v0, zero + vse16.v v0, (t5) + addi t5, t5, 128 + vse16.v v0, (t5) + vsetivli zero, 8, e16, m1, ta, ma +2: +.endif .endr .irp i, 0, 8 addi t4, sp, \i*2 @@ -1312,7 +1550,7 @@ function inv_txfm_add_16x16_rvv, export=1, ext=v ret endfunc -.macro def_fn_16x16 txfm1, txfm2 +.macro def_fn_16x16 txfm1, txfm2, eob_half function inv_txfm_add_\txfm1\()_\txfm2\()_16x16_8bpc_rvv, export=1, ext=v .ifc \txfm1, identity la a6, inv_txfm_horz_identity_16x8_rvv @@ -1321,19 +1559,558 @@ function inv_txfm_add_\txfm1\()_\txfm2\()_16x16_8bpc_rvv, export=1, ext=v la a4, inv_\txfm1\()_e16_x16_rvv .endif la a5, inv_\txfm2\()_e16_x16_rvv + li a7, \eob_half j inv_txfm_add_16x16_rvv endfunc .endm -def_fn_16x16 dct, dct -def_fn_16x16 identity, identity -def_fn_16x16 dct, adst -def_fn_16x16 dct, flipadst -def_fn_16x16 dct, identity -def_fn_16x16 adst, dct -def_fn_16x16 adst, adst -def_fn_16x16 adst, flipadst -def_fn_16x16 flipadst, dct -def_fn_16x16 flipadst, adst -def_fn_16x16 flipadst, flipadst -def_fn_16x16 identity, dct +def_fn_16x16 dct, dct, 36 +def_fn_16x16 identity, identity, 36 +def_fn_16x16 dct, adst, 36 +def_fn_16x16 dct, flipadst, 36 +def_fn_16x16 dct, identity, 8 +def_fn_16x16 adst, dct, 36 +def_fn_16x16 adst, adst, 36 +def_fn_16x16 adst, flipadst, 36 +def_fn_16x16 flipadst, dct, 36 +def_fn_16x16 flipadst, adst, 36 +def_fn_16x16 flipadst, flipadst, 36 +def_fn_16x16 identity, dct, 8 + +.macro def_fn_416_base variant +function inv_txfm_\variant\()add_4x16_rvv, export=1, ext=v + csrw vxrm, zero + + vsetivli zero, 8, e16, m1, ta, ma + + blt a3, a6, 1f + + addi t0, a2, 16 + vle16.v v0, (t0) + addi t0, t0, 32 + vle16.v v1, (t0) + addi t0, t0, 32 + vle16.v v2, (t0) + addi t0, t0, 32 + vle16.v v3, (t0) + +.ifc \variant, identity_ + li t1, (5793-4096)*8 + vsmul.vx v8, v0, t1 + vaadd.vv v4, v0, v8 + vsmul.vx v8, v1, t1 + vaadd.vv v5, v1, v8 + vsmul.vx v8, v2, t1 + vaadd.vv v6, v2, v8 + vsmul.vx v8, v3, t1 + vaadd.vv v7, v3, v8 +.else + jalr t0, a4 + + vssra.vi v4, v0, 1 + vssra.vi v5, v1, 1 + vssra.vi v6, v2, 1 + vssra.vi v7, v3, 1 +.endif + + j 2f + +1: +.irp i, 4, 5, 6, 7 + vmv.v.x v\i, zero +.endr + +2: + vle16.v v0, (a2) + addi t0, a2, 32 + vle16.v v1, (t0) + addi t0, t0, 32 + vle16.v v2, (t0) + addi t0, t0, 32 + vle16.v v3, (t0) + +.ifc \variant, identity_ + li t1, (5793-4096)*8 +.irp i, 0, 1, 2, 3 + vsmul.vx v8, v\i, t1 + vaadd.vv v\i, v\i, v8 +.endr + + j L(itx_4x16_epilog) +.else + jalr t0, a4 + + vssra.vi v0, v0, 1 + vssra.vi v1, v1, 1 + vssra.vi v2, v2, 1 + vssra.vi v3, v3, 1 + +L(itx_4x16_epilog): + vsseg4e16.v v0, (a2) + addi t0, a2, 64 + vsseg4e16.v v4, (t0) + + vsetivli zero, 4, e16, mf2, ta, ma + + vmv.v.x v16, zero + vle16.v v0, (a2) + vse16.v v16, (a2) + addi t0, a2, 8 + vle16.v v1, (t0) + vse16.v v16, (t0) +.irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + addi t0, t0, 8 + vle16.v v\i, (t0) + vse16.v v16, (t0) +.endr + + jalr t0, a5 + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + vssra.vi v\i, v\i, 4 +.endr + + vsetvli zero, zero, e8, mf4, ta, ma + + vle8.v v16, (a0) + add t0, a0, a1 + vle8.v v17, (t0) +.irp i, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 + add t0, t0, a1 + vle8.v v\i, (t0) +.endr + + vwaddu.wv v0, v0, v16 + vwaddu.wv v1, v1, v17 + vwaddu.wv v2, v2, v18 + vwaddu.wv v3, v3, v19 + vwaddu.wv v4, v4, v20 + vwaddu.wv v5, v5, v21 + vwaddu.wv v6, v6, v22 + vwaddu.wv v7, v7, v23 + vwaddu.wv v8, v8, v24 + vwaddu.wv v9, v9, v25 + vwaddu.wv v10, v10, v26 + vwaddu.wv v11, v11, v27 + vwaddu.wv v12, v12, v28 + vwaddu.wv v13, v13, v29 + vwaddu.wv v14, v14, v30 + vwaddu.wv v15, v15, v31 + + vsetvli zero, zero, e16, mf2, ta, ma +.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + vmax.vx v\i, v\i, zero +.endr + + vsetvli zero, zero, e8, mf4, ta, ma + + vnclipu.wi v16, v0, 0 + vnclipu.wi v17, v1, 0 + vnclipu.wi v18, v2, 0 + vnclipu.wi v19, v3, 0 + vnclipu.wi v20, v4, 0 + vnclipu.wi v21, v5, 0 + vnclipu.wi v22, v6, 0 + vnclipu.wi v23, v7, 0 + vnclipu.wi v24, v8, 0 + vnclipu.wi v25, v9, 0 + vnclipu.wi v26, v10, 0 + vnclipu.wi v27, v11, 0 + vnclipu.wi v28, v12, 0 + vnclipu.wi v29, v13, 0 + vnclipu.wi v30, v14, 0 + vnclipu.wi v31, v15, 0 + + vse8.v v16, (a0) +.irp i, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 + add a0, a0, a1 + vse8.v v\i, (a0) +.endr + + ret +.endif +endfunc + +function inv_txfm_\variant\()add_16x4_rvv, export=1, ext=v + csrw vxrm, zero + + vsetivli zero, 4, e16, mf2, ta, ma + vle16.v v0, (a2) + addi t0, a2, 8 + vle16.v v1, (t0) +.irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + addi t0, t0, 8 + vle16.v v\i, (t0) +.endr + +.ifc \variant, identity_ + li t1, 2*(5793-4096)*8 +.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + vsmul.vx v16, v\i, t1 + vssra.vi v16, v16, 1 + vsadd.vv v\i, v\i, v16 +.endr + + j L(itx_16x4_epilog) +.else + jalr t0, a4 + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + vssra.vi v\i, v\i, 1 +.endr + +L(itx_16x4_epilog): + li t0, 32 + vssseg8e16.v v0, (a2), t0 + addi t1, a2, 16 + vssseg8e16.v v8, (t1), t0 + +.irp j, 0, 8 + vsetivli zero, 8, e16, m1, ta, ma + + vmv.v.x v4, zero + addi t0, a2, \j*2 + vle16.v v0, (t0) + vse16.v v4, (t0) +.irp i, 1, 2, 3 + addi t0, t0, 32 + vle16.v v\i, (t0) + vse16.v v4, (t0) +.endr + + jalr t0, a5 + + vssra.vi v0, v0, 4 + vssra.vi v1, v1, 4 + vssra.vi v2, v2, 4 + vssra.vi v3, v3, 4 + + vsetvli zero, zero, e8, mf2, ta, ma + addi t0, a0, \j + vle8.v v4, (t0) + add t0, t0, a1 + vle8.v v5, (t0) + add t0, t0, a1 + vle8.v v6, (t0) + add t0, t0, a1 + vle8.v v7, (t0) + + vwaddu.wv v0, v0, v4 + vwaddu.wv v1, v1, v5 + vwaddu.wv v2, v2, v6 + vwaddu.wv v3, v3, v7 + + vsetvli zero, zero, e16, m1, ta, ma + vmax.vx v0, v0, zero + vmax.vx v1, v1, zero + vmax.vx v2, v2, zero + vmax.vx v3, v3, zero + + vsetvli zero, zero, e8, mf2, ta, ma + + vnclipu.wi v4, v0, 0 + vnclipu.wi v5, v1, 0 + vnclipu.wi v6, v2, 0 + vnclipu.wi v7, v3, 0 + + addi t0, a0, \j + vse8.v v4, (t0) + add t0, t0, a1 + vse8.v v5, (t0) + add t0, t0, a1 + vse8.v v6, (t0) + add t0, t0, a1 + vse8.v v7, (t0) +.endr + + ret +.endif +endfunc +.endm + +def_fn_416_base identity_ +def_fn_416_base + +.macro def_fn_416 w, h, txfm1, txfm2, eob_half +function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_rvv, export=1 +.if \w == 4 && (\txfm1 == adst || \txfm1 == flipadst) + la a4, inv_\txfm1\()_e16_x\w\()w_rvv +.elseif \txfm1 != identity + la a4, inv_\txfm1\()_e16_x\w\()_rvv +.endif +.if \h == 4 && (\txfm2 == adst || \txfm2 == flipadst) + la a5, inv_\txfm2\()_e16_x\h\()w_rvv +.else + la a5, inv_\txfm2\()_e16_x\h\()_rvv +.endif +.if \w == 4 + li a6, \eob_half +.endif +.ifc \txfm1, identity + j inv_txfm_identity_add_\w\()x\h\()_rvv +.else + j inv_txfm_add_\w\()x\h\()_rvv +.endif +endfunc +.endm + +.macro def_fns_416 w, h +def_fn_416 \w, \h, dct, dct, 29 +def_fn_416 \w, \h, identity, identity, 29 +def_fn_416 \w, \h, dct, adst, 29 +def_fn_416 \w, \h, dct, flipadst, 29 +def_fn_416 \w, \h, dct, identity, 8 +def_fn_416 \w, \h, adst, dct, 29 +def_fn_416 \w, \h, adst, adst, 29 +def_fn_416 \w, \h, adst, flipadst, 29 +def_fn_416 \w, \h, flipadst, dct, 29 +def_fn_416 \w, \h, flipadst, adst, 29 +def_fn_416 \w, \h, flipadst, flipadst, 29 +def_fn_416 \w, \h, identity, dct, 32 +def_fn_416 \w, \h, adst, identity, 8 +def_fn_416 \w, \h, flipadst, identity, 8 +def_fn_416 \w, \h, identity, adst, 32 +def_fn_416 \w, \h, identity, flipadst, 32 +.endm + +def_fns_416 4, 16 +def_fns_416 16, 4 + +.macro def_fn_816_base variant +function inv_txfm_\variant\()add_8x16_rvv, export=1, ext=v + csrw vxrm, zero + + vsetivli zero, 8, e16, m1, ta, ma + + blt a3, a6, 1f + + vmv.v.x v16, zero + addi t0, a2, 16 + vle16.v v0, (t0) + vse16.v v16, (t0) +.irp i, 1, 2, 3, 4, 5, 6, 7 + addi t0, t0, 32 + vle16.v v\i, (t0) + vse16.v v16, (t0) +.endr + + li t1, 2896*8 +.ifc \variant, identity_ + vsmul.vx v8, v0, t1 + vsmul.vx v9, v1, t1 + vsmul.vx v10, v2, t1 + vsmul.vx v11, v3, t1 + vsmul.vx v12, v4, t1 + vsmul.vx v13, v5, t1 + vsmul.vx v14, v6, t1 + vsmul.vx v15, v7, t1 +.else +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + vsmul.vx v\i, v\i, t1 +.endr + + jalr t0, a4 + + vssra.vi v8, v0, 1 + vssra.vi v9, v1, 1 + vssra.vi v10, v2, 1 + vssra.vi v11, v3, 1 + vssra.vi v12, v4, 1 + vssra.vi v13, v5, 1 + vssra.vi v14, v6, 1 + vssra.vi v15, v7, 1 +.endif + + j 2f + +1: +.irp i, 8, 9, 10, 11, 12, 13, 14, 15 + vmv.v.x v\i, zero +.endr + +2: + vmv.v.x v16, zero + vle16.v v0, (a2) + vse16.v v16, (a2) + addi t0, a2, 32 + vle16.v v1, (t0) + vse16.v v16, (t0) +.irp i, 2, 3, 4, 5, 6, 7 + addi t0, t0, 32 + vle16.v v\i, (t0) + vse16.v v16, (t0) +.endr + + li t1, 2896*8 +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + vsmul.vx v\i, v\i, t1 +.endr + +.ifc \variant, identity_ + j L(itx_8x16_epilog) +.else + jalr t0, a4 + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + vssra.vi v\i, v\i, 1 +.endr + +L(itx_8x16_epilog): + addi t4, sp, -8*32 + vsseg8e16.v v0, (t4) + addi t0, t4, 8*16 + vsseg8e16.v v8, (t0) + + mv t5, a0 + li t6, 16 + jal a7, inv_txfm_add_vert_8x16_rvv + + ret +.endif +endfunc + +function inv_txfm_\variant\()add_16x8_rvv, export=1, ext=v + csrw vxrm, zero + + vsetivli zero, 8, e16, m1, ta, ma + vle16.v v0, (a2) + addi t0, a2, 16 + vle16.v v1, (t0) +.irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + addi t0, t0, 16 + vle16.v v\i, (t0) +.endr + + li t1, 2896*8 +.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + vsmul.vx v\i, v\i, t1 +.endr + +.ifc \variant, identity_ + li t1, 2*(5793-4096)*8 +.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + vsmul.vx v16, v\i, t1 + vssra.vi v16, v16, 1 + vsadd.vv v\i, v\i, v16 +.endr + + j L(itx_16x8_epilog) +.else + jalr t0, a4 + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + vssra.vi v\i, v\i, 1 +.endr + +L(itx_16x8_epilog): + li t0, 32 + vssseg8e16.v v0, (a2), t0 + addi t1, a2, 16 + vssseg8e16.v v8, (t1), t0 + +.irp j, 0, 8 + vsetivli zero, 8, e16, m1, ta, ma + + vmv.v.x v8, zero + addi t0, a2, \j*2 + vle16.v v0, (t0) + vse16.v v8, (t0) +.irp i, 1, 2, 3, 4, 5, 6, 7 + addi t0, t0, 32 + vle16.v v\i, (t0) + vse16.v v8, (t0) +.endr + + jalr t0, a5 + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + vssra.vi v\i, v\i, 4 +.endr + + vsetvli zero, zero, e8, mf2, ta, ma + addi t0, a0, \j + vle8.v v8, (t0) +.irp i, 9, 10, 11, 12, 13, 14, 15 + add t0, t0, a1 + vle8.v v\i, (t0) +.endr + + vwaddu.wv v0, v0, v8 + vwaddu.wv v1, v1, v9 + vwaddu.wv v2, v2, v10 + vwaddu.wv v3, v3, v11 + vwaddu.wv v4, v4, v12 + vwaddu.wv v5, v5, v13 + vwaddu.wv v6, v6, v14 + vwaddu.wv v7, v7, v15 + + vsetvli zero, zero, e16, m1, ta, ma +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + vmax.vx v\i, v\i, zero +.endr + + vsetvli zero, zero, e8, mf2, ta, ma + + vnclipu.wi v8, v0, 0 + vnclipu.wi v9, v1, 0 + vnclipu.wi v10, v2, 0 + vnclipu.wi v11, v3, 0 + vnclipu.wi v12, v4, 0 + vnclipu.wi v13, v5, 0 + vnclipu.wi v14, v6, 0 + vnclipu.wi v15, v7, 0 + + addi t0, a0, \j + vse8.v v8, (t0) +.irp i, 9, 10, 11, 12, 13, 14, 15 + add t0, t0, a1 + vse8.v v\i, (t0) +.endr +.endr + + ret +.endif +endfunc +.endm + +def_fn_816_base identity_ +def_fn_816_base + +.macro def_fn_816 w, h, txfm1, txfm2, eob_half +function inv_txfm_add_\txfm1\()_\txfm2\()_\w\()x\h\()_8bpc_rvv, export=1 +.ifnc \txfm1, identity + la a4, inv_\txfm1\()_e16_x\w\()_rvv +.endif + la a5, inv_\txfm2\()_e16_x\h\()_rvv +.if \w == 8 + li a6, \eob_half +.endif +.ifc \txfm1, identity + j inv_txfm_identity_add_\w\()x\h\()_rvv +.else + j inv_txfm_add_\w\()x\h\()_rvv +.endif +endfunc +.endm + +.macro def_fns_816 w, h +def_fn_816 \w, \h, dct, dct, 43 +def_fn_816 \w, \h, identity, identity, 43 +def_fn_816 \w, \h, dct, adst, 43 +def_fn_816 \w, \h, dct, flipadst, 43 +def_fn_816 \w, \h, dct, identity, 8 +def_fn_816 \w, \h, adst, dct, 43 +def_fn_816 \w, \h, adst, adst, 43 +def_fn_816 \w, \h, adst, flipadst, 43 +def_fn_816 \w, \h, flipadst, dct, 43 +def_fn_816 \w, \h, flipadst, adst, 43 +def_fn_816 \w, \h, flipadst, flipadst, 43 +def_fn_816 \w, \h, identity, dct, 64 +def_fn_816 \w, \h, adst, identity, 8 +def_fn_816 \w, \h, flipadst, identity, 8 +def_fn_816 \w, \h, identity, adst, 64 +def_fn_816 \w, \h, identity, flipadst, 64 +.endm + +def_fns_816 8, 16 +def_fns_816 16, 8 diff --git a/third_party/dav1d/src/riscv/asm.S b/third_party/dav1d/src/riscv/asm.S index 2435170acb..eed4d67bf5 100644 --- a/third_party/dav1d/src/riscv/asm.S +++ b/third_party/dav1d/src/riscv/asm.S @@ -123,4 +123,6 @@ EXTERN\name: end_thread_local .endm +#define L(x) .L ## x + #endif /* DAV1D_SRC_RISCV_ASM_S */ diff --git a/third_party/dav1d/src/riscv/itx.h b/third_party/dav1d/src/riscv/itx.h index 28c5e54d42..d3f9a03a03 100644 --- a/third_party/dav1d/src/riscv/itx.h +++ b/third_party/dav1d/src/riscv/itx.h @@ -58,7 +58,13 @@ decl_itx_fn(BF(dav1d_inv_txfm_add_wht_wht_##w##x##h, opt)) #define decl_itx_fns(ext) \ decl_itx17_fns( 4, 4, ext); \ +decl_itx16_fns( 4, 8, ext); \ +decl_itx16_fns( 4, 16, ext); \ +decl_itx16_fns( 8, 4, ext); \ decl_itx16_fns( 8, 8, ext); \ +decl_itx16_fns( 8, 16, ext); \ +decl_itx16_fns(16, 4, ext); \ +decl_itx16_fns(16, 8, ext); \ decl_itx16_fns(16, 16, ext) decl_itx_fns(rvv); @@ -105,7 +111,13 @@ static ALWAYS_INLINE void itx_dsp_init_riscv(Dav1dInvTxfmDSPContext *const c, in #if BITDEPTH == 8 assign_itx17_fn( , 4, 4, rvv); + assign_itx16_fn(R, 4, 8, rvv); + assign_itx16_fn(R, 4, 16, rvv); + assign_itx16_fn(R, 8, 4, rvv); assign_itx16_fn( , 8, 8, rvv); + assign_itx16_fn(R, 8, 16, rvv); + assign_itx16_fn(R, 16, 4, rvv); + assign_itx16_fn(R, 16, 8, rvv); assign_itx12_fn( , 16, 16, rvv); #endif } diff --git a/third_party/dav1d/src/x86/cdef_avx2.asm b/third_party/dav1d/src/x86/cdef_avx2.asm index 1f30f8a3b7..95d35fc1c8 100644 --- a/third_party/dav1d/src/x86/cdef_avx2.asm +++ b/third_party/dav1d/src/x86/cdef_avx2.asm @@ -398,7 +398,6 @@ SECTION .text INIT_YMM avx2 cglobal cdef_filter_%1x%2_8bpc, 5, 11, 0, dst, stride, left, top, bot, \ pri, sec, dir, damping, edge -%assign stack_offset_entry stack_offset mov edged, edgem cmp edged, 0xf jne .border_block @@ -1195,9 +1194,9 @@ cglobal cdef_filter_%1x%2_8bpc, 5, 11, 0, dst, stride, left, top, bot, \ .border_block: DEFINE_ARGS dst, stride, left, top, bot, pri, sec, stride3, dst4, edge -%define rstk rsp -%assign stack_offset stack_offset_entry -%assign regs_used 11 + RESET_STACK_STATE + %assign stack_offset stack_offset - (regs_used - 11) * gprsize + %assign regs_used 11 ALLOC_STACK 2*16+(%2+4)*32, 16 %define px rsp+2*16+2*32 diff --git a/third_party/dav1d/src/x86/filmgrain16_avx2.asm b/third_party/dav1d/src/x86/filmgrain16_avx2.asm index a1d4c41f27..eda6035923 100644 --- a/third_party/dav1d/src/x86/filmgrain16_avx2.asm +++ b/third_party/dav1d/src/x86/filmgrain16_avx2.asm @@ -646,18 +646,9 @@ INIT_XMM avx2 INIT_YMM avx2 .ar2: %if WIN64 - ; xmm6 and xmm7 already saved - %assign xmm_regs_used 13 + %2 %assign stack_size_padded 136 SUB rsp, stack_size_padded - movaps [rsp+16*2], xmm8 - movaps [rsp+16*3], xmm9 - movaps [rsp+16*4], xmm10 - movaps [rsp+16*5], xmm11 - movaps [rsp+16*6], xmm12 -%if %2 - movaps [rsp+16*7], xmm13 -%endif + WIN64_PUSH_XMM 13 + %2, 8 %endif DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift mov shiftd, [fg_dataq+FGData.ar_coeff_shift] @@ -747,20 +738,10 @@ INIT_YMM avx2 .ar3: %if WIN64 - ; xmm6 and xmm7 already saved %assign stack_offset 32 - %assign xmm_regs_used 14 + %2 %assign stack_size_padded 152 SUB rsp, stack_size_padded - movaps [rsp+16*2], xmm8 - movaps [rsp+16*3], xmm9 - movaps [rsp+16*4], xmm10 - movaps [rsp+16*5], xmm11 - movaps [rsp+16*6], xmm12 - movaps [rsp+16*7], xmm13 -%if %2 - movaps [rsp+16*8], xmm14 -%endif + WIN64_PUSH_XMM 14 + %2, 8 %endif DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift mov shiftd, [fg_dataq+FGData.ar_coeff_shift] diff --git a/third_party/dav1d/src/x86/filmgrain16_sse.asm b/third_party/dav1d/src/x86/filmgrain16_sse.asm index 6b0daaac0b..25d01caa19 100644 --- a/third_party/dav1d/src/x86/filmgrain16_sse.asm +++ b/third_party/dav1d/src/x86/filmgrain16_sse.asm @@ -275,7 +275,6 @@ cglobal generate_grain_y_16bpc, 3, 6, 8, buf, fg_data, bdmax .ar2: %if ARCH_X86_32 -%assign stack_offset_old stack_offset ALLOC_STACK -16*8 %endif DEFINE_ARGS buf, fg_data, bdmax, shift @@ -428,7 +427,6 @@ cglobal generate_grain_y_16bpc, 3, 6, 8, buf, fg_data, bdmax %elif ARCH_X86_64 %define tmp rsp+stack_offset-72 %else -%assign stack_offset stack_offset_old ALLOC_STACK -16*12 %define tmp rsp mov bdmaxd, bdmaxm @@ -715,7 +713,6 @@ cglobal generate_grain_uv_%1_16bpc, 1, 7, 8, buf, x, pic_reg, fg_data, h DEFINE_ARGS buf, bufy, fg_data, uv, bdmax, shift %else DEFINE_ARGS buf, bufy, pic_reg, fg_data, uv, shift -%assign stack_offset_old stack_offset ALLOC_STACK -16*2 mov bufyq, r1m mov uvd, r3m @@ -831,9 +828,7 @@ cglobal generate_grain_uv_%1_16bpc, 1, 7, 8, buf, x, pic_reg, fg_data, h %if ARCH_X86_64 DEFINE_ARGS buf, bufy, fg_data, uv, max, cf3, min, val3, x %else -%assign stack_offset stack_offset_old -%xdefine rstk rsp -%assign stack_size_padded 0 + RESET_STACK_STATE DEFINE_ARGS buf, shift, pic_reg, fg_data, uv, bufy, cf3 mov bufyq, r1m mov uvd, r3m @@ -1159,7 +1154,6 @@ cglobal generate_grain_uv_%1_16bpc, 1, 7, 8, buf, x, pic_reg, fg_data, h %endif %else DEFINE_ARGS buf, bufy, pic_reg, fg_data, uv, shift -%assign stack_offset stack_offset_old ALLOC_STACK -16*14 mov bufyq, r1m mov uvd, r3m diff --git a/third_party/dav1d/src/x86/filmgrain_avx2.asm b/third_party/dav1d/src/x86/filmgrain_avx2.asm index 55445cf593..91d8ca5c14 100644 --- a/third_party/dav1d/src/x86/filmgrain_avx2.asm +++ b/third_party/dav1d/src/x86/filmgrain_avx2.asm @@ -204,18 +204,9 @@ cglobal generate_grain_y_8bpc, 2, 9, 8, buf, fg_data .ar2: %if WIN64 - ; xmm6 and xmm7 already saved - %assign xmm_regs_used 16 %assign stack_size_padded 168 SUB rsp, stack_size_padded - movaps [rsp+16*2], xmm8 - movaps [rsp+16*3], xmm9 - movaps [rsp+16*4], xmm10 - movaps [rsp+16*5], xmm11 - movaps [rsp+16*6], xmm12 - movaps [rsp+16*7], xmm13 - movaps [rsp+16*8], xmm14 - movaps [rsp+16*9], xmm15 + WIN64_PUSH_XMM 16, 8 %endif DEFINE_ARGS buf, fg_data, h, x mov r6d, [fg_dataq+FGData.ar_coeff_shift] @@ -287,15 +278,9 @@ cglobal generate_grain_y_8bpc, 2, 9, 8, buf, fg_data INIT_YMM avx2 .ar3: %if WIN64 - ; xmm6 and xmm7 already saved - %assign stack_offset 16 ALLOC_STACK 16*14 %assign stack_size stack_size - 16*4 - %assign xmm_regs_used 12 - movaps [rsp+16*12], xmm8 - movaps [rsp+16*13], xmm9 - movaps [rsp+16*14], xmm10 - movaps [rsp+16*15], xmm11 + WIN64_PUSH_XMM 12, 8 %else ALLOC_STACK 16*12 %endif diff --git a/third_party/dav1d/src/x86/filmgrain_sse.asm b/third_party/dav1d/src/x86/filmgrain_sse.asm index 0172f98760..d06e349a8c 100644 --- a/third_party/dav1d/src/x86/filmgrain_sse.asm +++ b/third_party/dav1d/src/x86/filmgrain_sse.asm @@ -232,7 +232,6 @@ cglobal generate_grain_y_8bpc, 2, 7 + 2 * ARCH_X86_64, 16, buf, fg_data .ar2: %if ARCH_X86_32 -%assign stack_offset_old stack_offset ALLOC_STACK -16*8 %endif DEFINE_ARGS buf, fg_data, shift @@ -333,7 +332,6 @@ cglobal generate_grain_y_8bpc, 2, 7 + 2 * ARCH_X86_64, 16, buf, fg_data .ar3: DEFINE_ARGS buf, fg_data, shift %if ARCH_X86_32 -%assign stack_offset stack_offset_old ALLOC_STACK -16*14 %elif WIN64 SUB rsp, 16*6 @@ -601,7 +599,6 @@ cglobal generate_grain_uv_%1_8bpc, 1, 7 + 3 * ARCH_X86_64, 16, buf, bufy, fg_dat DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift movifnidn bufyq, bufymp %if ARCH_X86_32 -%assign stack_offset_old stack_offset ALLOC_STACK -2*16 %endif imul uvd, 28 @@ -738,9 +735,7 @@ cglobal generate_grain_uv_%1_8bpc, 1, 7 + 3 * ARCH_X86_64, 16, buf, bufy, fg_dat .ar1: %if ARCH_X86_32 -%assign stack_offset stack_offset_old -%assign stack_size_padded 0 -%xdefine rstk rsp + RESET_STACK_STATE %endif DEFINE_ARGS buf, bufy, fg_data, uv, val3, cf3, min, max, x imul uvd, 28 @@ -881,9 +876,6 @@ cglobal generate_grain_uv_%1_8bpc, 1, 7 + 3 * ARCH_X86_64, 16, buf, bufy, fg_dat .ar2: %if ARCH_X86_32 -%assign stack_offset stack_offset_old -%assign stack_size_padded 0 -%xdefine rstk rsp ALLOC_STACK -8*16 %endif DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift @@ -1014,9 +1006,7 @@ cglobal generate_grain_uv_%1_8bpc, 1, 7 + 3 * ARCH_X86_64, 16, buf, bufy, fg_dat .ar3: %if ARCH_X86_32 -%assign stack_offset stack_offset_old -%assign stack_size_padded 0 -%xdefine rstk rsp + RESET_STACK_STATE %endif DEFINE_ARGS buf, bufy, fg_data, uv, unused, shift movifnidn bufyq, bufymp diff --git a/third_party/dav1d/src/x86/ipred16_avx2.asm b/third_party/dav1d/src/x86/ipred16_avx2.asm index f4931e977b..7b52abaa10 100644 --- a/third_party/dav1d/src/x86/ipred16_avx2.asm +++ b/third_party/dav1d/src/x86/ipred16_avx2.asm @@ -946,7 +946,6 @@ cglobal ipred_smooth_16bpc, 3, 7, 6, dst, stride, tl, w, h, v_weights jg .w4_loop RET .w8: -%assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 12 vpbroadcastw m0, [tlq] ; bottom vbroadcasti128 m7, [tlq+hq*2+2] @@ -974,7 +973,6 @@ cglobal ipred_smooth_16bpc, 3, 7, 6, dst, stride, tl, w, h, v_weights jg .w8_loop RET .w16: -%assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 11 vpbroadcastw m0, [tlq] ; bottom movu m7, [tlq+hq*2+2] @@ -1005,7 +1003,6 @@ cglobal ipred_smooth_16bpc, 3, 7, 6, dst, stride, tl, w, h, v_weights jg .w16_loop RET .w32: -%assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 15 vpbroadcastw m0, [tlq] ; bottom movu m7, [tlq+hq*2+ 2] @@ -1047,7 +1044,6 @@ cglobal ipred_smooth_16bpc, 3, 7, 6, dst, stride, tl, w, h, v_weights jg .w32_loop RET .w64: -%assign stack_offset stack_offset - stack_size_padded PROLOGUE 0, 11, 16, dst, stride, tl, tl_base, h, v_weights, dummy, v_weights_base, x, y, dst_base mov dst_baseq, dstq mov tl_baseq, tlq @@ -1104,7 +1100,6 @@ cglobal ipred_smooth_16bpc, 3, 7, 6, dst, stride, tl, w, h, v_weights RET cglobal ipred_z1_16bpc, 3, 8, 0, dst, stride, tl, w, h, angle, dx, maxbase - %assign org_stack_offset stack_offset lea r6, [ipred_z1_16bpc_avx2_table] tzcnt wd, wm movifnidn angled, anglem @@ -1312,7 +1307,6 @@ ALIGN function_align .w4_end: RET .w8: - %assign stack_offset org_stack_offset ALLOC_STACK -64, 7 lea r3d, [angleq+216] mov r3b, hb @@ -1476,7 +1470,6 @@ ALIGN function_align or maxbased, 16 ; imin(h+15, 31) jmp .w16_main .w16: - %assign stack_offset org_stack_offset ALLOC_STACK -96, 7 lea maxbased, [hq+15] test angled, 0x400 @@ -1622,7 +1615,6 @@ ALIGN function_align .w16_end: RET .w32: - %assign stack_offset org_stack_offset ALLOC_STACK -160, 8 lea maxbased, [hq+31] mov r3d, 63 @@ -1737,7 +1729,6 @@ ALIGN function_align .w32_end: RET .w64: - %assign stack_offset org_stack_offset ALLOC_STACK -256, 10 lea maxbased, [hq+63] test angled, 0x400 @@ -2691,7 +2682,6 @@ ALIGN function_align jmp .w32_filter_above cglobal ipred_z3_16bpc, 4, 9, 0, dst, stride, tl, w, h, angle, dy, org_w, maxbase - %assign org_stack_offset stack_offset lea r6, [ipred_z3_16bpc_avx2_table] tzcnt hd, hm movifnidn angled, anglem @@ -2907,7 +2897,6 @@ ALIGN function_align RET .h8: lea r4d, [angleq+216] - %assign stack_offset org_stack_offset ALLOC_STACK -64, 8 mov r4b, wb lea r7, [strideq*3] @@ -3155,7 +3144,6 @@ ALIGN function_align jmp .h16_main ALIGN function_align .h16: - %assign stack_offset org_stack_offset ALLOC_STACK -96, 10 lea maxbased, [wq+15] lea r7, [strideq*3] @@ -3372,7 +3360,6 @@ ALIGN function_align .h16_end: RET .h32: - %assign stack_offset org_stack_offset ALLOC_STACK -160, 9 lea maxbased, [wq+31] and maxbased, 31 @@ -3557,7 +3544,6 @@ ALIGN function_align .h32_end: RET .h64: - %assign stack_offset org_stack_offset ALLOC_STACK -256, 10 lea maxbased, [wq+63] test angled, 0x400 @@ -3804,7 +3790,6 @@ ALIGN function_align ; 5 8 8 i cglobal ipred_filter_16bpc, 3, 9, 0, dst, stride, tl, w, h, filter -%assign org_stack_offset stack_offset %define base r6-ipred_filter_16bpc_avx2_table lea r6, [filter_intra_taps] tzcnt wd, wm @@ -3846,7 +3831,6 @@ cglobal ipred_filter_16bpc, 3, 9, 0, dst, stride, tl, w, h, filter RET ALIGN function_align .w8: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 16 vbroadcasti128 m14, [base+filter_shuf3] vpbroadcastw m15, r8m ; bitdepth_max @@ -3883,7 +3867,6 @@ ALIGN function_align RET ALIGN function_align .w16: - %assign stack_offset stack_offset - stack_size_padded ALLOC_STACK 32, 16 vpbroadcastw m15, r8m ; bitdepth_max sub hd, 2 @@ -3977,7 +3960,6 @@ ALIGN function_align ret ALIGN function_align .w32: - %assign stack_offset org_stack_offset ALLOC_STACK 64, 16 vpbroadcastw m15, r8m ; bitdepth_max sub hd, 2 diff --git a/third_party/dav1d/src/x86/ipred_avx2.asm b/third_party/dav1d/src/x86/ipred_avx2.asm index 58e40935ac..35738e7c0b 100644 --- a/third_party/dav1d/src/x86/ipred_avx2.asm +++ b/third_party/dav1d/src/x86/ipred_avx2.asm @@ -772,7 +772,6 @@ ALIGN function_align RET ALIGN function_align .w32: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 6 movu m3, [tlq+1] punpcklbw m2, m3, m5 @@ -823,29 +822,17 @@ ALIGN function_align jl .w64_loop RET -%macro SETUP_STACK_FRAME 3 ; stack_size, regs_used, xmm_regs_used - %assign stack_offset 0 - %assign stack_size_padded 0 - %assign regs_used %2 - %xdefine rstk rsp - SETUP_STACK_POINTER %1 - %if regs_used != %2 && WIN64 - PUSH r%2 - %endif - ALLOC_STACK %1, %3 -%endmacro - cglobal ipred_smooth_h_8bpc, 3, 7, 0, dst, stride, tl, w, h -%define base r6-ipred_smooth_h_avx2_table - lea r6, [ipred_smooth_h_avx2_table] +%define base r5-ipred_smooth_h_avx2_table + lea r5, [ipred_smooth_h_avx2_table] mov wd, wm vpbroadcastb m3, [tlq+wq] ; right tzcnt wd, wd mov hd, hm - movsxd wq, [r6+wq*4] + movsxd wq, [r5+wq*4] vpbroadcastd m4, [base+pb_127_m127] vpbroadcastd m5, [base+pw_128] - add wq, r6 + add wq, r5 jmp wq .w4: WIN64_SPILL_XMM 8 @@ -891,7 +878,6 @@ cglobal ipred_smooth_h_8bpc, 3, 7, 0, dst, stride, tl, w, h RET ALIGN function_align .w8: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 8 vbroadcasti128 m6, [base+smooth_weights+8*2] mova m7, [base+ipred_h_shuf] @@ -927,7 +913,7 @@ ALIGN function_align RET ALIGN function_align .w16: - SETUP_STACK_FRAME 32*4, 7, 8 + ALLOC_STACK 32*4, 8 lea r3, [rsp+64*2-4] call .prep ; only worthwhile for for w16 and above sub tlq, 2 @@ -951,7 +937,7 @@ ALIGN function_align RET ALIGN function_align .w32: - SETUP_STACK_FRAME 32*4, 7, 6 + ALLOC_STACK 32*4 lea r3, [rsp+64*2-2] call .prep dec tlq @@ -971,19 +957,19 @@ ALIGN function_align RET ALIGN function_align .w64: - SETUP_STACK_FRAME 32*4, 7, 9 + ALLOC_STACK 32*4, 9 lea r3, [rsp+64*2-2] call .prep - add r6, smooth_weights+16*15-ipred_smooth_h_avx2_table + add r5, smooth_weights+16*15-ipred_smooth_h_avx2_table dec tlq - mova xm5, [r6-16*7] - vinserti128 m5, [r6-16*5], 1 - mova xm6, [r6-16*6] - vinserti128 m6, [r6-16*4], 1 - mova xm7, [r6-16*3] - vinserti128 m7, [r6-16*1], 1 - mova xm8, [r6-16*2] - vinserti128 m8, [r6-16*0], 1 + mova xm5, [r5-16*7] + vinserti128 m5, [r5-16*5], 1 + mova xm6, [r5-16*6] + vinserti128 m6, [r5-16*4], 1 + mova xm7, [r5-16*3] + vinserti128 m7, [r5-16*1], 1 + mova xm8, [r5-16*2] + vinserti128 m8, [r5-16*0], 1 .w64_loop: vpbroadcastb m2, [tlq+hq] punpcklbw m2, m3 @@ -1113,7 +1099,6 @@ cglobal ipred_smooth_8bpc, 3, 7, 0, dst, stride, tl, w, h, v_weights RET ALIGN function_align .w8: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 12 mova m10, [base+ipred_h_shuf] vbroadcasti128 m11, [base+smooth_weights+8*2] @@ -1157,7 +1142,9 @@ ALIGN function_align RET ALIGN function_align .w16: - SETUP_STACK_FRAME 32*4, 7, 14 + %assign regs_used 4 + ALLOC_STACK -32*4, 14 + %assign regs_used 7 vbroadcasti128 m11, [tlq+1] lea r3, [rsp+64*2-4] punpcklbw m10, m11, m0 ; top, bottom @@ -1197,7 +1184,9 @@ ALIGN function_align RET ALIGN function_align .w32: - SETUP_STACK_FRAME 32*4, 7, 11 + %assign regs_used 4 + ALLOC_STACK -32*4, 11 + %assign regs_used 7 movu m8, [tlq+1] lea r3, [rsp+64*2-2] punpcklbw m7, m8, m0 @@ -1232,7 +1221,9 @@ ALIGN function_align RET ALIGN function_align .w64: - SETUP_STACK_FRAME 32*8, 7, 16 + %assign regs_used 4 + ALLOC_STACK -32*8, 16 + %assign regs_used 7 movu m13, [tlq+1 ] movu m15, [tlq+33] add r6, smooth_weights+16*15-ipred_smooth_avx2_table @@ -1316,7 +1307,6 @@ ALIGN function_align ret cglobal ipred_z1_8bpc, 3, 8, 0, dst, stride, tl, w, h, angle, dx, maxbase - %assign org_stack_offset stack_offset lea r6, [ipred_z1_avx2_table] tzcnt wd, wm movifnidn angled, anglem @@ -1415,7 +1405,6 @@ ALIGN function_align pmovmskb r5d, m1 ret .w4_no_upsample: - %assign stack_offset org_stack_offset ALLOC_STACK -16, 11 mov maxbased, 7 test angled, 0x400 ; !enable_intra_edge_filter @@ -1522,7 +1511,6 @@ ALIGN function_align mov r3b, hb cmp r3d, 8 ja .w8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || h > 8 - %assign stack_offset org_stack_offset ALLOC_STACK -32, 8 movu xm2, [z_filter_s+6] mova xm0, [tlq-1] @@ -1592,7 +1580,6 @@ ALIGN function_align or maxbased, 8 ; imin(h+7, 15) jmp .w8_main .w8_no_upsample: - %assign stack_offset org_stack_offset ALLOC_STACK -32, 10 lea maxbased, [hq+7] test angled, 0x400 @@ -1696,7 +1683,6 @@ ALIGN function_align jmp .w16_main ALIGN function_align .w16: - %assign stack_offset org_stack_offset ALLOC_STACK -64, 12 lea maxbased, [hq+15] test angled, 0x400 @@ -1816,7 +1802,6 @@ ALIGN function_align RET ALIGN function_align .w32: - %assign stack_offset org_stack_offset ALLOC_STACK -96, 15 lea r3d, [hq+31] mov maxbased, 63 @@ -1960,7 +1945,6 @@ ALIGN function_align RET ALIGN function_align .w64: - %assign stack_offset org_stack_offset ALLOC_STACK -128, 16 lea maxbased, [hq+63] test angled, 0x400 ; !enable_intra_edge_filter @@ -3001,7 +2985,6 @@ ALIGN function_align jmp .w32_filter_above cglobal ipred_z3_8bpc, 4, 9, 0, dst, stride, tl, w, h, angle, dy, org_w, maxbase - %assign org_stack_offset stack_offset lea r6, [ipred_z3_avx2_table] tzcnt hd, hm movifnidn angled, anglem @@ -3102,7 +3085,6 @@ ALIGN function_align pmovmskb r5d, m1 ret .h4_no_upsample: - %assign stack_offset org_stack_offset ALLOC_STACK -16, 12 mov maxbased, 7 test angled, 0x400 ; !enable_intra_edge_filter @@ -3215,7 +3197,6 @@ ALIGN function_align mov r4b, wb cmp r4d, 8 ja .h8_no_upsample ; !enable_intra_edge_filter || is_sm || d >= 40 || w > 8 - %assign stack_offset org_stack_offset ALLOC_STACK -32, 8 and r4d, 4 mova xm0, [tlq-15] @@ -3297,7 +3278,6 @@ ALIGN function_align or maxbased, 8 ; imin(w+7, 15) jmp .h8_main .h8_no_upsample: - %assign stack_offset org_stack_offset ALLOC_STACK -32, 10 lea maxbased, [wq+7] test angled, 0x400 @@ -3455,7 +3435,6 @@ ALIGN function_align jmp .h16_main ALIGN function_align .h16: - %assign stack_offset org_stack_offset ALLOC_STACK -64, 12 lea maxbased, [wq+15] test angled, 0x400 @@ -3661,7 +3640,6 @@ ALIGN function_align RET ALIGN function_align .h32: - %assign stack_offset org_stack_offset ALLOC_STACK -96, 15 lea maxbased, [wq+31] and maxbased, 31 @@ -3890,7 +3868,6 @@ ALIGN function_align RET ALIGN function_align .h64: - %assign stack_offset org_stack_offset ALLOC_STACK -128, 16 lea maxbased, [wq+63] test angled, 0x400 ; !enable_intra_edge_filter @@ -4221,6 +4198,7 @@ cglobal ipred_filter_8bpc, 3, 7, 0, dst, stride, tl, w, h, filter movzx filterd, byte filterm %endif shl filterd, 6 + WIN64_SPILL_XMM 9, 15 add filterq, r6 lea r6, [ipred_filter_avx2_table] movq xm0, [tlq-3] ; _ 6 5 0 1 2 3 4 @@ -4234,7 +4212,6 @@ cglobal ipred_filter_8bpc, 3, 7, 0, dst, stride, tl, w, h, filter mov hd, hm jmp wq .w4: - WIN64_SPILL_XMM 9 mova xm8, [base+filter_shuf2] sub tlq, 3 sub tlq, hq @@ -4251,8 +4228,7 @@ cglobal ipred_filter_8bpc, 3, 7, 0, dst, stride, tl, w, h, filter RET ALIGN function_align .w8: - %assign stack_offset stack_offset - stack_size_padded - WIN64_SPILL_XMM 10 + WIN64_PUSH_XMM 10 mova m8, [base+filter_shuf1] FILTER_XMM 7, 0, 6, [base+filter_shuf2] vpbroadcastd m0, [tlq+4] @@ -4278,26 +4254,18 @@ ALIGN function_align RET ALIGN function_align .w16: -%if WIN64 - %assign stack_offset stack_offset - stack_size_padded - %assign xmm_regs_used 15 - %assign stack_size_padded 0x98 - SUB rsp, stack_size_padded -%endif sub hd, 2 - TAIL_CALL .w16_main, 0 -.w16_main: + call .w16_main %if WIN64 - movaps [rsp+0xa8], xmm6 - movaps [rsp+0xb8], xmm7 - movaps [rsp+0x28], xmm8 - movaps [rsp+0x38], xmm9 - movaps [rsp+0x48], xmm10 - movaps [rsp+0x58], xmm11 - movaps [rsp+0x68], xmm12 - movaps [rsp+0x78], xmm13 - movaps [rsp+0x88], xmm14 + jmp .end +%else + RET %endif +.w16_main: + ; The spills are into the callers stack frame + %assign stack_size stack_size + gprsize + WIN64_PUSH_XMM 15, 9 + %assign stack_size stack_size - gprsize FILTER_XMM 12, 0, 7, [base+filter_shuf2] vpbroadcastd m0, [tlq+5] vpblendd m0, [tlq-12], 0x14 @@ -4350,7 +4318,6 @@ ALIGN function_align ret ALIGN function_align .w32: - sub rsp, stack_size_padded sub hd, 2 lea r3, [dstq+16] lea r5d, [hq-2] @@ -4415,6 +4382,7 @@ ALIGN function_align shufps xm6, xm12, xm6, q3131 ; d0 d1 d2 d3 mova [dstq+strideq*0], xm0 mova [dstq+strideq*1], xm6 +.end: RET ALIGN function_align .main: diff --git a/third_party/dav1d/src/x86/ipred_sse.asm b/third_party/dav1d/src/x86/ipred_sse.asm index 976f33a24b..f6b0cad001 100644 --- a/third_party/dav1d/src/x86/ipred_sse.asm +++ b/third_party/dav1d/src/x86/ipred_sse.asm @@ -670,10 +670,7 @@ ALIGN function_align RET ALIGN function_align .w32: -%if WIN64 - movaps [rsp+24], xmm7 - %define xmm_regs_used 8 -%endif + WIN64_PUSH_XMM 8, 7 mova m7, m5 .w32_loop_init: mov r3d, 2 @@ -705,10 +702,7 @@ ALIGN function_align RET ALIGN function_align .w64: -%if WIN64 - movaps [rsp+24], xmm7 - %define xmm_regs_used 8 -%endif + WIN64_PUSH_XMM 8, 7 mova m7, m5 .w64_loop_init: mov r3d, 4 diff --git a/third_party/dav1d/src/x86/looprestoration_sse.asm b/third_party/dav1d/src/x86/looprestoration_sse.asm index 01eb6fa348..b5c73a51d4 100644 --- a/third_party/dav1d/src/x86/looprestoration_sse.asm +++ b/third_party/dav1d/src/x86/looprestoration_sse.asm @@ -42,7 +42,6 @@ pb_0to15: db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 pb_right_ext_mask: times 24 db 0xff times 8 db 0 pb_1: times 16 db 1 -pb_3: times 16 db 3 pw_256: times 8 dw 256 pw_2056: times 8 dw 2056 pw_m16380: times 8 dw -16380 @@ -290,7 +289,7 @@ cglobal wiener_filter7_8bpc, 0, 7, 8, -384*12-stk_off, _, x, left, lpf, tmpstrid call mangle(private_prefix %+ _wiener_filter7_8bpc_ssse3).v jmp .v1 .extend_right: - movd m2, [lpfq-4] + movd m2, [lpfq-1] %if ARCH_X86_64 push r0 lea r0, [pb_right_ext_mask+21] @@ -302,10 +301,11 @@ cglobal wiener_filter7_8bpc, 0, 7, 8, -384*12-stk_off, _, x, left, lpf, tmpstrid movu m1, [r6+xq+8] %endif %if cpuflag(ssse3) - pshufb m2, [base+pb_3] + pxor m3, m3 + pshufb m2, m3 %else punpcklbw m2, m2 - pshuflw m2, m2, q3333 + pshuflw m2, m2, q0000 punpcklqdq m2, m2 %endif pand m4, m0 diff --git a/third_party/dav1d/src/x86/mc16_avx2.asm b/third_party/dav1d/src/x86/mc16_avx2.asm index 61eeaa1007..42e2a5525e 100644 --- a/third_party/dav1d/src/x86/mc16_avx2.asm +++ b/third_party/dav1d/src/x86/mc16_avx2.asm @@ -1337,7 +1337,6 @@ cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my cmp wd, 4 je .h_w4 jl .h_w2 - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 13 shr mxd, 16 sub srcq, 6 @@ -1415,7 +1414,6 @@ cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my cmp hd, 4 cmovle myd, mxd vpbroadcastq m0, [base+subpel_filters+myq*8] - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 15 vpbroadcastd m6, [pd_32] vpbroadcastw m7, r8m @@ -1590,7 +1588,6 @@ cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my jg .v_w8_loop0 RET .hv: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 16 vpbroadcastw m15, r8m cmp wd, 4 @@ -2046,7 +2043,6 @@ cglobal prep_8tap_16bpc, 4, 8, 0, tmp, src, stride, w, h, mx, my shr mxd, 16 sub srcq, 6 vpbroadcastq m0, [base+subpel_filters+mxq*8] - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 12 vbroadcasti128 m6, [subpel_h_shufA] vbroadcasti128 m7, [subpel_h_shufB] @@ -2125,7 +2121,6 @@ cglobal prep_8tap_16bpc, 4, 8, 0, tmp, src, stride, w, h, mx, my cmp hd, 4 cmovle myd, mxd vpbroadcastq m0, [base+subpel_filters+myq*8] - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 15 vpbroadcastd m7, [prep_8tap_1d_rnd] lea r6, [strideq*3] @@ -2264,7 +2259,6 @@ cglobal prep_8tap_16bpc, 4, 8, 0, tmp, src, stride, w, h, mx, my %endif RET .hv: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 16 vpbroadcastd m15, [prep_8tap_2d_rnd] cmp wd, 4 diff --git a/third_party/dav1d/src/x86/mc16_avx512.asm b/third_party/dav1d/src/x86/mc16_avx512.asm index 585ba53e08..e5de7ecd96 100644 --- a/third_party/dav1d/src/x86/mc16_avx512.asm +++ b/third_party/dav1d/src/x86/mc16_avx512.asm @@ -2377,7 +2377,6 @@ cglobal put_8tap_16bpc, 4, 9, 16, dst, ds, src, ss, w, h, mx, my jg .hv_w16_loop RET .hv_w32: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 32 vbroadcasti32x4 m20, [spel_h_shufA] vbroadcasti32x4 m21, [spel_h_shufB] @@ -3175,7 +3174,6 @@ cglobal prep_8tap_16bpc, 3, 8, 16, tmp, src, stride, w, h, mx, my, stride3 jg .hv_w8_loop RET .hv_w16: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 27 vbroadcasti32x8 m5, [srcq+strideq*0+ 8] vinserti32x8 m4, m5, [srcq+strideq*0+ 0], 0 @@ -3313,7 +3311,6 @@ cglobal prep_8tap_16bpc, 3, 8, 16, tmp, src, stride, w, h, mx, my, stride3 RET .hv_w32: %if WIN64 - %assign stack_offset stack_offset - stack_size_padded PUSH r8 %assign regs_used regs_used + 1 WIN64_SPILL_XMM 32 diff --git a/third_party/dav1d/src/x86/mc16_sse.asm b/third_party/dav1d/src/x86/mc16_sse.asm index fde8e372a3..b0c42597f7 100644 --- a/third_party/dav1d/src/x86/mc16_sse.asm +++ b/third_party/dav1d/src/x86/mc16_sse.asm @@ -1302,10 +1302,7 @@ cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my jg .h_w4_loop RET .h_w8: -%if WIN64 - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 12 -%endif shr mxd, 16 movq m3, [base+subpel_filters+mxq*8] movifnidn dstq, dstmp @@ -1383,14 +1380,7 @@ cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my cmp hd, 6 cmovb myd, mxd movq m3, [base+subpel_filters+myq*8] -%if STACK_ALIGNMENT < 16 - %xdefine rstk rsp -%else - %assign stack_offset stack_offset - stack_size_padded -%endif -%if WIN64 WIN64_SPILL_XMM 15 -%endif movd m7, r8m movifnidn dstq, dstmp movifnidn dsq, dsmp @@ -1604,11 +1594,7 @@ cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my jg .v_w4_loop0 RET .hv: -%if STACK_ALIGNMENT < 16 - %xdefine rstk rsp -%else - %assign stack_offset stack_offset - stack_size_padded -%endif + RESET_STACK_STATE %if ARCH_X86_32 movd m4, r8m mova m6, [base+pd_512] @@ -1750,11 +1736,7 @@ cglobal put_8tap_16bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my cmovb myd, mxd movq m3, [base+subpel_filters+myq*8] %if ARCH_X86_32 -%if STACK_ALIGNMENT < 16 - %xdefine rstk rsp -%else - %assign stack_offset stack_offset - stack_size_padded -%endif + RESET_STACK_STATE mov dstq, dstmp mov dsq, dsmp mova m0, [base+spel_h_shufA] @@ -2182,11 +2164,6 @@ cglobal prep_8tap_16bpc, 4, 8, 0, tmp, src, ss, w, h, mx, my cmp hd, 4 cmove myd, mxd movq m3, [base+subpel_filters+myq*8] -%if STACK_ALIGNMENT < 16 - %xdefine rstk rsp -%else - %assign stack_offset stack_offset - stack_size_padded -%endif WIN64_SPILL_XMM 15 movddup m7, [base+prep_8tap_1d_rnd] movifnidn ssq, r2mp @@ -2339,11 +2316,7 @@ cglobal prep_8tap_16bpc, 4, 8, 0, tmp, src, ss, w, h, mx, my jg .v_loop0 RET .hv: -%if STACK_ALIGNMENT < 16 - %xdefine rstk rsp -%else - %assign stack_offset stack_offset - stack_size_padded -%endif + RESET_STACK_STATE movzx t3d, mxb shr mxd, 16 cmp wd, 4 diff --git a/third_party/dav1d/src/x86/mc_avx2.asm b/third_party/dav1d/src/x86/mc_avx2.asm index 3b208033bd..58e3cb5af1 100644 --- a/third_party/dav1d/src/x86/mc_avx2.asm +++ b/third_party/dav1d/src/x86/mc_avx2.asm @@ -1259,7 +1259,6 @@ cglobal prep_bilin_8bpc, 3, 7, 0, tmp, src, stride, w, h, mxy, stride3 .hv: ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 8) >> 4 ; = src[x] + (((my * (src[x + src_stride] - src[x])) + 8) >> 4) - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 7 movzx wd, word [r6+wq*2+table_offset(prep, _bilin_hv)] shl mxyd, 11 @@ -1620,7 +1619,6 @@ cglobal put_8tap_8bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3 jg .h_loop RET .v: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 16 movzx mxd, myb shr myd, 16 @@ -1834,7 +1832,6 @@ cglobal put_8tap_8bpc, 4, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3 jg .v_w16_loop0 RET .hv: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 16 cmp wd, 4 jg .hv_w8 @@ -2247,7 +2244,6 @@ cglobal prep_8tap_8bpc, 3, 8, 0, tmp, src, stride, w, h, mx, my, stride3 jg .h_loop RET .v: - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 16 movzx mxd, myb ; Select 4-tap/8-tap filter multipliers. shr myd, 16 ; Note that the code is 8-tap only, having @@ -2430,8 +2426,6 @@ cglobal prep_8tap_8bpc, 3, 8, 0, tmp, src, stride, w, h, mx, my, stride3 jg .v_w16_loop0 RET .hv: - %assign stack_offset stack_offset - stack_size_padded - %assign stack_size_padded 0 WIN64_SPILL_XMM 16 cmp wd, 4 je .hv_w4 @@ -4108,10 +4102,9 @@ cglobal warp_affine_8x8t_8bpc, 0, 14, 0, tmp, ts cglobal warp_affine_8x8_8bpc, 0, 14, 0, dst, ds, src, ss, abcd, mx, tmp2, alpha, \ beta, filter, tmp1, delta, my, gamma %if WIN64 - sub rsp, 0xa0 %assign xmm_regs_used 16 %assign stack_size_padded 0xa0 - %assign stack_offset stack_offset+stack_size_padded + SUB rsp, stack_size_padded %endif call .main jmp .start @@ -4134,21 +4127,13 @@ cglobal warp_affine_8x8_8bpc, 0, 14, 0, dst, ds, src, ss, abcd, mx, tmp2, alpha, RET ALIGN function_align .main: - ; Stack args offset by one (r4m -> r5m etc.) due to call -%if WIN64 - mov abcdq, r5m - mov mxd, r6m - movaps [rsp+stack_offset+0x10], xmm6 - movaps [rsp+stack_offset+0x20], xmm7 - movaps [rsp+0x28], xmm8 - movaps [rsp+0x38], xmm9 - movaps [rsp+0x48], xmm10 - movaps [rsp+0x58], xmm11 - movaps [rsp+0x68], xmm12 - movaps [rsp+0x78], xmm13 - movaps [rsp+0x88], xmm14 - movaps [rsp+0x98], xmm15 -%endif + ; Stack is offset due to call + %assign stack_offset stack_offset + gprsize + %assign stack_size stack_size + gprsize + %assign stack_size_padded stack_size_padded + gprsize + movifnidn abcdq, abcdmp + movifnidn mxd, mxm + WIN64_PUSH_XMM movsx alphad, word [abcdq+2*0] movsx betad, word [abcdq+2*1] mova m12, [warp_8x8_shufA] @@ -4162,7 +4147,7 @@ ALIGN function_align lea tmp2d, [alphaq*3] sub srcq, tmp1q ; src -= src_stride*3 + 3 sub betad, tmp2d ; beta -= alpha*3 - mov myd, r7m + mov myd, r6m call .h psrld m1, m0, 16 call .h diff --git a/third_party/dav1d/src/x86/mc_avx512.asm b/third_party/dav1d/src/x86/mc_avx512.asm index 7897f1decc..f9043f1ad3 100644 --- a/third_party/dav1d/src/x86/mc_avx512.asm +++ b/third_party/dav1d/src/x86/mc_avx512.asm @@ -1276,7 +1276,6 @@ cglobal prep_bilin_8bpc, 3, 7, 0, tmp, src, stride, w, h, mxy, stride3 .hv: ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 8) >> 4 ; = src[x] + (((my * (src[x + src_stride] - src[x])) + 8) >> 4) - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 7 movzx wd, word [t2+wq*2+table_offset(prep, _bilin_hv)] shl mxyd, 11 @@ -2853,8 +2852,6 @@ cglobal prep_8tap_8bpc, 3, 8, 0, tmp, src, stride, w, h, mx, my, stride3 jg .v_loop0 RET .hv: - %assign stack_offset stack_offset - stack_size_padded - %assign stack_size_padded 0 WIN64_SPILL_XMM 16 cmp wd, 4 je .hv_w4 diff --git a/third_party/dav1d/src/x86/mc_sse.asm b/third_party/dav1d/src/x86/mc_sse.asm index 54939c647a..a447a80161 100644 --- a/third_party/dav1d/src/x86/mc_sse.asm +++ b/third_party/dav1d/src/x86/mc_sse.asm @@ -1199,7 +1199,6 @@ cglobal prep_bilin_8bpc, 3, 7, 0, tmp, src, stride, w, h, mxy, stride3 RET .v: %if notcpuflag(ssse3) - %assign stack_offset stack_offset - stack_size_padded WIN64_SPILL_XMM 8 %endif movzx wd, word [r6+wq*2+table_offset(prep, _bilin_v)] @@ -1375,7 +1374,6 @@ cglobal prep_bilin_8bpc, 3, 7, 0, tmp, src, stride, w, h, mxy, stride3 ; (16 * src[x] + (my * (src[x + src_stride] - src[x])) + 8) >> 4 ; = src[x] + (((my * (src[x + src_stride] - src[x])) + 8) >> 4) movzx wd, word [r6+wq*2+table_offset(prep, _bilin_hv)] -%assign stack_offset stack_offset - stack_size_padded %if cpuflag(ssse3) imul mxyd, 0x08000800 WIN64_SPILL_XMM 8 @@ -1592,7 +1590,6 @@ FN put_8tap, regular, REGULAR, REGULAR %endif cglobal put_8tap_8bpc, 1, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3 -%assign org_stack_offset stack_offset imul mxd, mxm, 0x010101 add mxd, t0d ; 8tap_h, mx, 4tap_h %if ARCH_X86_64 @@ -1618,7 +1615,6 @@ cglobal put_8tap_8bpc, 1, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3 movzx wd, word [base_reg+wq*2+table_offset(put,)] add wq, base_reg ; put_bilin mangling jump -%assign stack_offset org_stack_offset movifnidn dsq, dsmp movifnidn ssq, ssmp %if WIN64 @@ -1792,7 +1788,6 @@ cglobal put_8tap_8bpc, 1, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3 cmovs ssd, mxd movq m0, [base_reg+ssq*8+subpel_filters-put_ssse3] %else - %assign stack_offset org_stack_offset WIN64_SPILL_XMM 16 movzx mxd, myb shr myd, 16 @@ -2048,7 +2043,7 @@ cglobal put_8tap_8bpc, 1, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3 %undef subpel2 %undef subpel3 .hv: - %assign stack_offset org_stack_offset + RESET_STACK_STATE cmp wd, 4 jg .hv_w8 %if ARCH_X86_32 @@ -2369,7 +2364,7 @@ cglobal put_8tap_8bpc, 1, 9, 0, dst, ds, src, ss, w, h, mx, my, ss3 %undef subpelv2 %undef subpelv3 .hv_w8: - %assign stack_offset org_stack_offset + RESET_STACK_STATE %define hv8_line_1 0 %define hv8_line_2 1 %define hv8_line_3 2 @@ -2843,7 +2838,6 @@ FN prep_8tap, regular, REGULAR, REGULAR %define base 0 %endif cglobal prep_8tap_8bpc, 1, 9, 0, tmp, src, stride, w, h, mx, my, stride3 -%assign org_stack_offset stack_offset imul mxd, mxm, 0x010101 add mxd, t0d ; 8tap_h, mx, 4tap_h imul myd, mym, 0x010101 @@ -2862,7 +2856,6 @@ cglobal prep_8tap_8bpc, 1, 9, 0, tmp, src, stride, w, h, mx, my, stride3 add wq, base_reg movifnidn strided, stridem lea r6, [strideq*3] - %assign stack_offset org_stack_offset %if WIN64 pop r8 pop r7 @@ -3095,7 +3088,6 @@ cglobal prep_8tap_8bpc, 1, 9, 0, tmp, src, stride, w, h, mx, my, stride3 mov mxd, myd and mxd, 0x7f %else - %assign stack_offset org_stack_offset WIN64_SPILL_XMM 16 movzx mxd, myb %endif @@ -3359,7 +3351,7 @@ cglobal prep_8tap_8bpc, 1, 9, 0, tmp, src, stride, w, h, mx, my, stride3 %undef subpel2 %undef subpel3 .hv: - %assign stack_offset org_stack_offset + RESET_STACK_STATE cmp wd, 4 jg .hv_w8 and mxd, 0x7f @@ -3659,7 +3651,7 @@ cglobal prep_8tap_8bpc, 1, 9, 0, tmp, src, stride, w, h, mx, my, stride3 %undef subpelv2 %undef subpelv3 .hv_w8: - %assign stack_offset org_stack_offset + RESET_STACK_STATE %define hv8_line_1 0 %define hv8_line_2 1 %define hv8_line_3 2 diff --git a/third_party/dav1d/src/x86/msac.asm b/third_party/dav1d/src/x86/msac.asm index 9f05c921a6..4156efe914 100644 --- a/third_party/dav1d/src/x86/msac.asm +++ b/third_party/dav1d/src/x86/msac.asm @@ -143,10 +143,9 @@ cglobal msac_decode_symbol_adapt4, 0, 6, 6 mov esp, [esp] %endif %endif - not t4 sub t2d, t1d ; rng shl t1, gprsize*8-16 - add t4, t1 ; ~dif + sub t4, t1 ; dif - v .renorm3: mov t1d, [t0+msac.cnt] movifnidn t7, t0 @@ -157,33 +156,31 @@ cglobal msac_decode_symbol_adapt4, 0, 6, 6 shl t2d, cl shl t4, cl mov [t7+msac.rng], t2d - not t4 sub t1d, ecx jae .end ; no refill required ; refill: - mov t2, [t7+msac.buf] - mov rcx, [t7+msac.end] %if ARCH_X86_64 == 0 push t5 %endif - lea t5, [t2+gprsize] - cmp t5, rcx + mov t2, [t7+msac.buf] + mov t5, [t7+msac.end] + lea rcx, [t2+gprsize] + sub rcx, t5 ja .refill_eob - mov t2, [t2] - lea ecx, [t1+23] - add t1d, 16 - shr ecx, 3 ; shift_bytes - bswap t2 - sub t5, rcx - shl ecx, 3 ; shift_bits - shr t2, cl - sub ecx, t1d ; shift_bits - 16 - cnt - mov t1d, gprsize*8-16 - shl t2, cl - mov [t7+msac.buf], t5 - sub t1d, ecx ; cnt + gprsize*8 - shift_bits - xor t4, t2 + mov t5, [t2] + lea ecx, [t1+16-gprsize*8] + not t5 + bswap t5 + shr t5, cl + neg ecx + shr ecx, 3 ; num_bytes_read + or t4, t5 +.refill_end: + add t2, rcx + lea t1d, [t1+rcx*8] ; cnt += num_bits_read + mov [t7+msac.buf], t2 +.refill_end2: %if ARCH_X86_64 == 0 pop t5 %endif @@ -191,29 +188,35 @@ cglobal msac_decode_symbol_adapt4, 0, 6, 6 mov [t7+msac.cnt], t1d mov [t7+msac.dif], t4 RET +.pad_with_ones: + lea ecx, [t1-16] +%if ARCH_X86_64 + ror rcx, cl +%else + shr ecx, cl +%endif + or t4, rcx + jmp .refill_end2 .refill_eob: ; avoid overreading the input buffer - mov t5, rcx - mov ecx, gprsize*8-24 - sub ecx, t1d ; c -.refill_eob_loop: cmp t2, t5 - jae .refill_eob_end ; eob reached - movzx t1d, byte [t2] - inc t2 - shl t1, cl - xor t4, t1 - sub ecx, 8 - jge .refill_eob_loop -.refill_eob_end: - mov t1d, gprsize*8-24 -%if ARCH_X86_64 == 0 - pop t5 -%endif - sub t1d, ecx - mov [t7+msac.buf], t2 - mov [t7+msac.dif], t4 - mov [t7+msac.cnt], t1d - RET + jae .pad_with_ones ; eob reached + ; We can safely do a register-sized load of the last bytes of the buffer + ; as this code is only reached if the msac buffer size is >= gprsize. + mov t5, [t5-gprsize] + shl ecx, 3 + shr t5, cl + lea ecx, [t1+16-gprsize*8] + not t5 + bswap t5 + shr t5, cl + neg ecx + or t4, t5 + mov t5d, [t7+msac.end] + shr ecx, 3 + sub t5d, t2d ; num_bytes_left + cmp ecx, t5d + cmovae ecx, t5d ; num_bytes_read + jmp .refill_end cglobal msac_decode_symbol_adapt8, 0, 6, 6 DECODE_SYMBOL_ADAPT_INIT @@ -366,7 +369,6 @@ cglobal msac_decode_bool_adapt, 0, 6, 0 %if ARCH_X86_64 == 0 movzx eax, al %endif - not t4 test t3d, t3d jz m(msac_decode_symbol_adapt4, SUFFIX).renorm3 %if UNIX64 == 0 @@ -420,7 +422,6 @@ cglobal msac_decode_bool_equi, 0, 6, 0 mov ecx, 0xbfff setb al ; the upper 32 bits contains garbage but that's OK sub ecx, t2d - not t4 ; In this case of this function, (d =) 16 - clz(v) = 2 - (v >> 14) ; i.e. (0 <= d <= 2) and v < (3 << 14) shr ecx, 14 ; d @@ -447,7 +448,6 @@ cglobal msac_decode_bool, 0, 6, 0 cmovb t2d, t1d cmovb t4, t3 setb al - not t4 %if ARCH_X86_64 == 0 movzx eax, al %endif @@ -497,48 +497,45 @@ cglobal msac_decode_bool, 0, 6, 0 tzcnt eax, eax movzx ecx, word [buf+rax+16] movzx t2d, word [buf+rax+14] - not t4 %if ARCH_X86_64 add t6d, 5 %endif sub eax, 5 ; setup for merging the tok_br and tok branches sub t2d, ecx shl rcx, gprsize*8-16 - add t4, rcx + sub t4, rcx bsr ecx, t2d xor ecx, 15 shl t2d, cl shl t4, cl movd m2, t2d mov [t7+msac.rng], t2d - not t4 sub t5d, ecx jae %%end - mov t2, [t7+msac.buf] - mov rcx, [t7+msac.end] %if UNIX64 == 0 push t8 %endif - lea t8, [t2+gprsize] - cmp t8, rcx + mov t2, [t7+msac.buf] + mov t8, [t7+msac.end] + lea rcx, [t2+gprsize] + sub rcx, t8 ja %%refill_eob - mov t2, [t2] - lea ecx, [t5+23] - add t5d, 16 + mov t8, [t2] + lea ecx, [t5+16-gprsize*8] + not t8 + bswap t8 + shr t8, cl + neg ecx shr ecx, 3 - bswap t2 - sub t8, rcx - shl ecx, 3 - shr t2, cl - sub ecx, t5d - mov t5d, gprsize*8-16 - shl t2, cl - mov [t7+msac.buf], t8 + or t4, t8 +%%refill_end: + add t2, rcx + lea t5d, [t5+rcx*8] + mov [t7+msac.buf], t2 +%%refill_end2: %if UNIX64 == 0 pop t8 %endif - sub t5d, ecx - xor t4, t2 %%end: movp m3, t4 %if ARCH_X86_64 @@ -559,27 +556,34 @@ cglobal msac_decode_bool, 0, 6, 0 shr eax, 1 mov [t7+msac.cnt], t5d RET +%%pad_with_ones: + ; ensure that dif is padded with at least 15 bits of ones at the end + lea ecx, [t5-16] +%if ARCH_X86_64 + ror rcx, cl +%else + shr ecx, cl +%endif + or t4, rcx + jmp %%refill_end2 %%refill_eob: - mov t8, rcx - mov ecx, gprsize*8-24 - sub ecx, t5d -%%refill_eob_loop: cmp t2, t8 - jae %%refill_eob_end - movzx t5d, byte [t2] - inc t2 - shl t5, cl - xor t4, t5 - sub ecx, 8 - jge %%refill_eob_loop -%%refill_eob_end: -%if UNIX64 == 0 - pop t8 -%endif - mov t5d, gprsize*8-24 - mov [t7+msac.buf], t2 - sub t5d, ecx - jmp %%end + jae %%pad_with_ones + mov t8, [t8-gprsize] + shl ecx, 3 + shr t8, cl + lea ecx, [t5+16-gprsize*8] + not t8 + bswap t8 + shr t8, cl + neg ecx + or t4, t8 + mov t8d, [t7+msac.end] + shr ecx, 3 + sub t8d, t2d + cmp ecx, t8d + cmovae ecx, t8d + jmp %%refill_end %endmacro cglobal msac_decode_hi_tok, 0, 7 + ARCH_X86_64, 6 diff --git a/third_party/jpeg-xl/CHANGELOG.md b/third_party/jpeg-xl/CHANGELOG.md index 3c62a1f2df..42f0f2e5c1 100644 --- a/third_party/jpeg-xl/CHANGELOG.md +++ b/third_party/jpeg-xl/CHANGELOG.md @@ -16,6 +16,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +## [0.10.2] - 2024-03-08 + +### Fixed + - bugs in (lossless) encoding (#3367, #3359 and #3386) + - re-enable installation of MIME file (#3375) + - bugs in streaming mode (#3379 and #3380) + +## [0.10.1] - 2024-02-28 + +### Fixed + - reduce allocations (#3336 and #3339), + fixing a significant speed regression present since 0.9.0 + - bug in streaming encoding (#3331) + ## [0.10.0] - 2024-02-21 ### Added diff --git a/third_party/jpeg-xl/WORKSPACE b/third_party/jpeg-xl/WORKSPACE index 1383b44e0d..db9fcddb6e 100644 --- a/third_party/jpeg-xl/WORKSPACE +++ b/third_party/jpeg-xl/WORKSPACE @@ -1,5 +1,5 @@ -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") workspace(name = "libjxl") diff --git a/third_party/jpeg-xl/debian/changelog b/third_party/jpeg-xl/debian/changelog index 83f256f642..0722b1bd4a 100644 --- a/third_party/jpeg-xl/debian/changelog +++ b/third_party/jpeg-xl/debian/changelog @@ -1,8 +1,20 @@ -jpeg-xl (0.10.0) UNRELEASED; urgency=medium +jpeg-xl (0.10.2) unstable; urgency=medium + + * Bump JPEG XL version to 0.10.2. + + -- JPEG XL Maintainers Thu, 07 Mar 2024 13:50:05 +0100 + +jpeg-xl (0.10.1) unstable; urgency=medium + + * Bump JPEG XL version to 0.10.1. + + -- JPEG XL Maintainers Wed, 28 Feb 2024 12:52:20 +0100 + +jpeg-xl (0.10.0) unstable; urgency=medium * Bump JPEG XL version to 0.10.0. - -- JPEG XL Maintainers Tue, 21 Nov 2023 10:32:59 +0100 + -- JPEG XL Maintainers Wed, 21 Feb 2024 08:37:00 +0100 jpeg-xl (0.9.0) unstable; urgency=medium diff --git a/third_party/jpeg-xl/examples/decode_exif_metadata.cc b/third_party/jpeg-xl/examples/decode_exif_metadata.cc index d5f11705bd..65608621d9 100644 --- a/third_party/jpeg-xl/examples/decode_exif_metadata.cc +++ b/third_party/jpeg-xl/examples/decode_exif_metadata.cc @@ -97,7 +97,7 @@ bool LoadFile(const char* filename, std::vector* out) { return false; } - long size = ftell(file); + long size = ftell(file); // NOLINT // Avoid invalid file or directory. if (size >= LONG_MAX || size < 0) { fclose(file); diff --git a/third_party/jpeg-xl/examples/decode_oneshot.cc b/third_party/jpeg-xl/examples/decode_oneshot.cc index a24bd73bfb..b7e17c21a4 100644 --- a/third_party/jpeg-xl/examples/decode_oneshot.cc +++ b/third_party/jpeg-xl/examples/decode_oneshot.cc @@ -169,7 +169,7 @@ bool LoadFile(const char* filename, std::vector* out) { return false; } - long size = ftell(file); + long size = ftell(file); // NOLINT // Avoid invalid file or directory. if (size >= LONG_MAX || size < 0) { fclose(file); diff --git a/third_party/jpeg-xl/examples/decode_progressive.cc b/third_party/jpeg-xl/examples/decode_progressive.cc index fa7f3df663..2cdc175e8a 100644 --- a/third_party/jpeg-xl/examples/decode_progressive.cc +++ b/third_party/jpeg-xl/examples/decode_progressive.cc @@ -6,6 +6,10 @@ // This C++ example decodes a JPEG XL image progressively (input bytes are // passed in chunks). The example outputs the intermediate steps to PAM files. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + #include #include #include @@ -174,7 +178,7 @@ bool LoadFile(const char* filename, std::vector* out) { return false; } - long size = ftell(file); + long size = ftell(file); // NOLINT // Avoid invalid file or directory. if (size >= LONG_MAX || size < 0) { fclose(file); @@ -220,7 +224,7 @@ int main(int argc, char* argv[]) { } size_t chunksize = jxl.size(); if (argc > 3) { - long cs = atol(argv[3]); + long cs = atol(argv[3]); // NOLINT if (cs < 100) { fprintf(stderr, "Chunk size is too low, try at least 100 bytes\n"); return 1; diff --git a/third_party/jpeg-xl/examples/encode_oneshot.cc b/third_party/jpeg-xl/examples/encode_oneshot.cc index 1582570432..6c45a70411 100644 --- a/third_party/jpeg-xl/examples/encode_oneshot.cc +++ b/third_party/jpeg-xl/examples/encode_oneshot.cc @@ -48,7 +48,7 @@ bool ReadPFM(const char* filename, std::vector* pixels, uint32_t* xsize, return false; } - long size = ftell(file); + long size = ftell(file); // NOLINT // Avoid invalid file or directory. if (size >= LONG_MAX || size < 0) { fclose(file); @@ -64,7 +64,7 @@ bool ReadPFM(const char* filename, std::vector* pixels, uint32_t* xsize, data.resize(size); size_t readsize = fread(data.data(), 1, size, file); - if (static_cast(readsize) != size) { + if (static_cast(readsize) != size) { // NOLINT fclose(file); return false; } diff --git a/third_party/jpeg-xl/lib/BUILD b/third_party/jpeg-xl/lib/BUILD index d93858f22d..3d48919f77 100644 --- a/third_party/jpeg-xl/lib/BUILD +++ b/third_party/jpeg-xl/lib/BUILD @@ -3,6 +3,9 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +load("@bazel_skylib//rules:copy_file.bzl", "copy_file") +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") + # Load sources/headers/tests lists. load( "jxl_lists.bzl", @@ -57,8 +60,6 @@ load( "libjxl_test_shards", "libjxl_test_timeouts", ) -load("@bazel_skylib//rules:copy_file.bzl", "copy_file") -load("@bazel_skylib//rules:expand_template.bzl", "expand_template") DEFAULT_VISIBILITY = ["//:__subpackages__"] diff --git a/third_party/jpeg-xl/lib/CMakeLists.txt b/third_party/jpeg-xl/lib/CMakeLists.txt index 1e6f4abf74..a178e02f67 100644 --- a/third_party/jpeg-xl/lib/CMakeLists.txt +++ b/third_party/jpeg-xl/lib/CMakeLists.txt @@ -5,7 +5,7 @@ set(JPEGXL_MAJOR_VERSION 0) set(JPEGXL_MINOR_VERSION 10) -set(JPEGXL_PATCH_VERSION 0) +set(JPEGXL_PATCH_VERSION 2) set(JPEGXL_LIBRARY_VERSION "${JPEGXL_MAJOR_VERSION}.${JPEGXL_MINOR_VERSION}.${JPEGXL_PATCH_VERSION}") diff --git a/third_party/jpeg-xl/lib/extras/codec_test.cc b/third_party/jpeg-xl/lib/extras/codec_test.cc index 50d5e37bc9..1357b5a616 100644 --- a/third_party/jpeg-xl/lib/extras/codec_test.cc +++ b/third_party/jpeg-xl/lib/extras/codec_test.cc @@ -26,6 +26,7 @@ #include "lib/extras/enc/encode.h" #include "lib/extras/packed_image.h" #include "lib/jxl/base/byte_order.h" +#include "lib/jxl/base/data_parallel.h" #include "lib/jxl/base/random.h" #include "lib/jxl/base/span.h" #include "lib/jxl/base/status.h" @@ -333,10 +334,10 @@ TEST(CodecTest, TestRoundTrip) { params.add_alpha = add_alpha; params.big_endian = big_endian; params.add_extra_channels = false; - TestRoundTrip(params, &pool); + TestRoundTrip(params, pool.get()); if (codec == Codec::kPNM && add_alpha) { params.add_extra_channels = true; - TestRoundTrip(params, &pool); + TestRoundTrip(params, pool.get()); } } } @@ -369,7 +370,7 @@ TEST(CodecTest, LosslessPNMRoundtrip) { EncodedImage encoded; auto encoder = Encoder::FromExtension(extension); ASSERT_TRUE(encoder.get()); - ASSERT_TRUE(encoder->Encode(ppf, &encoded, &pool)); + ASSERT_TRUE(encoder->Encode(ppf, &encoded, pool.get())); ASSERT_EQ(encoded.bitstreams.size(), 1); ASSERT_EQ(orig.size(), encoded.bitstreams[0].size()); EXPECT_EQ(0, diff --git a/third_party/jpeg-xl/lib/extras/dec/apng.cc b/third_party/jpeg-xl/lib/extras/dec/apng.cc index 8b0da06eb1..c607a71d08 100644 --- a/third_party/jpeg-xl/lib/extras/dec/apng.cc +++ b/third_party/jpeg-xl/lib/extras/dec/apng.cc @@ -381,9 +381,11 @@ class BlobsReaderPNG { // We need 2*bytes for the hex values plus 1 byte every 36 values, // plus terminal \n for length. - const unsigned long needed_bytes = - bytes_to_decode * 2 + 1 + DivCeil(bytes_to_decode, 36); - if (needed_bytes != static_cast(encoded_end - pos)) { + size_t tail = static_cast(encoded_end - pos); + bool ok = ((tail / 2) >= bytes_to_decode); + if (ok) tail -= 2 * static_cast(bytes_to_decode); + ok = ok && (tail == 1 + DivCeil(bytes_to_decode, 36)); + if (!ok) { return JXL_FAILURE("Not enough bytes to parse %d bytes in hex", bytes_to_decode); } @@ -439,7 +441,7 @@ struct APNGFrame { Status Resize(size_t new_size) { if (new_size > pixels_size) { pixels.reset(malloc(new_size)); - if (!pixels.get()) { + if (!pixels) { // TODO(szabadka): use specialized OOM error code return JXL_FAILURE("Failed to allocate memory for image buffer"); } @@ -462,7 +464,7 @@ struct Reader { bool Eof() const { return next == last; } }; -const unsigned long cMaxPNGSize = 1000000UL; +const uint32_t cMaxPNGSize = 1000000UL; const size_t kMaxPNGChunkSize = 1lu << 30; // 1 GB void info_fn(png_structp png_ptr, png_infop info_ptr) { @@ -641,17 +643,17 @@ Status DecodeImageAPNG(const Span bytes, bool have_srgb = false; bool errorstate = true; if (id == kId_IHDR && chunkIHDR.size() == 25) { - unsigned int x0 = 0; - unsigned int y0 = 0; - unsigned int delay_num = 1; - unsigned int delay_den = 10; - unsigned int dop = 0; - unsigned int bop = 0; - - unsigned int w = png_get_uint_32(chunkIHDR.data() + 8); - unsigned int h = png_get_uint_32(chunkIHDR.data() + 12); - unsigned int w0 = w; - unsigned int h0 = h; + uint32_t x0 = 0; + uint32_t y0 = 0; + uint32_t delay_num = 1; + uint32_t delay_den = 10; + uint32_t dop = 0; + uint32_t bop = 0; + + uint32_t w = png_get_uint_32(chunkIHDR.data() + 8); + uint32_t h = png_get_uint_32(chunkIHDR.data() + 12); + uint32_t w0 = w; + uint32_t h0 = h; if (w > cMaxPNGSize || h > cMaxPNGSize) { return false; } diff --git a/third_party/jpeg-xl/lib/extras/dec/pnm.cc b/third_party/jpeg-xl/lib/extras/dec/pnm.cc index 040c0bff81..e64d7e95f9 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pnm.cc +++ b/third_party/jpeg-xl/lib/extras/dec/pnm.cc @@ -332,7 +332,7 @@ struct PNMChunkedInputFrame { METHOD_TO_C_CALLBACK(&PNMChunkedInputFrame::ReleaseCurrentData)}; } - void GetColorChannelsPixelFormat(JxlPixelFormat* pixel_format) { + void /* NOLINT */ GetColorChannelsPixelFormat(JxlPixelFormat* pixel_format) { *pixel_format = format; } @@ -349,12 +349,14 @@ struct PNMChunkedInputFrame { void GetExtraChannelPixelFormat(size_t ec_index, JxlPixelFormat* pixel_format) { + (void)this; JXL_ABORT("Not implemented"); } const void* GetExtraChannelDataAt(size_t ec_index, size_t xpos, size_t ypos, size_t xsize, size_t ysize, size_t* row_offset) { + (void)this; JXL_ABORT("Not implemented"); } diff --git a/third_party/jpeg-xl/lib/extras/enc/apng.cc b/third_party/jpeg-xl/lib/extras/enc/apng.cc index 40aa876e84..a28408a7f2 100644 --- a/third_party/jpeg-xl/lib/extras/enc/apng.cc +++ b/third_party/jpeg-xl/lib/extras/enc/apng.cc @@ -73,17 +73,30 @@ class APNGEncoder : public Encoder { } Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image, ThreadPool* pool) const override { + // Encode main image frames JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info)); encoded_image->icc.clear(); encoded_image->bitstreams.resize(1); - return EncodePackedPixelFileToAPNG(ppf, pool, - &encoded_image->bitstreams.front()); + JXL_RETURN_IF_ERROR(EncodePackedPixelFileToAPNG( + ppf, pool, &encoded_image->bitstreams.front())); + + // Encode extra channels + for (size_t i = 0; i < ppf.extra_channels_info.size(); ++i) { + encoded_image->extra_channel_bitstreams.emplace_back(); + auto& ec_bitstreams = encoded_image->extra_channel_bitstreams.back(); + ec_bitstreams.emplace_back(); + JXL_RETURN_IF_ERROR(EncodePackedPixelFileToAPNG( + ppf, pool, &ec_bitstreams.back(), true, i)); + } + return true; } private: Status EncodePackedPixelFileToAPNG(const PackedPixelFile& ppf, ThreadPool* pool, - std::vector* bytes) const; + std::vector* bytes, + bool encode_extra_channels = false, + size_t extra_channel_index = 0) const; }; void PngWrite(png_structp png_ptr, png_bytep data, png_size_t length) { @@ -266,15 +279,21 @@ void MaybeAddCLLi(const JxlColorEncoding& c_enc, const float intensity_target, } Status APNGEncoder::EncodePackedPixelFileToAPNG( - const PackedPixelFile& ppf, ThreadPool* pool, - std::vector* bytes) const { - size_t xsize = ppf.info.xsize; - size_t ysize = ppf.info.ysize; - bool has_alpha = ppf.info.alpha_bits != 0; - bool is_gray = ppf.info.num_color_channels == 1; - size_t color_channels = ppf.info.num_color_channels; + const PackedPixelFile& ppf, ThreadPool* pool, std::vector* bytes, + bool encode_extra_channels, size_t extra_channel_index) const { + JxlExtraChannelInfo ec_info{}; + if (encode_extra_channels) { + if (ppf.extra_channels_info.size() <= extra_channel_index) { + return JXL_FAILURE("Invalid index for extra channel"); + } + ec_info = ppf.extra_channels_info[extra_channel_index].ec_info; + } + + bool has_alpha = !encode_extra_channels && (ppf.info.alpha_bits != 0); + bool is_gray = encode_extra_channels || (ppf.info.num_color_channels == 1); + size_t color_channels = + encode_extra_channels ? 1 : ppf.info.num_color_channels; size_t num_channels = color_channels + (has_alpha ? 1 : 0); - size_t num_samples = num_channels * xsize * ysize; if (!ppf.info.have_animation && ppf.frames.size() != 1) { return JXL_FAILURE("Invalid number of frames"); @@ -284,9 +303,24 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG( size_t anim_chunks = 0; for (const auto& frame : ppf.frames) { - JXL_RETURN_IF_ERROR(VerifyPackedImage(frame.color, ppf.info)); - - const PackedImage& color = frame.color; + const PackedImage& color = encode_extra_channels + ? frame.extra_channels[extra_channel_index] + : frame.color; + + size_t xsize = color.xsize; + size_t ysize = color.ysize; + size_t num_samples = num_channels * xsize * ysize; + + uint32_t bits_per_sample = encode_extra_channels ? ec_info.bits_per_sample + : ppf.info.bits_per_sample; + if (!encode_extra_channels) { + JXL_RETURN_IF_ERROR(VerifyPackedImage(color, ppf.info)); + } else { + JXL_RETURN_IF_ERROR(VerifyFormat(color.format)); + JXL_RETURN_IF_ERROR(VerifyBitDepth(color.format.data_type, + bits_per_sample, + ec_info.exponent_bits_per_sample)); + } const JxlPixelFormat format = color.format; const uint8_t* in = reinterpret_cast(color.pixels()); size_t data_bits_per_sample = PackedImage::BitsPerChannel(format.data_type); @@ -297,24 +331,23 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG( std::vector out(out_size); if (format.data_type == JXL_TYPE_UINT8) { - if (ppf.info.bits_per_sample < 8) { - float mul = 255.0 / ((1u << ppf.info.bits_per_sample) - 1); + if (bits_per_sample < 8) { + float mul = 255.0 / ((1u << bits_per_sample) - 1); for (size_t i = 0; i < num_samples; ++i) { - out[i] = static_cast(in[i] * mul + 0.5); + out[i] = static_cast(std::lroundf(in[i] * mul)); } } else { memcpy(out.data(), in, out_size); } } else if (format.data_type == JXL_TYPE_UINT16) { - if (ppf.info.bits_per_sample < 16 || - format.endianness != JXL_BIG_ENDIAN) { - float mul = 65535.0 / ((1u << ppf.info.bits_per_sample) - 1); + if (bits_per_sample < 16 || format.endianness != JXL_BIG_ENDIAN) { + float mul = 65535.0 / ((1u << bits_per_sample) - 1); const uint8_t* p_in = in; uint8_t* p_out = out.data(); for (size_t i = 0; i < num_samples; ++i, p_in += 2, p_out += 2) { uint32_t val = (format.endianness == JXL_BIG_ENDIAN ? LoadBE16(p_in) : LoadLE16(p_in)); - StoreBE16(static_cast(val * mul + 0.5), p_out); + StoreBE16(static_cast(std::lroundf(val * mul)), p_out); } } else { memcpy(out.data(), in, out_size); @@ -344,7 +377,7 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG( png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if (count == 0) { + if (count == 0 && !encode_extra_channels) { if (!MaybeAddSRGB(ppf.color_encoding, png_ptr, info_ptr)) { MaybeAddCICP(ppf.color_encoding, png_ptr, info_ptr); if (!ppf.icc.empty()) { diff --git a/third_party/jpeg-xl/lib/extras/enc/jpegli.cc b/third_party/jpeg-xl/lib/extras/enc/jpegli.cc index aa10b584d0..cb473a1290 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jpegli.cc +++ b/third_party/jpeg-xl/lib/extras/enc/jpegli.cc @@ -390,7 +390,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, // before the call to setjmp(). std::vector pixels; unsigned char* output_buffer = nullptr; - unsigned long output_size = 0; + unsigned long output_size = 0; // NOLINT std::vector row_bytes; size_t rowlen = RoundUpTo(ppf.info.xsize, MaxVectorSize()); hwy::AlignedFreeUniquePtr xyb_tmp = diff --git a/third_party/jpeg-xl/lib/extras/enc/jpg.cc b/third_party/jpeg-xl/lib/extras/enc/jpg.cc index de0228fc0d..0095ac9294 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jpg.cc +++ b/third_party/jpeg-xl/lib/extras/enc/jpg.cc @@ -276,7 +276,7 @@ Status EncodeWithLibJpeg(const PackedImage& image, const JxlBasicInfo& info, cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); unsigned char* buffer = nullptr; - unsigned long size = 0; + unsigned long size = 0; // NOLINT jpeg_mem_dest(&cinfo, &buffer, &size); cinfo.image_width = image.xsize; cinfo.image_height = image.ysize; diff --git a/third_party/jpeg-xl/lib/extras/enc/pnm.cc b/third_party/jpeg-xl/lib/extras/enc/pnm.cc index 966611cfca..d2d67ae52a 100644 --- a/third_party/jpeg-xl/lib/extras/enc/pnm.cc +++ b/third_party/jpeg-xl/lib/extras/enc/pnm.cc @@ -87,8 +87,8 @@ class PNMEncoder : public BasePNMEncoder { } private: - Status EncodeImage(const PackedImage& image, size_t bits_per_sample, - std::vector* bytes) const { + static Status EncodeImage(const PackedImage& image, size_t bits_per_sample, + std::vector* bytes) { uint32_t maxval = (1u << bits_per_sample) - 1; char type = image.format.num_channels == 1 ? '5' : '6'; char header[kMaxHeaderSize]; @@ -161,8 +161,8 @@ class PFMEncoder : public BasePNMEncoder { } private: - Status EncodeImage(const PackedImage& image, - std::vector* bytes) const { + static Status EncodeImage(const PackedImage& image, + std::vector* bytes) { char type = image.format.num_channels == 1 ? 'f' : 'F'; double scale = image.format.endianness == JXL_LITTLE_ENDIAN ? -1.0 : 1.0; char header[kMaxHeaderSize]; diff --git a/third_party/jpeg-xl/lib/extras/mmap.h b/third_party/jpeg-xl/lib/extras/mmap.h index 8bc023dec0..60cc215993 100644 --- a/third_party/jpeg-xl/lib/extras/mmap.h +++ b/third_party/jpeg-xl/lib/extras/mmap.h @@ -18,10 +18,10 @@ class MemoryMappedFile { static StatusOr Init(const char* path); const uint8_t* data() const; size_t size() const; - MemoryMappedFile(); - ~MemoryMappedFile(); - MemoryMappedFile(MemoryMappedFile&&) noexcept; - MemoryMappedFile& operator=(MemoryMappedFile&&) noexcept; + MemoryMappedFile(); // NOLINT + ~MemoryMappedFile(); // NOLINT + MemoryMappedFile(MemoryMappedFile&&) noexcept; // NOLINT + MemoryMappedFile& operator=(MemoryMappedFile&&) noexcept; // NOLINT private: std::unique_ptr impl_; diff --git a/third_party/jpeg-xl/lib/jpegli/color_transform.cc b/third_party/jpeg-xl/lib/jpegli/color_transform.cc index 020a6fd80c..60a0dc83bb 100644 --- a/third_party/jpeg-xl/lib/jpegli/color_transform.cc +++ b/third_party/jpeg-xl/lib/jpegli/color_transform.cc @@ -135,19 +135,25 @@ bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) { return num_components == 1; case JCS_RGB: case JCS_YCbCr: +#ifdef JCS_EXTENSIONS case JCS_EXT_RGB: case JCS_EXT_BGR: +#endif return num_components == 3; case JCS_CMYK: case JCS_YCCK: +#ifdef JCS_EXTENSIONS case JCS_EXT_RGBX: case JCS_EXT_BGRX: case JCS_EXT_XBGR: case JCS_EXT_XRGB: +#endif +#ifdef JCS_ALPHA_EXTENSIONS case JCS_EXT_RGBA: case JCS_EXT_BGRA: case JCS_EXT_ABGR: case JCS_EXT_ARGB: +#endif return num_components == 4; default: // Unrecognized colorspaces can have any number of channels, since no diff --git a/third_party/jpeg-xl/lib/jpegli/decode.h b/third_party/jpeg-xl/lib/jpegli/decode.h index 9800ebf67a..f5b099eda3 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode.h +++ b/third_party/jpeg-xl/lib/jpegli/decode.h @@ -36,7 +36,7 @@ void jpegli_CreateDecompress(j_decompress_ptr cinfo, int version, void jpegli_stdio_src(j_decompress_ptr cinfo, FILE *infile); void jpegli_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer, - unsigned long insize); + unsigned long insize /* NOLINT */); int jpegli_read_header(j_decompress_ptr cinfo, boolean require_image); diff --git a/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc index 0cc5a194d7..3ecd479951 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc @@ -3,8 +3,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include #include +#include #include #include "lib/jpegli/decode.h" @@ -78,7 +78,8 @@ class SourceManager { return TRUE; } - static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + static void skip_input_data(j_decompress_ptr cinfo, + long num_bytes /* NOLINT */) { auto* src = reinterpret_cast(cinfo->src); if (num_bytes <= 0) { return; @@ -447,7 +448,7 @@ std::vector GenerateBasicConfigs() { TEST(DecodeAPITest, ReuseCinfoSameMemSource) { std::vector all_configs = GenerateBasicConfigs(); uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -502,7 +503,7 @@ TEST(DecodeAPITest, ReuseCinfoSameStdSource) { EXPECT_TRUE(try_catch_block()); jpegli_destroy_compress(&cinfo); } - rewind(tmpf); + fseek(tmpf, 0, SEEK_SET); std::vector all_outputs(all_configs.size()); { jpeg_decompress_struct cinfo; @@ -527,9 +528,9 @@ TEST(DecodeAPITest, ReuseCinfoSameStdSource) { TEST(DecodeAPITest, AbbreviatedStreams) { uint8_t* table_stream = nullptr; - unsigned long table_stream_size = 0; + unsigned long table_stream_size = 0; // NOLINT uint8_t* data_stream = nullptr; - unsigned long data_stream_size = 0; + unsigned long data_stream_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { diff --git a/third_party/jpeg-xl/lib/jpegli/destination_manager.cc b/third_party/jpeg-xl/lib/jpegli/destination_manager.cc index 6548130866..05d35797b8 100644 --- a/third_party/jpeg-xl/lib/jpegli/destination_manager.cc +++ b/third_party/jpeg-xl/lib/jpegli/destination_manager.cc @@ -52,7 +52,7 @@ struct MemoryDestinationManager { jpeg_destination_mgr pub; // Output buffer supplied by the application uint8_t** output; - unsigned long* output_size; + unsigned long* output_size; // NOLINT // Output buffer allocated by us. uint8_t* temp_buffer; // Current output buffer (either application supplied or allocated by us). @@ -113,7 +113,7 @@ void jpegli_stdio_dest(j_compress_ptr cinfo, FILE* outfile) { } void jpegli_mem_dest(j_compress_ptr cinfo, unsigned char** outbuffer, - unsigned long* outsize) { + unsigned long* outsize /* NOLINT */) { if (outbuffer == nullptr || outsize == nullptr) { JPEGLI_ERROR("jpegli_mem_dest: Invalid destination."); } diff --git a/third_party/jpeg-xl/lib/jpegli/encode.h b/third_party/jpeg-xl/lib/jpegli/encode.h index 320dfaaf8d..ed34838450 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode.h +++ b/third_party/jpeg-xl/lib/jpegli/encode.h @@ -35,7 +35,7 @@ void jpegli_CreateCompress(j_compress_ptr cinfo, int version, void jpegli_stdio_dest(j_compress_ptr cinfo, FILE* outfile); void jpegli_mem_dest(j_compress_ptr cinfo, unsigned char** outbuffer, - unsigned long* outsize); + unsigned long* outsize /* NOLINT */); void jpegli_set_defaults(j_compress_ptr cinfo); diff --git a/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc index 1afdcf610d..2978b3f35d 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc @@ -69,7 +69,7 @@ TEST(EncodeAPITest, ReuseCinfoSameImageTwice) { CompressParams jparams; GenerateInput(PIXELS, jparams, &input); uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT std::vector compressed0; std::vector compressed1; jpeg_compress_struct cinfo; @@ -117,7 +117,7 @@ std::vector GenerateBasicConfigs() { TEST(EncodeAPITest, ReuseCinfoSameMemOutput) { std::vector all_configs = GenerateBasicConfigs(); uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -161,7 +161,7 @@ TEST(EncodeAPITest, ReuseCinfoSameStdOutput) { jpegli_destroy_compress(&cinfo); } size_t total_size = ftell(tmpf); - rewind(tmpf); + fseek(tmpf, 0, SEEK_SET); std::vector compressed(total_size); JXL_CHECK(total_size == fread(compressed.data(), 1, total_size, tmpf)); fclose(tmpf); @@ -181,7 +181,7 @@ TEST(EncodeAPITest, ReuseCinfoChangeParams) { CompressParams jparams; DecompressParams dparams; uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT std::vector compressed; jpeg_compress_struct cinfo; const auto max_rms = [](int q, int hs, int vs) { @@ -246,9 +246,9 @@ TEST(EncodeAPITest, ReuseCinfoChangeParams) { TEST(EncodeAPITest, AbbreviatedStreams) { uint8_t* table_stream = nullptr; - unsigned long table_stream_size = 0; + unsigned long table_stream_size = 0; // NOLINT uint8_t* data_stream = nullptr; - unsigned long data_stream_size = 0; + unsigned long data_stream_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { diff --git a/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc b/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc index 3eaf6a313b..bcd7355124 100644 --- a/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc @@ -15,7 +15,7 @@ namespace { TEST(EncoderErrorHandlingTest, MinimalSuccess) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -64,7 +64,7 @@ TEST(EncoderErrorHandlingTest, NoDestination) { TEST(EncoderErrorHandlingTest, NoImageDimensions) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -82,7 +82,7 @@ TEST(EncoderErrorHandlingTest, NoImageDimensions) { TEST(EncoderErrorHandlingTest, ImageTooBig) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -102,7 +102,7 @@ TEST(EncoderErrorHandlingTest, ImageTooBig) { TEST(EncoderErrorHandlingTest, NoInputComponents) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -121,7 +121,7 @@ TEST(EncoderErrorHandlingTest, NoInputComponents) { TEST(EncoderErrorHandlingTest, TooManyInputComponents) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -141,7 +141,7 @@ TEST(EncoderErrorHandlingTest, TooManyInputComponents) { TEST(EncoderErrorHandlingTest, NoSetDefaults) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -164,7 +164,7 @@ TEST(EncoderErrorHandlingTest, NoSetDefaults) { TEST(EncoderErrorHandlingTest, NoStartCompress) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -186,7 +186,7 @@ TEST(EncoderErrorHandlingTest, NoStartCompress) { TEST(EncoderErrorHandlingTest, NoWriteScanlines) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -207,7 +207,7 @@ TEST(EncoderErrorHandlingTest, NoWriteScanlines) { TEST(EncoderErrorHandlingTest, NoWriteAllScanlines) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -231,7 +231,7 @@ TEST(EncoderErrorHandlingTest, NoWriteAllScanlines) { TEST(EncoderErrorHandlingTest, InvalidQuantValue) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -260,7 +260,7 @@ TEST(EncoderErrorHandlingTest, InvalidQuantValue) { TEST(EncoderErrorHandlingTest, InvalidQuantTableIndex) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -285,7 +285,7 @@ TEST(EncoderErrorHandlingTest, InvalidQuantTableIndex) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch1) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -306,7 +306,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch1) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch2) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -327,7 +327,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch2) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch3) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -353,7 +353,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch3) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch4) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -378,7 +378,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch4) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch5) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -403,7 +403,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch5) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch6) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -429,7 +429,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch6) { TEST(EncoderErrorHandlingTest, InvalidColorTransform) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -455,7 +455,7 @@ TEST(EncoderErrorHandlingTest, InvalidColorTransform) { TEST(EncoderErrorHandlingTest, DuplicateComponentIds) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -477,7 +477,7 @@ TEST(EncoderErrorHandlingTest, DuplicateComponentIds) { TEST(EncoderErrorHandlingTest, InvalidComponentIndex) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -498,7 +498,7 @@ TEST(EncoderErrorHandlingTest, InvalidComponentIndex) { TEST(EncoderErrorHandlingTest, ArithmeticCoding) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -519,7 +519,7 @@ TEST(EncoderErrorHandlingTest, ArithmeticCoding) { TEST(EncoderErrorHandlingTest, CCIR601Sampling) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -540,7 +540,7 @@ TEST(EncoderErrorHandlingTest, CCIR601Sampling) { TEST(EncoderErrorHandlingTest, InvalidScanScript1) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -563,7 +563,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript1) { TEST(EncoderErrorHandlingTest, InvalidScanScript2) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -586,7 +586,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript2) { TEST(EncoderErrorHandlingTest, InvalidScanScript3) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -609,7 +609,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript3) { TEST(EncoderErrorHandlingTest, InvalidScanScript4) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -632,7 +632,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript4) { TEST(EncoderErrorHandlingTest, InvalidScanScript5) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -655,7 +655,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript5) { TEST(EncoderErrorHandlingTest, InvalidScanScript6) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -678,7 +678,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript6) { TEST(EncoderErrorHandlingTest, InvalidScanScript7) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -701,7 +701,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript7) { TEST(EncoderErrorHandlingTest, InvalidScanScript8) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -726,7 +726,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript8) { TEST(EncoderErrorHandlingTest, InvalidScanScript9) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -751,7 +751,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript9) { TEST(EncoderErrorHandlingTest, InvalidScanScript10) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -776,7 +776,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript10) { TEST(EncoderErrorHandlingTest, InvalidScanScript11) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -801,7 +801,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript11) { TEST(EncoderErrorHandlingTest, InvalidScanScript12) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -826,7 +826,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript12) { TEST(EncoderErrorHandlingTest, InvalidScanScript13) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -854,7 +854,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript13) { TEST(EncoderErrorHandlingTest, MCUSizeTooBig) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -877,7 +877,7 @@ TEST(EncoderErrorHandlingTest, MCUSizeTooBig) { TEST(EncoderErrorHandlingTest, RestartIntervalTooBig) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -898,7 +898,7 @@ TEST(EncoderErrorHandlingTest, RestartIntervalTooBig) { TEST(EncoderErrorHandlingTest, SamplingFactorTooBig) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -919,7 +919,7 @@ TEST(EncoderErrorHandlingTest, SamplingFactorTooBig) { TEST(EncoderErrorHandlingTest, NonIntegralSamplingRatio) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); diff --git a/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc b/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc index eb8b7ebc26..6546b7b087 100644 --- a/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc @@ -80,7 +80,8 @@ struct SourceManager { static boolean fill_input_buffer(j_decompress_ptr cinfo) { return FALSE; } - static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + static void skip_input_data(j_decompress_ptr cinfo, + long num_bytes /* NOLINT*/) { auto* src = reinterpret_cast(cinfo->src); if (num_bytes <= 0) { return; diff --git a/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc b/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc index 471b7c7192..a2b333afef 100644 --- a/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc +++ b/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc @@ -38,7 +38,7 @@ void jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile) { } void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer, - unsigned long insize) { + unsigned long insize /* NOLINT */) { jpegli_mem_src(cinfo, inbuffer, insize); } @@ -138,7 +138,7 @@ void jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile) { } void jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer, - unsigned long *outsize) { + unsigned long *outsize /* NOLINT */) { jpegli_mem_dest(cinfo, outbuffer, outsize); } diff --git a/third_party/jpeg-xl/lib/jpegli/source_manager.cc b/third_party/jpeg-xl/lib/jpegli/source_manager.cc index 58adf803b1..e0f0b4c275 100644 --- a/third_party/jpeg-xl/lib/jpegli/source_manager.cc +++ b/third_party/jpeg-xl/lib/jpegli/source_manager.cc @@ -12,9 +12,10 @@ namespace jpegli { void init_mem_source(j_decompress_ptr cinfo) {} void init_stdio_source(j_decompress_ptr cinfo) {} -void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { +void skip_input_data(j_decompress_ptr cinfo, long num_bytes /* NOLINT */) { if (num_bytes <= 0) return; - while (num_bytes > static_cast(cinfo->src->bytes_in_buffer)) { + while (num_bytes > + static_cast(cinfo->src->bytes_in_buffer)) { // NOLINT num_bytes -= cinfo->src->bytes_in_buffer; (*cinfo->src->fill_input_buffer)(cinfo); } @@ -53,7 +54,7 @@ struct StdioSourceManager { } // namespace jpegli void jpegli_mem_src(j_decompress_ptr cinfo, const unsigned char* inbuffer, - unsigned long insize) { + unsigned long insize /* NOLINT */) { if (cinfo->src && cinfo->src->init_source != jpegli::init_mem_source) { JPEGLI_ERROR("jpegli_mem_src: a different source manager was already set"); } diff --git a/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc b/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc index 59d12b001b..a513b7063b 100644 --- a/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc @@ -43,7 +43,7 @@ FILE* MemOpen(const std::vector& data) { FILE* src = tmpfile(); if (!src) return nullptr; fwrite(data.data(), 1, data.size(), src); - rewind(src); + fseek(src, 0, SEEK_SET); return src; } } // namespace diff --git a/third_party/jpeg-xl/lib/jpegli/streaming_test.cc b/third_party/jpeg-xl/lib/jpegli/streaming_test.cc index 2e6f7029b0..1f19dc2045 100644 --- a/third_party/jpeg-xl/lib/jpegli/streaming_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/streaming_test.cc @@ -28,7 +28,8 @@ struct SourceManager { static void init_source(j_decompress_ptr cinfo) {} static boolean fill_input_buffer(j_decompress_ptr cinfo) { return FALSE; } - static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {} + static void skip_input_data(j_decompress_ptr cinfo, + long num_bytes /* NOLINT */) {} static void term_source(j_decompress_ptr cinfo) {} }; diff --git a/third_party/jpeg-xl/lib/jpegli/test_utils.cc b/third_party/jpeg-xl/lib/jpegli/test_utils.cc index 4e675070cf..db5a30e8dc 100644 --- a/third_party/jpeg-xl/lib/jpegli/test_utils.cc +++ b/third_party/jpeg-xl/lib/jpegli/test_utils.cc @@ -673,7 +673,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, bool EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, std::vector* compressed) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); diff --git a/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc index 1d99ce37fa..13c81a1119 100644 --- a/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc @@ -20,7 +20,7 @@ void TranscodeWithJpegli(const std::vector& jpeg_input, jpeg_decompress_struct dinfo = {}; jpeg_compress_struct cinfo = {}; uint8_t* transcoded_data = nullptr; - unsigned long transcoded_size; + unsigned long transcoded_size; // NOLINT const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); dinfo.err = cinfo.err; diff --git a/third_party/jpeg-xl/lib/jxl.cmake b/third_party/jpeg-xl/lib/jxl.cmake index 86fa37151d..82a2716978 100644 --- a/third_party/jpeg-xl/lib/jxl.cmake +++ b/third_party/jpeg-xl/lib/jxl.cmake @@ -80,10 +80,10 @@ foreach(path ${JPEGXL_INTERNAL_PUBLIC_HEADERS}) endforeach() add_library(jxl_base INTERFACE) -target_include_directories(jxl_base SYSTEM INTERFACE +target_include_directories(jxl_base SYSTEM BEFORE INTERFACE "$" ) -target_include_directories(jxl_base INTERFACE +target_include_directories(jxl_base BEFORE INTERFACE ${PROJECT_SOURCE_DIR} ${JXL_HWY_INCLUDE_DIRS} ) @@ -104,7 +104,7 @@ add_library(jxl_dec-obj OBJECT ${JPEGXL_INTERNAL_DEC_SOURCES}) target_compile_options(jxl_dec-obj PRIVATE ${JPEGXL_INTERNAL_FLAGS}) target_compile_options(jxl_dec-obj PUBLIC ${JPEGXL_COVERAGE_FLAGS}) set_property(TARGET jxl_dec-obj PROPERTY POSITION_INDEPENDENT_CODE ON) -target_include_directories(jxl_dec-obj PUBLIC +target_include_directories(jxl_dec-obj BEFORE PUBLIC "$" "${JXL_HWY_INCLUDE_DIRS}" "$>" @@ -119,7 +119,7 @@ add_library(jxl_enc-obj OBJECT ${JPEGXL_INTERNAL_ENC_SOURCES}) target_compile_options(jxl_enc-obj PRIVATE ${JPEGXL_INTERNAL_FLAGS}) target_compile_options(jxl_enc-obj PUBLIC ${JPEGXL_COVERAGE_FLAGS}) set_property(TARGET jxl_enc-obj PROPERTY POSITION_INDEPENDENT_CODE ON) -target_include_directories(jxl_enc-obj PUBLIC +target_include_directories(jxl_enc-obj BEFORE PUBLIC ${PROJECT_SOURCE_DIR} ${JXL_HWY_INCLUDE_DIRS} $ @@ -172,7 +172,7 @@ target_link_libraries(jxl-internal PUBLIC jxl_cms jxl_base ) -target_include_directories(jxl-internal PUBLIC +target_include_directories(jxl-internal BEFORE PUBLIC "$") target_compile_definitions(jxl-internal INTERFACE -DJXL_STATIC_DEFINE) diff --git a/third_party/jpeg-xl/lib/jxl/alpha_test.cc b/third_party/jpeg-xl/lib/jxl/alpha_test.cc index a93254f3dd..6e26e77be6 100644 --- a/third_party/jpeg-xl/lib/jxl/alpha_test.cc +++ b/third_party/jpeg-xl/lib/jxl/alpha_test.cc @@ -13,6 +13,16 @@ namespace jxl { namespace { +AlphaBlendingInputLayer makeAbil(const Color& rgb, const float& a) { + const float* data = rgb.data(); + return {data, data + 1, data + 2, &a}; +} + +AlphaBlendingOutput makeAbo(Color& rgb, float& a) { + float* data = rgb.data(); + return {data, data + 1, data + 2, &a}; +} + TEST(AlphaTest, BlendingWithNonPremultiplied) { const Color bg_rgb{100, 110, 120}; const float bg_a = 180.f / 255; @@ -22,16 +32,16 @@ TEST(AlphaTest, BlendingWithNonPremultiplied) { Color out_rgb; float out_a; PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/false, /*clamp=*/false); EXPECT_ARRAY_NEAR(out_rgb, (Color{77.2f, 83.0f, 90.6f}), 0.05f); EXPECT_NEAR(out_a, 3174.f / 4095, 1e-5); PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a2}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a2), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/false, /*clamp=*/true); EXPECT_ARRAY_NEAR(out_rgb, fg_rgb, 0.05f); EXPECT_NEAR(out_a, 1.0f, 1e-5); @@ -46,16 +56,16 @@ TEST(AlphaTest, BlendingWithPremultiplied) { Color out_rgb; float out_a; PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/true, /*clamp=*/false); EXPECT_ARRAY_NEAR(out_rgb, (Color{101.5f, 105.1f, 114.8f}), 0.05f); EXPECT_NEAR(out_a, 3174.f / 4095, 1e-5); PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a2}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a2), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/true, /*clamp=*/true); EXPECT_ARRAY_NEAR(out_rgb, fg_rgb, 0.05f); EXPECT_NEAR(out_a, 1.0f, 1e-5); diff --git a/third_party/jpeg-xl/lib/jxl/bit_reader_test.cc b/third_party/jpeg-xl/lib/jxl/bit_reader_test.cc index 22a20649e0..802da855fa 100644 --- a/third_party/jpeg-xl/lib/jxl/bit_reader_test.cc +++ b/third_party/jpeg-xl/lib/jxl/bit_reader_test.cc @@ -53,7 +53,7 @@ struct Symbol { TEST(BitReaderTest, TestRoundTrip) { test::ThreadPoolForTests pool(8); EXPECT_TRUE(RunOnPool( - &pool, 0, 1000, ThreadPool::NoInit, + pool.get(), 0, 1000, ThreadPool::NoInit, [](const uint32_t task, size_t /* thread */) { constexpr size_t kMaxBits = 8000; BitWriter writer; @@ -87,7 +87,7 @@ TEST(BitReaderTest, TestRoundTrip) { TEST(BitReaderTest, TestSkip) { test::ThreadPoolForTests pool(8); EXPECT_TRUE(RunOnPool( - &pool, 0, 96, ThreadPool::NoInit, + pool.get(), 0, 96, ThreadPool::NoInit, [](const uint32_t task, size_t /* thread */) { constexpr size_t kSize = 100; diff --git a/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.h b/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.h index e0bfd354e1..487db2bdce 100644 --- a/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.h +++ b/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.h @@ -8,12 +8,10 @@ #ifndef LIB_JXL_BUTTERAUGLI_BUTTERAUGLI_H_ #define LIB_JXL_BUTTERAUGLI_BUTTERAUGLI_H_ -#include #include #include #include -#include #include #include @@ -21,7 +19,10 @@ #include "lib/jxl/base/status.h" #include "lib/jxl/image.h" +#if !defined(BUTTERAUGLI_ENABLE_CHECKS) #define BUTTERAUGLI_ENABLE_CHECKS 0 +#endif + #define BUTTERAUGLI_RESTRICT JXL_RESTRICT // This is the main interface to butteraugli image similarity diff --git a/third_party/jpeg-xl/lib/jxl/cache_aligned.cc b/third_party/jpeg-xl/lib/jxl/cache_aligned.cc index 8a95634d68..814b538cf6 100644 --- a/third_party/jpeg-xl/lib/jxl/cache_aligned.cc +++ b/third_party/jpeg-xl/lib/jxl/cache_aligned.cc @@ -128,11 +128,12 @@ void* CacheAligned::Allocate(const size_t payload_size, size_t offset) { const uintptr_t payload = aligned + offset; // still aligned // Stash `allocated` and payload_size inside header for use by Free(). - AllocationHeader* header = reinterpret_cast(payload) - 1; + AllocationHeader* header = + reinterpret_cast(payload) - 1; // NOLINT header->allocated = allocated; header->allocated_size = allocated_size; - return JXL_ASSUME_ALIGNED(reinterpret_cast(payload), 64); + return JXL_ASSUME_ALIGNED(reinterpret_cast(payload), 64); // NOLINT } void CacheAligned::Free(const void* aligned_pointer) { @@ -142,7 +143,7 @@ void CacheAligned::Free(const void* aligned_pointer) { const uintptr_t payload = reinterpret_cast(aligned_pointer); JXL_ASSERT(payload % kAlignment == 0); const AllocationHeader* header = - reinterpret_cast(payload) - 1; + reinterpret_cast(payload) - 1; // NOLINT // Subtract (2's complement negation). bytes_in_use.fetch_add(~header->allocated_size + 1, diff --git a/third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h b/third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h index 7f59e688d0..a787bd11d8 100644 --- a/third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h +++ b/third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h @@ -183,12 +183,12 @@ static Status ToneMapPixel(const JxlColorEncoding& c, const float in[3], const float f_y = lab_f(xyz[1] / kYn); const float f_z = lab_f(xyz[2] / kZn); - pcslab_out[0] = - static_cast(.5f + 255.f * Clamp1(1.16f * f_y - .16f, 0.f, 1.f)); + pcslab_out[0] = static_cast( + std::lroundf(255.f * Clamp1(1.16f * f_y - .16f, 0.f, 1.f))); pcslab_out[1] = static_cast( - .5f + 128.f + Clamp1(500 * (f_x - f_y), -128.f, 127.f)); + std::lroundf(128.f + Clamp1(500 * (f_x - f_y), -128.f, 127.f))); pcslab_out[2] = static_cast( - .5f + 128.f + Clamp1(200 * (f_y - f_z), -128.f, 127.f)); + std::lroundf(128.f + Clamp1(200 * (f_y - f_z), -128.f, 127.f))); return true; } @@ -581,7 +581,8 @@ static void CreateICCCurvCurvTag(const std::vector& curve, } // Writes 12 + 4*params.size() bytes -static Status CreateICCCurvParaTag(std::vector params, size_t curve_type, +static Status CreateICCCurvParaTag(const std::vector& params, + size_t curve_type, std::vector* tags) { WriteICCTag("para", tags->size(), tags); WriteICCUint32(0, tags->size(), tags); @@ -637,7 +638,7 @@ static Status CreateICCLutAtoBTagForXYB(std::vector* tags) { for (size_t ib = 0; ib < 2; ++ib) { const jxl::cms::ColorCube0D& out_f = cube[ix][iy][ib]; for (int i = 0; i < 3; ++i) { - int32_t val = static_cast(0.5f + 65535 * out_f[i]); + int32_t val = static_cast(std::lroundf(65535 * out_f[i])); JXL_DASSERT(val >= 0 && val <= 65535); WriteICCUint16(val, tags->size(), tags); } diff --git a/third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h b/third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h index 81f301a31d..1f85dcca41 100644 --- a/third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h +++ b/third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h @@ -22,8 +22,8 @@ class Rec2408ToneMapperBase { explicit Rec2408ToneMapperBase(std::pair source_range, std::pair target_range, const Vector3& primaries_luminances) - : source_range_(source_range), - target_range_(target_range), + : source_range_(std::move(source_range)), + target_range_(std::move(target_range)), red_Y_(primaries_luminances[0]), green_Y_(primaries_luminances[1]), blue_Y_(primaries_luminances[2]) {} @@ -56,7 +56,7 @@ class Rec2408ToneMapperBase { } protected: - float InvEOTF(const float luminance) const { + static float InvEOTF(const float luminance) { return TF_PQ_Base::EncodedFromDisplay(/*display_intensity_target=*/1.0, luminance); } diff --git a/third_party/jpeg-xl/lib/jxl/cms/transfer_functions-inl.h b/third_party/jpeg-xl/lib/jxl/cms/transfer_functions-inl.h index 84bcbb45ed..133e624c08 100644 --- a/third_party/jpeg-xl/lib/jxl/cms/transfer_functions-inl.h +++ b/third_party/jpeg-xl/lib/jxl/cms/transfer_functions-inl.h @@ -69,7 +69,7 @@ class TF_HLG : TF_HLG_Base { class TF_709 { public: - JXL_INLINE double EncodedFromDisplay(const double d) const { + static JXL_INLINE double EncodedFromDisplay(const double d) { if (d < kThresh) return kMulLow * d; return kMulHi * std::pow(d, kPowHi) + kSub; } diff --git a/third_party/jpeg-xl/lib/jxl/color_management_test.cc b/third_party/jpeg-xl/lib/jxl/color_management_test.cc index b2d47c73f9..77cbe56926 100644 --- a/third_party/jpeg-xl/lib/jxl/color_management_test.cc +++ b/third_party/jpeg-xl/lib/jxl/color_management_test.cc @@ -434,7 +434,7 @@ TEST_F(ColorManagementTest, GoldenXYBCube) { for (size_t ib = 0; ib < 2; ++ib) { const jxl::cms::ColorCube0D& out_f = cube[ix][iy][ib]; for (int i = 0; i < 3; ++i) { - int32_t val = static_cast(0.5f + 65535 * out_f[i]); + int32_t val = static_cast(std::lroundf(65535 * out_f[i])); ASSERT_TRUE(val >= 0 && val <= 65535); actual.push_back(val); } diff --git a/third_party/jpeg-xl/lib/jxl/convolve_test.cc b/third_party/jpeg-xl/lib/jxl/convolve_test.cc index 09cbdc12a6..084398c5e1 100644 --- a/third_party/jpeg-xl/lib/jxl/convolve_test.cc +++ b/third_party/jpeg-xl/lib/jxl/convolve_test.cc @@ -161,7 +161,7 @@ void TestConvolve() { test::ThreadPoolForTests pool(4); EXPECT_EQ(true, RunOnPool( - &pool, kConvolveMaxRadius, 40, ThreadPool::NoInit, + pool.get(), kConvolveMaxRadius, 40, ThreadPool::NoInit, [](const uint32_t task, size_t /*thread*/) { const size_t xsize = task; Rng rng(129 + 13 * xsize); @@ -176,15 +176,15 @@ void TestConvolve() { JXL_DEBUG(JXL_DEBUG_CONVOLVE, "Sym3------------------"); VerifySymmetric3(xsize, ysize, null_pool, &rng); - VerifySymmetric3(xsize, ysize, &pool3, &rng); + VerifySymmetric3(xsize, ysize, pool3.get(), &rng); JXL_DEBUG(JXL_DEBUG_CONVOLVE, "Sym5------------------"); VerifySymmetric5(xsize, ysize, null_pool, &rng); - VerifySymmetric5(xsize, ysize, &pool3, &rng); + VerifySymmetric5(xsize, ysize, pool3.get(), &rng); JXL_DEBUG(JXL_DEBUG_CONVOLVE, "Sep5------------------"); VerifySeparable5(xsize, ysize, null_pool, &rng); - VerifySeparable5(xsize, ysize, &pool3, &rng); + VerifySeparable5(xsize, ysize, pool3.get(), &rng); } }, "TestConvolve")); diff --git a/third_party/jpeg-xl/lib/jxl/dct_for_test.h b/third_party/jpeg-xl/lib/jxl/dct_for_test.h index 58dd75e20e..b0cbffacad 100644 --- a/third_party/jpeg-xl/lib/jxl/dct_for_test.h +++ b/third_party/jpeg-xl/lib/jxl/dct_for_test.h @@ -22,7 +22,7 @@ static inline double alpha(int u) { return u == 0 ? 0.7071067811865475 : 1.0; } // N-DCT on M columns, divided by sqrt(N). Matches the definition in the spec. template -void DCT1D(double block[N * M], double out[N * M]) { +void DCT1D(const double block[N * M], double out[N * M]) { std::vector matrix(N * N); const double scale = std::sqrt(2.0) / N; for (size_t y = 0; y < N; y++) { @@ -43,7 +43,7 @@ void DCT1D(double block[N * M], double out[N * M]) { // N-IDCT on M columns, multiplied by sqrt(N). Matches the definition in the // spec. template -void IDCT1D(double block[N * M], double out[N * M]) { +void IDCT1D(const double block[N * M], double out[N * M]) { std::vector matrix(N * N); const double scale = std::sqrt(2.0); for (size_t y = 0; y < N; y++) { @@ -63,7 +63,7 @@ void IDCT1D(double block[N * M], double out[N * M]) { } template -void TransposeBlock(double in[N * M], double out[M * N]) { +void TransposeBlock(const double in[N * M], double out[M * N]) { for (size_t x = 0; x < N; x++) { for (size_t y = 0; y < M; y++) { out[y * N + x] = in[x * M + y]; diff --git a/third_party/jpeg-xl/lib/jxl/dct_test.cc b/third_party/jpeg-xl/lib/jxl/dct_test.cc index e4982e2f45..57ce9291e2 100644 --- a/third_party/jpeg-xl/lib/jxl/dct_test.cc +++ b/third_party/jpeg-xl/lib/jxl/dct_test.cc @@ -160,7 +160,7 @@ void TestInverseT(float accuracy) { test::ThreadPoolForTests pool(N < 32 ? 0 : 8); enum { kBlockSize = N * N }; EXPECT_TRUE(RunOnPool( - &pool, 0, kBlockSize, ThreadPool::NoInit, + pool.get(), 0, kBlockSize, ThreadPool::NoInit, [accuracy](const uint32_t task, size_t /*thread*/) { const size_t i = static_cast(task); HWY_ALIGN float x[kBlockSize] = {0.0f}; diff --git a/third_party/jpeg-xl/lib/jxl/dec_cache.cc b/third_party/jpeg-xl/lib/jxl/dec_cache.cc index 2a89420018..639857d4f8 100644 --- a/third_party/jpeg-xl/lib/jxl/dec_cache.cc +++ b/third_party/jpeg-xl/lib/jxl/dec_cache.cc @@ -125,8 +125,8 @@ Status PassesDecoderState::PreparePipeline(const FrameHeader& frame_header, if (frame_header.CanBeReferenced() && frame_header.save_before_color_transform) { - builder.AddStage(GetWriteToImageBundleStage( - &frame_storage_for_referencing, output_encoding_info.color_encoding)); + builder.AddStage(GetWriteToImageBundleStage(&frame_storage_for_referencing, + output_encoding_info)); } bool has_alpha = false; @@ -181,7 +181,7 @@ Status PassesDecoderState::PreparePipeline(const FrameHeader& frame_header, linear = false; } builder.AddStage(GetWriteToImageBundleStage( - &frame_storage_for_referencing, output_encoding_info.color_encoding)); + &frame_storage_for_referencing, output_encoding_info)); } if (options.render_spotcolors && @@ -228,7 +228,7 @@ Status PassesDecoderState::PreparePipeline(const FrameHeader& frame_header, if ((output_encoding_info.color_encoding_is_original) || (!output_encoding_info.cms_set) || mixing_color_and_grey) { // in those cases we only need a linear stage in other cases we attempt - // to obtain an cms stage: the cases are + // to obtain a cms stage: the cases are // - output_encoding_info.color_encoding_is_original: no cms stage // needed because it would be a no-op // - !output_encoding_info.cms_set: can't use the cms, so no point in @@ -255,8 +255,8 @@ Status PassesDecoderState::PreparePipeline(const FrameHeader& frame_header, has_alpha, unpremul_alpha, alpha_c, undo_orientation, extra_output)); } else { - builder.AddStage(GetWriteToImageBundleStage( - decoded, output_encoding_info.color_encoding)); + builder.AddStage( + GetWriteToImageBundleStage(decoded, output_encoding_info)); } } JXL_ASSIGN_OR_RETURN(render_pipeline, diff --git a/third_party/jpeg-xl/lib/jxl/dec_modular.cc b/third_party/jpeg-xl/lib/jxl/dec_modular.cc index 49561e6ec2..80cc9d1360 100644 --- a/third_party/jpeg-xl/lib/jxl/dec_modular.cc +++ b/third_party/jpeg-xl/lib/jxl/dec_modular.cc @@ -362,7 +362,7 @@ Status ModularFrameDecoder::DecodeGroup( // Undo global transforms that have been pushed to the group level if (!use_full_image) { JXL_ASSERT(render_pipeline_input); - for (auto t : global_transform) { + for (const auto& t : global_transform) { JXL_RETURN_IF_ERROR(t.Inverse(gi, global_header.wp_header)); } JXL_RETURN_IF_ERROR(ModularImageToDecodedRect( diff --git a/third_party/jpeg-xl/lib/jxl/decode_test.cc b/third_party/jpeg-xl/lib/jxl/decode_test.cc index 33176cfd66..99b5871ccd 100644 --- a/third_party/jpeg-xl/lib/jxl/decode_test.cc +++ b/third_party/jpeg-xl/lib/jxl/decode_test.cc @@ -2475,7 +2475,7 @@ void TestPartialStream(bool reconstructible_jpeg) { TEST(DecodeTest, PixelPartialTest) { TestPartialStream(false); } // Tests the return status when trying to decode JPEG bytes on incomplete file. -TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGPartialTest)) { +JXL_TRANSCODE_JPEG_TEST(DecodeTest, JPEGPartialTest) { TEST_LIBJPEG_SUPPORT(); TestPartialStream(true); } @@ -4195,7 +4195,7 @@ TEST(DecodeTest, InputHandlingTestOneShot) { } } -TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(InputHandlingTestJPEGOneshot)) { +JXL_TRANSCODE_JPEG_TEST(DecodeTest, InputHandlingTestJPEGOneshot) { TEST_LIBJPEG_SUPPORT(); size_t xsize = 123; size_t ysize = 77; @@ -4976,7 +4976,7 @@ void VerifyJPEGReconstruction(jxl::Span container, EXPECT_EQ(0, memcmp(reconstructed_buffer.data(), jpeg_bytes.data(), used)); } -TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructTestCodestream)) { +JXL_TRANSCODE_JPEG_TEST(DecodeTest, JPEGReconstructTestCodestream) { TEST_LIBJPEG_SUPPORT(); size_t xsize = 123; size_t ysize = 77; @@ -4994,7 +4994,7 @@ TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructTestCodestream)) { VerifyJPEGReconstruction(jxl::Bytes(compressed), jxl::Bytes(jpeg_codestream)); } -TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructionTest)) { +JXL_TRANSCODE_JPEG_TEST(DecodeTest, JPEGReconstructionTest) { const std::string jpeg_path = "jxl/flower/flower.png.im_q85_420.jpg"; const std::vector orig = jxl::test::ReadTestData(jpeg_path); jxl::CodecInOut orig_io; @@ -5024,7 +5024,7 @@ TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructionTest)) { VerifyJPEGReconstruction(jxl::Bytes(container), jxl::Bytes(orig)); } -TEST(DecodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructionMetadataTest)) { +JXL_TRANSCODE_JPEG_TEST(DecodeTest, JPEGReconstructionMetadataTest) { const std::string jpeg_path = "jxl/jpeg_reconstruction/1x1_exif_xmp.jpg"; const std::string jxl_path = "jxl/jpeg_reconstruction/1x1_exif_xmp.jxl"; const std::vector jpeg = jxl::test::ReadTestData(jpeg_path); @@ -5135,7 +5135,7 @@ TEST(DecodeTest, ExtentedBoxSizeTest) { JxlDecoderDestroy(dec); } -TEST(DecodeTest, JXL_BOXES_TEST(BoxTest)) { +JXL_BOXES_TEST(DecodeTest, BoxTest) { size_t xsize = 1; size_t ysize = 1; std::vector pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0); @@ -5212,7 +5212,7 @@ TEST(DecodeTest, JXL_BOXES_TEST(BoxTest)) { JxlDecoderDestroy(dec); } -TEST(DecodeTest, JXL_BOXES_TEST(ExifBrobBoxTest)) { +JXL_BOXES_TEST(DecodeTest, ExifBrobBoxTest) { size_t xsize = 1; size_t ysize = 1; std::vector pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0); @@ -5394,7 +5394,7 @@ TEST(DecodeTest, JXL_BOXES_TEST(ExifBrobBoxTest)) { } } -TEST(DecodeTest, JXL_BOXES_TEST(PartialCodestreamBoxTest)) { +JXL_BOXES_TEST(DecodeTest, PartialCodestreamBoxTest) { size_t xsize = 23; size_t ysize = 81; std::vector pixels = jxl::test::GetSomeTestImage(xsize, ysize, 4, 0); diff --git a/third_party/jpeg-xl/lib/jxl/enc_ar_control_field.cc b/third_party/jpeg-xl/lib/jxl/enc_ar_control_field.cc index e80771248e..4f1d2dadb5 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_ar_control_field.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_ar_control_field.cc @@ -149,9 +149,9 @@ Status ProcessTile(const CompressParams& cparams, float* JXL_RESTRICT row_out = sqrsum_00_row + y * sqrsum_00_stride; for (size_t x = 0; x < rect.xsize() * 2; x++) { auto sum = Zero(df4); - for (size_t iy = 0; iy < 4; iy++) { + for (auto& row : rows_in) { for (size_t ix = 0; ix < 4; ix += Lanes(df4)) { - sum = Add(sum, LoadU(df4, rows_in[iy] + x * 4 + ix + 2)); + sum = Add(sum, LoadU(df4, row + x * 4 + ix + 2)); } } row_out[x] = GetLane(Sqrt(SumOfLanes(df4, sum))) * (1.0f / 4.0f); diff --git a/third_party/jpeg-xl/lib/jxl/enc_fast_lossless.cc b/third_party/jpeg-xl/lib/jxl/enc_fast_lossless.cc index 58d0d00eaa..1797139428 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_fast_lossless.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_fast_lossless.cc @@ -202,8 +202,8 @@ size_t TOCBucket(size_t group_size) { size_t TOCSize(const std::vector& group_sizes) { size_t toc_bits = 0; - for (size_t i = 0; i < group_sizes.size(); i++) { - toc_bits += kTOCBits[TOCBucket(group_sizes[i])]; + for (size_t group_size : group_sizes) { + toc_bits += kTOCBits[TOCBucket(group_size)]; } return (toc_bits + 7) / 8; } @@ -328,8 +328,8 @@ struct PrefixCode { template static void ComputeCodeLengthsNonZeroImpl(const uint64_t* freqs, size_t n, size_t precision, T infty, - uint8_t* min_limit, - uint8_t* max_limit, + const uint8_t* min_limit, + const uint8_t* max_limit, uint8_t* nbits) { assert(precision < 15); assert(n <= kMaxNumSymbols); @@ -454,8 +454,8 @@ struct PrefixCode { uint8_t min_lengths[kNumLZ77] = {}; uint8_t l = 15 - level1_nbits[numraw]; uint8_t max_lengths[kNumLZ77]; - for (size_t i = 0; i < kNumLZ77; i++) { - max_lengths[i] = l; + for (uint8_t& max_length : max_lengths) { + max_length = l; } size_t num_lz77 = kNumLZ77; while (num_lz77 > 0 && lz77_counts[num_lz77 - 1] == 0) num_lz77--; @@ -487,11 +487,11 @@ struct PrefixCode { void WriteTo(BitWriter* writer) const { uint64_t code_length_counts[18] = {}; code_length_counts[17] = 3 + 2 * (kNumLZ77 - 1); - for (size_t i = 0; i < kNumRawSymbols; i++) { - code_length_counts[raw_nbits[i]]++; + for (uint8_t raw_nbit : raw_nbits) { + code_length_counts[raw_nbit]++; } - for (size_t i = 0; i < kNumLZ77; i++) { - code_length_counts[lz77_nbits[i]]++; + for (uint8_t lz77_nbit : lz77_nbits) { + code_length_counts[lz77_nbit]++; } uint8_t code_length_nbits[18] = {}; uint8_t code_length_nbits_min[18] = {}; @@ -527,9 +527,8 @@ struct PrefixCode { code_length_bits, 18); // Encode raw bit code lengths. // Max bits written in this loop: 19 * 5 = 95 - for (size_t i = 0; i < kNumRawSymbols; i++) { - writer->Write(code_length_nbits[raw_nbits[i]], - code_length_bits[raw_nbits[i]]); + for (uint8_t raw_nbit : raw_nbits) { + writer->Write(code_length_nbits[raw_nbit], code_length_bits[raw_nbit]); } size_t num_lz77 = kNumLZ77; while (lz77_nbits[num_lz77 - 1] == 0) { @@ -590,8 +589,8 @@ struct JxlFastLosslessFrameState { size_t JxlFastLosslessOutputSize(const JxlFastLosslessFrameState* frame) { size_t total_size_groups = 0; - for (size_t i = 0; i < frame->group_data.size(); i++) { - total_size_groups += SectionSize(frame->group_data[i]); + for (const auto& section : frame->group_data) { + total_size_groups += SectionSize(section); } return frame->header.bytes_written + total_size_groups; } @@ -719,11 +718,10 @@ void JxlFastLosslessPrepareHeader(JxlFastLosslessFrameState* frame, output->Write(1, 0); // No TOC permutation output->ZeroPadToByte(); // TOC is byte-aligned. assert(add_image_header || output->bytes_written <= kMaxFrameHeaderSize); - for (size_t i = 0; i < frame->group_sizes.size(); i++) { - size_t sz = frame->group_sizes[i]; - size_t bucket = TOCBucket(sz); + for (size_t group_size : frame->group_sizes) { + size_t bucket = TOCBucket(group_size); output->Write(2, bucket); - output->Write(kTOCBits[bucket] - 2, sz - kGroupSizeOffset[bucket]); + output->Write(kTOCBits[bucket] - 2, group_size - kGroupSizeOffset[bucket]); } output->ZeroPadToByte(); // Groups are byte-aligned. } diff --git a/third_party/jpeg-xl/lib/jxl/enc_frame.cc b/third_party/jpeg-xl/lib/jxl/enc_frame.cc index 8587e1aed2..2a3389921b 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_frame.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_frame.cc @@ -1786,8 +1786,8 @@ size_t TOCBucket(size_t group_size) { size_t TOCSize(const std::vector& group_sizes) { size_t toc_bits = 0; - for (size_t i = 0; i < group_sizes.size(); i++) { - toc_bits += kTOCBits[TOCBucket(group_sizes[i])]; + for (size_t group_size : group_sizes) { + toc_bits += kTOCBits[TOCBucket(group_size)]; } return (toc_bits + 7) / 8; } @@ -1795,8 +1795,8 @@ size_t TOCSize(const std::vector& group_sizes) { PaddedBytes EncodeTOC(const std::vector& group_sizes, AuxOut* aux_out) { BitWriter writer; BitWriter::Allotment allotment(&writer, 32 * group_sizes.size()); - for (size_t i = 0; i < group_sizes.size(); i++) { - JXL_CHECK(U32Coder::Write(kTocDist, group_sizes[i], &writer)); + for (size_t group_size : group_sizes) { + JXL_CHECK(U32Coder::Write(kTocDist, group_size, &writer)); } writer.ZeroPadToByte(); // before first group allotment.ReclaimAndCharge(&writer, kLayerTOC, aux_out); @@ -1854,13 +1854,13 @@ void RemoveUnusedHistograms(std::vector& context_map, EntropyEncodingData& codes) { std::vector remap(256, -1); std::vector inv_remap; - for (size_t i = 0; i < context_map.size(); ++i) { - const uint8_t histo_ix = context_map[i]; + for (uint8_t& context : context_map) { + const uint8_t histo_ix = context; if (remap[histo_ix] == -1) { remap[histo_ix] = inv_remap.size(); inv_remap.push_back(histo_ix); } - context_map[i] = remap[histo_ix]; + context = remap[histo_ix]; } EntropyEncodingData new_codes; new_codes.use_prefix_code = codes.use_prefix_code; diff --git a/third_party/jpeg-xl/lib/jxl/enc_group.cc b/third_party/jpeg-xl/lib/jxl/enc_group.cc index 1967fdaba9..2b60643e7c 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_group.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_group.cc @@ -43,7 +43,7 @@ using hwy::HWY_NAMESPACE::Round; void QuantizeBlockAC(const Quantizer& quantizer, const bool error_diffusion, size_t c, float qm_multiplier, size_t quant_kind, size_t xsize, size_t ysize, float* thresholds, - const float* JXL_RESTRICT block_in, int32_t* quant, + const float* JXL_RESTRICT block_in, const int32_t* quant, int32_t* JXL_RESTRICT block_out) { const float* JXL_RESTRICT qm = quantizer.InvDequantMatrix(quant_kind, c); float qac = quantizer.Scale() * (*quant); @@ -322,10 +322,8 @@ void QuantizeRoundtripYBlockAC(PassesEncoderState* enc_state, const size_t size, int quant_orig = *quant; float val[3] = {enc_state->x_qm_multiplier, 1.0f, enc_state->b_qm_multiplier}; - int clut[3] = {1, 0, 2}; - for (int ii = 0; ii < 3; ++ii) { + for (int c : {1, 0, 2}) { float thres[4] = {0.58f, 0.64f, 0.64f, 0.64f}; - int c = clut[ii]; *quant = quant_orig; AdjustQuantBlockAC(quantizer, c, val[c], quant_kind, xsize, ysize, &thres[0], inout + c * size, quant); diff --git a/third_party/jpeg-xl/lib/jxl/enc_icc_codec.cc b/third_party/jpeg-xl/lib/jxl/enc_icc_codec.cc index a29fb3f299..c3899600e5 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_icc_codec.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_icc_codec.cc @@ -127,8 +127,8 @@ Status PredictICC(const uint8_t* icc, size_t size, PaddedBytes* result) { } if (size <= kICCHeaderSize) { EncodeVarInt(0, result); // 0 commands - for (size_t i = 0; i < data.size(); i++) { - result->push_back(data[i]); + for (uint8_t b : data) { + result->push_back(b); } return true; } @@ -403,11 +403,11 @@ Status PredictICC(const uint8_t* icc, size_t size, PaddedBytes* result) { data.push_back(icc[last0++]); } } - for (size_t i = 0; i < commands_add.size(); i++) { - commands.push_back(commands_add[i]); + for (uint8_t b : commands_add) { + commands.push_back(b); } - for (size_t i = 0; i < data_add.size(); i++) { - data.push_back(data_add[i]); + for (uint8_t b : data_add) { + data.push_back(b); } last0 = pos; } @@ -417,11 +417,11 @@ Status PredictICC(const uint8_t* icc, size_t size, PaddedBytes* result) { } EncodeVarInt(commands.size(), result); - for (size_t i = 0; i < commands.size(); i++) { - result->push_back(commands[i]); + for (uint8_t b : commands) { + result->push_back(b); } - for (size_t i = 0; i < data.size(); i++) { - result->push_back(data[i]); + for (uint8_t b : data) { + result->push_back(b); } return true; diff --git a/third_party/jpeg-xl/lib/jxl/enc_modular.cc b/third_party/jpeg-xl/lib/jxl/enc_modular.cc index dbd62d4a01..35fac3c827 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_modular.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_modular.cc @@ -300,13 +300,12 @@ bool do_transform(Image& image, const Transform& tr, bool maybe_do_transform(Image& image, const Transform& tr, const CompressParams& cparams, - const weighted::Header& wp_header, + const weighted::Header& wp_header, float cost_before, jxl::ThreadPool* pool = nullptr, bool force_jxlart = false) { if (force_jxlart || cparams.speed_tier >= SpeedTier::kSquirrel) { return do_transform(image, tr, wp_header, pool, force_jxlart); } - float cost_before = EstimateCost(image); bool did_it = do_transform(image, tr, wp_header, pool); if (did_it) { float cost_after = EstimateCost(image); @@ -321,6 +320,110 @@ bool maybe_do_transform(Image& image, const Transform& tr, return did_it; } +void try_palettes(Image& gi, int& max_bitdepth, int& maxval, + const CompressParams& cparams_, float channel_colors_percent, + jxl::ThreadPool* pool = nullptr) { + float cost_before = 0.f; + size_t did_palette = 0; + float nb_pixels = gi.channel[0].w * gi.channel[0].h; + int nb_chans = gi.channel.size() - gi.nb_meta_channels; + // arbitrary estimate: 4.8 bpp for 8-bit RGB + float arbitrary_bpp_estimate = 0.2f * gi.bitdepth * nb_chans; + + if (cparams_.palette_colors != 0 || cparams_.lossy_palette) { + // when not estimating, assume some arbitrary bpp + cost_before = cparams_.speed_tier <= SpeedTier::kSquirrel + ? EstimateCost(gi) + : nb_pixels * arbitrary_bpp_estimate; + // all-channel palette (e.g. RGBA) + if (nb_chans > 1) { + Transform maybe_palette(TransformId::kPalette); + maybe_palette.begin_c = gi.nb_meta_channels; + maybe_palette.num_c = nb_chans; + // Heuristic choice of max colors for a palette: + // max_colors = nb_pixels * estimated_bpp_without_palette * 0.0005 + + // + nb_pixels / 128 + 128 + // (estimated_bpp_without_palette = cost_before / nb_pixels) + // Rationale: small image with large palette is not effective; + // also if the entropy (estimated bpp) is low (e.g. mostly solid/gradient + // areas), palette is less useful and may even be counterproductive. + maybe_palette.nb_colors = std::min( + static_cast(cost_before * 0.0005f + nb_pixels / 128 + 128), + std::abs(cparams_.palette_colors)); + maybe_palette.ordered_palette = cparams_.palette_colors >= 0; + maybe_palette.lossy_palette = + (cparams_.lossy_palette && maybe_palette.num_c == 3); + if (maybe_palette.lossy_palette) { + maybe_palette.predictor = Predictor::Average4; + } + // TODO(veluca): use a custom weighted header if using the weighted + // predictor. + if (maybe_do_transform(gi, maybe_palette, cparams_, weighted::Header(), + cost_before, pool, cparams_.options.zero_tokens)) { + did_palette = 1; + }; + } + // all-minus-one-channel palette (RGB with separate alpha, or CMY with + // separate K) + if (!did_palette && nb_chans > 3) { + Transform maybe_palette_3(TransformId::kPalette); + maybe_palette_3.begin_c = gi.nb_meta_channels; + maybe_palette_3.num_c = nb_chans - 1; + maybe_palette_3.nb_colors = std::min( + static_cast(cost_before * 0.0005f + nb_pixels / 128 + 128), + std::abs(cparams_.palette_colors)); + maybe_palette_3.ordered_palette = cparams_.palette_colors >= 0; + maybe_palette_3.lossy_palette = cparams_.lossy_palette; + if (maybe_palette_3.lossy_palette) { + maybe_palette_3.predictor = Predictor::Average4; + } + if (maybe_do_transform(gi, maybe_palette_3, cparams_, weighted::Header(), + cost_before, pool, cparams_.options.zero_tokens)) { + did_palette = 1; + } + } + } + + if (channel_colors_percent > 0) { + // single channel palette (like FLIF's ChannelCompact) + size_t nb_channels = gi.channel.size() - gi.nb_meta_channels - did_palette; + int orig_bitdepth = max_bitdepth; + max_bitdepth = 0; + if (nb_channels > 0 && (did_palette || cost_before == 0)) { + cost_before = + cparams_.speed_tier < SpeedTier::kSquirrel ? EstimateCost(gi) : 0; + } + for (size_t i = did_palette; i < nb_channels + did_palette; i++) { + int32_t min; + int32_t max; + compute_minmax(gi.channel[gi.nb_meta_channels + i], &min, &max); + int64_t colors = static_cast(max) - min + 1; + JXL_DEBUG_V(10, "Channel %" PRIuS ": range=%i..%i", i, min, max); + Transform maybe_palette_1(TransformId::kPalette); + maybe_palette_1.begin_c = i + gi.nb_meta_channels; + maybe_palette_1.num_c = 1; + // simple heuristic: if less than X percent of the values in the range + // actually occur, it is probably worth it to do a compaction + // (but only if the channel palette is less than 6% the size of the + // image itself) + maybe_palette_1.nb_colors = + std::min(static_cast(nb_pixels / 16), + static_cast(channel_colors_percent / 100. * colors)); + if (maybe_do_transform(gi, maybe_palette_1, cparams_, weighted::Header(), + cost_before, pool)) { + // effective bit depth is lower, adjust quantization accordingly + compute_minmax(gi.channel[gi.nb_meta_channels + i], &min, &max); + if (max < maxval) maxval = max; + int ch_bitdepth = + (max > 0 ? CeilLog2Nonzero(static_cast(max)) : 0); + if (ch_bitdepth > max_bitdepth) max_bitdepth = ch_bitdepth; + } else { + max_bitdepth = orig_bitdepth; + } + } + } +} + } // namespace ModularFrameEncoder::ModularFrameEncoder(const FrameHeader& frame_header, @@ -479,7 +582,6 @@ ModularFrameEncoder::ModularFrameEncoder(const FrameHeader& frame_header, cparams_.options.predictor = Predictor::Gradient; } } else { - delta_pred_ = cparams_.options.predictor; if (cparams_.lossy_palette) cparams_.options.predictor = Predictor::Zero; } if (!cparams_.ModularPartIsLossless()) { @@ -624,6 +726,7 @@ Status ModularFrameEncoder::ComputeEncodingData( pixel_type* const JXL_RESTRICT row_out = gi.channel[c_out].Row(y); pixel_type* const JXL_RESTRICT row_Y = gi.channel[0].Row(y); for (size_t x = 0; x < xsize; ++x) { + // TODO(eustas): check if std::roundf is appropriate row_out[x] = row_in[x] * factor + 0.5f; row_out[x] -= row_Y[x]; // zero the lsb of B @@ -720,81 +823,16 @@ Status ModularFrameEncoder::ComputeEncodingData( cparams_.lossy_palette = false; } - // Global palette - if ((cparams_.palette_colors != 0 || cparams_.lossy_palette) && !groupwise) { - // all-channel palette (e.g. RGBA) - if (gi.channel.size() - gi.nb_meta_channels > 1) { - Transform maybe_palette(TransformId::kPalette); - maybe_palette.begin_c = gi.nb_meta_channels; - maybe_palette.num_c = gi.channel.size() - gi.nb_meta_channels; - maybe_palette.nb_colors = std::min(static_cast(xsize * ysize / 2), - std::abs(cparams_.palette_colors)); - maybe_palette.ordered_palette = cparams_.palette_colors >= 0; - maybe_palette.lossy_palette = - (cparams_.lossy_palette && maybe_palette.num_c == 3); - if (maybe_palette.lossy_palette) { - maybe_palette.predictor = delta_pred_; - } - // TODO(veluca): use a custom weighted header if using the weighted - // predictor. - maybe_do_transform(gi, maybe_palette, cparams_, weighted::Header(), pool, - cparams_.options.zero_tokens); - } - // all-minus-one-channel palette (RGB with separate alpha, or CMY with - // separate K) - if (gi.channel.size() - gi.nb_meta_channels > 3) { - Transform maybe_palette_3(TransformId::kPalette); - maybe_palette_3.begin_c = gi.nb_meta_channels; - maybe_palette_3.num_c = gi.channel.size() - gi.nb_meta_channels - 1; - maybe_palette_3.nb_colors = std::min(static_cast(xsize * ysize / 3), - std::abs(cparams_.palette_colors)); - maybe_palette_3.ordered_palette = cparams_.palette_colors >= 0; - maybe_palette_3.lossy_palette = cparams_.lossy_palette; - if (maybe_palette_3.lossy_palette) { - maybe_palette_3.predictor = delta_pred_; - } - maybe_do_transform(gi, maybe_palette_3, cparams_, weighted::Header(), - pool, cparams_.options.zero_tokens); - } - } - - // Global channel palette - if (!groupwise && cparams_.channel_colors_pre_transform_percent > 0 && - !cparams_.lossy_palette && + // Global palette transforms + float channel_colors_percent = 0; + if (!cparams_.lossy_palette && (cparams_.speed_tier <= SpeedTier::kThunder || (do_color && metadata.bit_depth.bits_per_sample > 8))) { - // single channel palette (like FLIF's ChannelCompact) - size_t nb_channels = gi.channel.size() - gi.nb_meta_channels; - int orig_bitdepth = max_bitdepth; - max_bitdepth = 0; - for (size_t i = 0; i < nb_channels; i++) { - int32_t min; - int32_t max; - compute_minmax(gi.channel[gi.nb_meta_channels + i], &min, &max); - int64_t colors = static_cast(max) - min + 1; - JXL_DEBUG_V(10, "Channel %" PRIuS ": range=%i..%i", i, min, max); - Transform maybe_palette_1(TransformId::kPalette); - maybe_palette_1.begin_c = i + gi.nb_meta_channels; - maybe_palette_1.num_c = 1; - // simple heuristic: if less than X percent of the values in the range - // actually occur, it is probably worth it to do a compaction - // (but only if the channel palette is less than 6% the size of the - // image itself) - maybe_palette_1.nb_colors = std::min( - static_cast(xsize * ysize / 16), - static_cast(cparams_.channel_colors_pre_transform_percent / - 100. * colors)); - if (maybe_do_transform(gi, maybe_palette_1, cparams_, weighted::Header(), - pool)) { - // effective bit depth is lower, adjust quantization accordingly - compute_minmax(gi.channel[gi.nb_meta_channels + i], &min, &max); - if (max < maxval) maxval = max; - int ch_bitdepth = - (max > 0 ? CeilLog2Nonzero(static_cast(max)) : 0); - if (ch_bitdepth > max_bitdepth) max_bitdepth = ch_bitdepth; - } else - max_bitdepth = orig_bitdepth; - } + channel_colors_percent = cparams_.channel_colors_pre_transform_percent; + } + if (!groupwise) { + try_palettes(gi, max_bitdepth, maxval, cparams_, channel_colors_percent, + pool); } // don't do an RCT if we're short on bits @@ -1318,61 +1356,17 @@ Status ModularFrameEncoder::PrepareStreamParams(const Rect& rect, if (gi.channel.empty()) return true; // Do some per-group transforms - // Local palette + // Local palette transforms // TODO(veluca): make this work with quantize-after-prediction in lossy // mode. - if (cparams_.butteraugli_distance == 0.f && cparams_.palette_colors != 0 && + if (cparams_.butteraugli_distance == 0.f && !cparams_.lossy_palette && cparams_.speed_tier < SpeedTier::kCheetah) { - // all-channel palette (e.g. RGBA) - if (gi.channel.size() - gi.nb_meta_channels > 1) { - Transform maybe_palette(TransformId::kPalette); - maybe_palette.begin_c = gi.nb_meta_channels; - maybe_palette.num_c = gi.channel.size() - gi.nb_meta_channels; - maybe_palette.nb_colors = std::abs(cparams_.palette_colors); - maybe_palette.ordered_palette = cparams_.palette_colors >= 0; - maybe_do_transform(gi, maybe_palette, cparams_, weighted::Header()); - } - // all-minus-one-channel palette (RGB with separate alpha, or CMY with - // separate K) - if (gi.channel.size() - gi.nb_meta_channels > 3) { - Transform maybe_palette_3(TransformId::kPalette); - maybe_palette_3.begin_c = gi.nb_meta_channels; - maybe_palette_3.num_c = gi.channel.size() - gi.nb_meta_channels - 1; - maybe_palette_3.nb_colors = std::abs(cparams_.palette_colors); - maybe_palette_3.ordered_palette = cparams_.palette_colors >= 0; - maybe_palette_3.lossy_palette = cparams_.lossy_palette; - if (maybe_palette_3.lossy_palette) { - maybe_palette_3.predictor = Predictor::Weighted; - } - maybe_do_transform(gi, maybe_palette_3, cparams_, weighted::Header()); - } - } - - // Local channel palette - if (cparams_.channel_colors_percent > 0 && - cparams_.butteraugli_distance == 0.f && !cparams_.lossy_palette && - cparams_.speed_tier < SpeedTier::kCheetah && - !(cparams_.responsive && cparams_.decoding_speed_tier >= 1)) { - // single channel palette (like FLIF's ChannelCompact) - size_t nb_channels = gi.channel.size() - gi.nb_meta_channels; - for (size_t i = 0; i < nb_channels; i++) { - int32_t min; - int32_t max; - compute_minmax(gi.channel[gi.nb_meta_channels + i], &min, &max); - int64_t colors = static_cast(max) - min + 1; - JXL_DEBUG_V(10, "Channel %" PRIuS ": range=%i..%i", i, min, max); - Transform maybe_palette_1(TransformId::kPalette); - maybe_palette_1.begin_c = i + gi.nb_meta_channels; - maybe_palette_1.num_c = 1; - // simple heuristic: if less than X percent of the values in the range - // actually occur, it is probably worth it to do a compaction - // (but only if the channel palette is less than 80% the size of the - // image itself) - maybe_palette_1.nb_colors = std::min( - static_cast(xsize * ysize * 0.8), - static_cast(cparams_.channel_colors_percent / 100. * colors)); - maybe_do_transform(gi, maybe_palette_1, cparams_, weighted::Header()); + int max_bitdepth = 0, maxval = 0; // don't care about that here + float channel_color_percent = 0; + if (!(cparams_.responsive && cparams_.decoding_speed_tier >= 1)) { + channel_color_percent = cparams_.channel_colors_percent; } + try_palettes(gi, max_bitdepth, maxval, cparams_, channel_color_percent); } } diff --git a/third_party/jpeg-xl/lib/jxl/enc_modular.h b/third_party/jpeg-xl/lib/jxl/enc_modular.h index 8e2015b226..c7a8421982 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_modular.h +++ b/third_party/jpeg-xl/lib/jxl/enc_modular.h @@ -107,7 +107,6 @@ class ModularFrameEncoder { std::vector tree_splits_; std::vector> gi_channel_; std::vector image_widths_; - Predictor delta_pred_ = Predictor::Average4; struct GroupParams { Rect rect; diff --git a/third_party/jpeg-xl/lib/jxl/enc_params.h b/third_party/jpeg-xl/lib/jxl/enc_params.h index 162c59d04c..5e3ff7789c 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_params.h +++ b/third_party/jpeg-xl/lib/jxl/enc_params.h @@ -106,9 +106,12 @@ struct CompressParams { // modular mode options below ModularOptions options; + + // TODO(eustas): use Override? int responsive = -1; int colorspace = -1; int move_to_front_from_channel = -1; + // Use Global channel palette if #colors < this percentage of range float channel_colors_pre_transform_percent = 95.f; // Use Local channel palette if #colors < this percentage of range diff --git a/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc b/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc index f19ba0dd9e..6fc5f7f49e 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc @@ -237,9 +237,9 @@ StatusOr> FindTextLikePatches( auto is_same = [&opsin_rows, opsin_stride](std::pair p1, std::pair p2) { - for (size_t c = 0; c < 3; c++) { - float v1 = opsin_rows[c][p1.second * opsin_stride + p1.first]; - float v2 = opsin_rows[c][p2.second * opsin_stride + p2.first]; + for (auto& opsin_row : opsin_rows) { + float v1 = opsin_row[p1.second * opsin_stride + p1.first]; + float v2 = opsin_row[p2.second * opsin_stride + p2.first]; if (std::fabs(v1 - v2) > 1e-4) { return false; } @@ -556,8 +556,8 @@ StatusOr> FindTextLikePatches( size_t max_patch_size = 0; - for (size_t i = 0; i < info.size(); i++) { - size_t pixels = info[i].first.xsize * info[i].first.ysize; + for (const auto& patch : info) { + size_t pixels = patch.first.xsize * patch.first.ysize; if (pixels > max_patch_size) max_patch_size = pixels; } @@ -605,10 +605,10 @@ Status FindBestPatchDictionary(const Image3F& opsin, size_t max_y_size = 0; size_t total_pixels = 0; - for (size_t i = 0; i < info.size(); i++) { - size_t pixels = info[i].first.xsize * info[i].first.ysize; - if (max_x_size < info[i].first.xsize) max_x_size = info[i].first.xsize; - if (max_y_size < info[i].first.ysize) max_y_size = info[i].first.ysize; + for (const auto& patch : info) { + size_t pixels = patch.first.xsize * patch.first.ysize; + if (max_x_size < patch.first.xsize) max_x_size = patch.first.xsize; + if (max_y_size < patch.first.ysize) max_y_size = patch.first.ysize; total_pixels += pixels; } diff --git a/third_party/jpeg-xl/lib/jxl/enc_quant_weights.cc b/third_party/jpeg-xl/lib/jxl/enc_quant_weights.cc index 35e49d5993..978dfd5925 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_quant_weights.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_quant_weights.cc @@ -116,9 +116,9 @@ Status DequantMatricesEncode(const DequantMatrices& matrices, BitWriter* writer, bool all_default = true; const std::vector& encodings = matrices.encodings(); - for (size_t i = 0; i < encodings.size(); i++) { - if (encodings[i].mode != QuantEncoding::kQuantModeLibrary || - encodings[i].predefined != 0) { + for (const auto& encoding : encodings) { + if (encoding.mode != QuantEncoding::kQuantModeLibrary || + encoding.predefined != 0) { all_default = false; } } diff --git a/third_party/jpeg-xl/lib/jxl/enc_splines.cc b/third_party/jpeg-xl/lib/jxl/enc_splines.cc index fa15648ca5..186f19da93 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_splines.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_splines.cc @@ -34,8 +34,8 @@ class QuantizedSplineEncoder { tokens->emplace_back(kDCTContext, PackSigned(dct[i])); } }; - for (int c = 0; c < 3; ++c) { - encode_dct(spline.color_dct_[c]); + for (const auto& dct : spline.color_dct_) { + encode_dct(dct); } encode_dct(spline.sigma_dct_); } diff --git a/third_party/jpeg-xl/lib/jxl/enc_toc.cc b/third_party/jpeg-xl/lib/jxl/enc_toc.cc index e79298ef31..4ecba8fdb1 100644 --- a/third_party/jpeg-xl/lib/jxl/enc_toc.cc +++ b/third_party/jpeg-xl/lib/jxl/enc_toc.cc @@ -32,9 +32,9 @@ Status WriteGroupOffsets(const std::vector& group_codes, } writer->ZeroPadToByte(); // before TOC entries - for (size_t i = 0; i < group_codes.size(); i++) { - JXL_ASSERT(group_codes[i].BitsWritten() % kBitsPerByte == 0); - const size_t group_size = group_codes[i].BitsWritten() / kBitsPerByte; + for (const auto& bw : group_codes) { + JXL_ASSERT(bw.BitsWritten() % kBitsPerByte == 0); + const size_t group_size = bw.BitsWritten() / kBitsPerByte; JXL_RETURN_IF_ERROR(U32Coder::Write(kTocDist, group_size, writer)); } writer->ZeroPadToByte(); // before first group diff --git a/third_party/jpeg-xl/lib/jxl/encode.cc b/third_party/jpeg-xl/lib/jxl/encode.cc index 4dbbeba4e7..28a925dfc1 100644 --- a/third_party/jpeg-xl/lib/jxl/encode.cc +++ b/third_party/jpeg-xl/lib/jxl/encode.cc @@ -549,8 +549,8 @@ int VerifyLevelSettings(const JxlEncoder* enc, std::string* debug_string) { if (debug_string) *debug_string = "Too many extra channels"; return 10; } - for (size_t i = 0; i < m.extra_channel_info.size(); ++i) { - if (m.extra_channel_info[i].type == jxl::ExtraChannel::kBlack) { + for (const auto& eci : m.extra_channel_info) { + if (eci.type == jxl::ExtraChannel::kBlack) { if (debug_string) *debug_string = "CMYK channel not allowed"; return 10; } @@ -1514,6 +1514,10 @@ float JxlEncoderDistanceFromQuality(float quality) { JxlEncoderStatus JxlEncoderFrameSettingsSetOption( JxlEncoderFrameSettings* frame_settings, JxlEncoderFrameSettingId option, int64_t value) { + // Tri-state to bool convertors. + const auto default_to_true = [](int64_t v) { return v != 0; }; + const auto default_to_false = [](int64_t v) { return v == 1; }; + // check if value is -1, 0 or 1 for Override-type options switch (option) { case JXL_ENC_FRAME_SETTING_NOISE: @@ -1680,7 +1684,7 @@ JxlEncoderStatus JxlEncoderFrameSettingsSetOption( // See the logic in cjxl. Similar for other settings. This should be // handled in the encoder during JxlEncoderProcessOutput (or, // alternatively, in the cjxl binary like now) - frame_settings->values.cparams.lossy_palette = (value == 1); + frame_settings->values.cparams.lossy_palette = default_to_false(value); break; case JXL_ENC_FRAME_SETTING_COLOR_TRANSFORM: if (value < -1 || value > 2) { @@ -1734,11 +1738,8 @@ JxlEncoderStatus JxlEncoderFrameSettingsSetOption( } break; case JXL_ENC_FRAME_SETTING_JPEG_RECON_CFL: - if (value == -1) { - frame_settings->values.cparams.force_cfl_jpeg_recompression = true; - } else { - frame_settings->values.cparams.force_cfl_jpeg_recompression = value; - } + frame_settings->values.cparams.force_cfl_jpeg_recompression = + default_to_true(value); break; case JXL_ENC_FRAME_INDEX_BOX: if (value < 0 || value > 1) { @@ -1752,7 +1753,8 @@ JxlEncoderStatus JxlEncoderFrameSettingsSetOption( "Float option, try setting it with " "JxlEncoderFrameSettingsSetFloatOption"); case JXL_ENC_FRAME_SETTING_JPEG_COMPRESS_BOXES: - frame_settings->values.cparams.jpeg_compress_boxes = value; + frame_settings->values.cparams.jpeg_compress_boxes = + default_to_true(value); break; case JXL_ENC_FRAME_SETTING_BUFFERING: if (value < -1 || value > 3) { @@ -1762,20 +1764,21 @@ JxlEncoderStatus JxlEncoderFrameSettingsSetOption( frame_settings->values.cparams.buffering = value; break; case JXL_ENC_FRAME_SETTING_JPEG_KEEP_EXIF: - frame_settings->values.cparams.jpeg_keep_exif = value; + frame_settings->values.cparams.jpeg_keep_exif = default_to_true(value); break; case JXL_ENC_FRAME_SETTING_JPEG_KEEP_XMP: - frame_settings->values.cparams.jpeg_keep_xmp = value; + frame_settings->values.cparams.jpeg_keep_xmp = default_to_true(value); break; case JXL_ENC_FRAME_SETTING_JPEG_KEEP_JUMBF: - frame_settings->values.cparams.jpeg_keep_jumbf = value; + frame_settings->values.cparams.jpeg_keep_jumbf = default_to_true(value); break; case JXL_ENC_FRAME_SETTING_USE_FULL_IMAGE_HEURISTICS: if (value < 0 || value > 1) { return JXL_API_ERROR(frame_settings->enc, JXL_ENC_ERR_NOT_SUPPORTED, "Option value has to be 0 or 1"); } - frame_settings->values.cparams.use_full_image_heuristics = value; + frame_settings->values.cparams.use_full_image_heuristics = + default_to_false(value); break; default: diff --git a/third_party/jpeg-xl/lib/jxl/encode_test.cc b/third_party/jpeg-xl/lib/jxl/encode_test.cc index 3e519cc45d..0aef5f8aff 100644 --- a/third_party/jpeg-xl/lib/jxl/encode_test.cc +++ b/third_party/jpeg-xl/lib/jxl/encode_test.cc @@ -304,7 +304,7 @@ TEST(EncodeTest, CmsTest) { EXPECT_TRUE(cms_called); } -TEST(EncodeTest, frame_settingsTest) { +TEST(EncodeTest, FrameSettingsTest) { { JxlEncoderPtr enc = JxlEncoderMake(nullptr); EXPECT_NE(nullptr, enc.get()); @@ -451,7 +451,7 @@ TEST(EncodeTest, frame_settingsTest) { JxlEncoderFrameSettingsCreate(enc.get(), nullptr); EXPECT_EQ(JXL_ENC_SUCCESS, JxlEncoderSetFrameLossless(frame_settings, JXL_TRUE)); - VerifyFrameEncoding(63, 129, enc.get(), frame_settings, 3000, false); + VerifyFrameEncoding(63, 129, enc.get(), frame_settings, 3600, false); EXPECT_EQ(true, enc->last_used_cparams.IsLossless()); } @@ -838,20 +838,20 @@ TEST(EncodeTest, SingleFrameBoundedJXLCTest) { bool found_jxlc = false; bool found_jxlp = false; // The encoder is allowed to either emit a jxlc or one or more jxlp. - for (size_t i = 0; i < container.boxes.size(); ++i) { - if (memcmp("jxlc", container.boxes[i].type, 4) == 0) { + for (const auto& box : container.boxes) { + if (memcmp("jxlc", box.type, 4) == 0) { EXPECT_EQ(false, found_jxlc); // Max 1 jxlc EXPECT_EQ(false, found_jxlp); // Can't mix jxlc and jxlp found_jxlc = true; } - if (memcmp("jxlp", container.boxes[i].type, 4) == 0) { + if (memcmp("jxlp", box.type, 4) == 0) { EXPECT_EQ(false, found_jxlc); // Can't mix jxlc and jxlp found_jxlp = true; } // The encoder shouldn't create an unbounded box in this case, with the // single frame it knows the full size in time, so can help make decoding // more efficient by giving the full box size of the final box. - EXPECT_EQ(true, container.boxes[i].data_size_given); + EXPECT_EQ(true, box.data_size_given); } EXPECT_EQ(true, found_jxlc || found_jxlp); } @@ -940,7 +940,7 @@ TEST(EncodeTest, CodestreamLevelVerificationTest) { EXPECT_EQ(JXL_ENC_ERROR, JxlEncoderSetBasicInfo(enc.get(), &basic_info)); } -TEST(EncodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructionTest)) { +JXL_TRANSCODE_JPEG_TEST(EncodeTest, JPEGReconstructionTest) { const std::string jpeg_path = "jxl/flower/flower.png.im_q85_420.jpg"; const std::vector orig = jxl::test::ReadTestData(jpeg_path); @@ -980,7 +980,7 @@ TEST(EncodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGReconstructionTest)) { EXPECT_EQ(0, memcmp(decoded_jpeg_bytes.data(), orig.data(), orig.size())); } -TEST(EncodeTest, JXL_TRANSCODE_JPEG_TEST(ProgressiveJPEGReconstructionTest)) { +JXL_TRANSCODE_JPEG_TEST(EncodeTest, ProgressiveJPEGReconstructionTest) { const std::string jpeg_path = "jxl/flower/flower.png.im_q85_420.jpg"; const std::vector orig = jxl::test::ReadTestData(jpeg_path); @@ -1345,7 +1345,7 @@ TEST(EncodeTest, CroppedFrameTest) { struct EncodeBoxTest : public testing::TestWithParam> { }; -TEST_P(EncodeBoxTest, JXL_BOXES_TEST(BoxTest)) { +JXL_BOXES_TEST_P(EncodeBoxTest, BoxTest) { // Test with uncompressed boxes and with brob boxes bool compress_box = std::get<0>(GetParam()); size_t xml_box_size = std::get<1>(GetParam()); @@ -1485,7 +1485,7 @@ JXL_GTEST_INSTANTIATE_TEST_SUITE_P( jxl::kLargeBoxContentSizeThreshold + 77)), nameBoxTest); -TEST(EncodeTest, JXL_TRANSCODE_JPEG_TEST(JPEGFrameTest)) { +JXL_TRANSCODE_JPEG_TEST(EncodeTest, JPEGFrameTest) { TEST_LIBJPEG_SUPPORT(); for (int skip_basic_info = 0; skip_basic_info < 2; skip_basic_info++) { for (int skip_color_encoding = 0; skip_color_encoding < 2; diff --git a/third_party/jpeg-xl/lib/jxl/entropy_coder_test.cc b/third_party/jpeg-xl/lib/jxl/entropy_coder_test.cc index d32fe1b26b..0389490d8e 100644 --- a/third_party/jpeg-xl/lib/jxl/entropy_coder_test.cc +++ b/third_party/jpeg-xl/lib/jxl/entropy_coder_test.cc @@ -27,7 +27,7 @@ TEST(EntropyCoderTest, PackUnpack) { struct MockBitReader { uint32_t nbits, bits; void Consume(uint32_t nbits) {} - uint32_t PeekBits(uint32_t n) { + uint32_t PeekBits(uint32_t n) const { EXPECT_EQ(n, nbits); return bits; } diff --git a/third_party/jpeg-xl/lib/jxl/gradient_test.cc b/third_party/jpeg-xl/lib/jxl/gradient_test.cc index d2c83619fc..e09b34603f 100644 --- a/third_party/jpeg-xl/lib/jxl/gradient_test.cc +++ b/third_party/jpeg-xl/lib/jxl/gradient_test.cc @@ -186,13 +186,13 @@ constexpr bool fast_mode = true; TEST(GradientTest, SteepGradient) { test::ThreadPoolForTests pool(8); // Relatively steep gradients, colors from the sky of stp.png - TestGradient(&pool, 0xd99d58, 0x889ab1, 512, 512, 90, fast_mode, 3.0); + TestGradient(pool.get(), 0xd99d58, 0x889ab1, 512, 512, 90, fast_mode, 3.0); } TEST(GradientTest, SubtleGradient) { test::ThreadPoolForTests pool(8); // Very subtle gradient - TestGradient(&pool, 0xb89b7b, 0xa89b8d, 512, 512, 90, fast_mode, 4.0); + TestGradient(pool.get(), 0xb89b7b, 0xa89b8d, 512, 512, 90, fast_mode, 4.0); } } // namespace diff --git a/third_party/jpeg-xl/lib/jxl/icc_codec.h b/third_party/jpeg-xl/lib/jxl/icc_codec.h index 8b880c7d3b..3b0b0c041b 100644 --- a/third_party/jpeg-xl/lib/jxl/icc_codec.h +++ b/third_party/jpeg-xl/lib/jxl/icc_codec.h @@ -28,7 +28,7 @@ struct ICCReader { } private: - Status CheckEOI(BitReader* reader); + static Status CheckEOI(BitReader* reader); size_t i_ = 0; size_t bits_to_skip_ = 0; size_t used_bits_base_ = 0; diff --git a/third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data.cc b/third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data.cc index 9763786453..a971eb3dcc 100644 --- a/third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data.cc +++ b/third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data.cc @@ -106,15 +106,14 @@ Status DecodeJPEGData(Span encoded, JPEGData* jpeg_data) { } } // TODO(eustas): actually inject ICC profile and check it fits perfectly. - for (size_t i = 0; i < jpeg_data->com_data.size(); i++) { - auto& marker = jpeg_data->com_data[i]; + for (auto& marker : jpeg_data->com_data) { JXL_RETURN_IF_ERROR(br_read(marker)); if (marker[1] * 256u + marker[2] + 1u != marker.size()) { return JXL_FAILURE("Incorrect marker size"); } } - for (size_t i = 0; i < jpeg_data->inter_marker_data.size(); i++) { - JXL_RETURN_IF_ERROR(br_read(jpeg_data->inter_marker_data[i])); + for (auto& data : jpeg_data->inter_marker_data) { + JXL_RETURN_IF_ERROR(br_read(data)); } JXL_RETURN_IF_ERROR(br_read(jpeg_data->tail_data)); diff --git a/third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data_writer.cc b/third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data_writer.cc index 31bb2dda23..77c8b885e1 100644 --- a/third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data_writer.cc +++ b/third_party/jpeg-xl/lib/jxl/jpeg/dec_jpeg_data_writer.cc @@ -385,8 +385,8 @@ bool EncodeDHT(const JPEGData& jpg, SerializationState* state) { for (size_t i = state->dht_index; i < huffman_code.size(); ++i) { const JPEGHuffmanCode& huff = huffman_code[i]; marker_len += kJpegHuffmanMaxBitLength; - for (size_t j = 0; j < huff.counts.size(); ++j) { - marker_len += huff.counts[j]; + for (uint32_t count : huff.counts) { + marker_len += count; } if (huff.is_last) break; } diff --git a/third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data.cc b/third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data.cc index d311908415..d7c6c2ad78 100644 --- a/third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data.cc +++ b/third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data.cc @@ -173,8 +173,7 @@ Status ParseChunkedMarker(const jpeg::JPEGData& src, uint8_t marker_type, } Status SetBlobsFromJpegData(const jpeg::JPEGData& jpeg_data, Blobs* blobs) { - for (size_t i = 0; i < jpeg_data.app_data.size(); i++) { - const auto& marker = jpeg_data.app_data[i]; + for (const auto& marker : jpeg_data.app_data) { if (marker.empty() || marker[0] != kApp1) { continue; } @@ -318,11 +317,11 @@ Status EncodeJPEGData(JPEGData& jpeg_data, std::vector* bytes, } total_data += jpeg_data.app_data[i].size(); } - for (size_t i = 0; i < jpeg_data.com_data.size(); i++) { - total_data += jpeg_data.com_data[i].size(); + for (const auto& data : jpeg_data.com_data) { + total_data += data.size(); } - for (size_t i = 0; i < jpeg_data.inter_marker_data.size(); i++) { - total_data += jpeg_data.inter_marker_data[i].size(); + for (const auto& data : jpeg_data.inter_marker_data) { + total_data += data.size(); } total_data += jpeg_data.tail_data.size(); size_t brotli_capacity = BrotliEncoderMaxCompressedSize(total_data); @@ -365,11 +364,11 @@ Status EncodeJPEGData(JPEGData& jpeg_data, std::vector* bytes, } br_append(jpeg_data.app_data[i], /*last=*/false); } - for (size_t i = 0; i < jpeg_data.com_data.size(); i++) { - br_append(jpeg_data.com_data[i], /*last=*/false); + for (const auto& data : jpeg_data.com_data) { + br_append(data, /*last=*/false); } - for (size_t i = 0; i < jpeg_data.inter_marker_data.size(); i++) { - br_append(jpeg_data.inter_marker_data[i], /*last=*/false); + for (const auto& data : jpeg_data.inter_marker_data) { + br_append(data, /*last=*/false); } br_append(jpeg_data.tail_data, /*last=*/true); BrotliEncoderDestroyInstance(brotli_enc); diff --git a/third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data_reader.cc b/third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data_reader.cc index d1e8476db6..8208bba675 100644 --- a/third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data_reader.cc +++ b/third_party/jpeg-xl/lib/jxl/jpeg/enc_jpeg_data_reader.cc @@ -92,21 +92,21 @@ bool ProcessSOF(const uint8_t* data, const size_t len, JpegReadMode mode, std::vector ids_seen(256, false); int max_h_samp_factor = 1; int max_v_samp_factor = 1; - for (size_t i = 0; i < jpg->components.size(); ++i) { + for (auto& component : jpg->components) { const int id = ReadUint8(data, pos); if (ids_seen[id]) { // (cf. section B.2.2, syntax of Ci) return JXL_FAILURE("Duplicate ID %d in SOF.", id); } ids_seen[id] = true; - jpg->components[i].id = id; + component.id = id; int factor = ReadUint8(data, pos); int h_samp_factor = factor >> 4; int v_samp_factor = factor & 0xf; JXL_JPEG_VERIFY_INPUT(h_samp_factor, 1, kBrunsliMaxSampling, SAMP_FACTOR); JXL_JPEG_VERIFY_INPUT(v_samp_factor, 1, kBrunsliMaxSampling, SAMP_FACTOR); - jpg->components[i].h_samp_factor = h_samp_factor; - jpg->components[i].v_samp_factor = v_samp_factor; - jpg->components[i].quant_idx = ReadUint8(data, pos); + component.h_samp_factor = h_samp_factor; + component.v_samp_factor = v_samp_factor; + component.quant_idx = ReadUint8(data, pos); max_h_samp_factor = std::max(max_h_samp_factor, h_samp_factor); max_v_samp_factor = std::max(max_v_samp_factor, v_samp_factor); } @@ -116,18 +116,17 @@ bool ProcessSOF(const uint8_t* data, const size_t len, JpegReadMode mode, int MCU_rows = DivCeil(jpg->height, max_v_samp_factor * 8); int MCU_cols = DivCeil(jpg->width, max_h_samp_factor * 8); // Compute the block dimensions for each component. - for (size_t i = 0; i < jpg->components.size(); ++i) { - JPEGComponent* c = &jpg->components[i]; - if (max_h_samp_factor % c->h_samp_factor != 0 || - max_v_samp_factor % c->v_samp_factor != 0) { + for (JPEGComponent& c : jpg->components) { + if (max_h_samp_factor % c.h_samp_factor != 0 || + max_v_samp_factor % c.v_samp_factor != 0) { return JXL_FAILURE("Non-integral subsampling ratios."); } - c->width_in_blocks = MCU_cols * c->h_samp_factor; - c->height_in_blocks = MCU_rows * c->v_samp_factor; + c.width_in_blocks = MCU_cols * c.h_samp_factor; + c.height_in_blocks = MCU_rows * c.v_samp_factor; const uint64_t num_blocks = - static_cast(c->width_in_blocks) * c->height_in_blocks; + static_cast(c.width_in_blocks) * c.height_in_blocks; if (mode == JpegReadMode::kReadAll) { - c->coeffs.resize(num_blocks * kDCTBlockSize); + c.coeffs.resize(num_blocks * kDCTBlockSize); } } JXL_JPEG_VERIFY_MARKER_END(); @@ -192,8 +191,8 @@ bool ProcessSOS(const uint8_t* data, const size_t len, size_t* pos, for (size_t i = 0; i < comps_in_scan; ++i) { bool found_dc_table = false; bool found_ac_table = false; - for (size_t j = 0; j < jpg->huffman_code.size(); ++j) { - uint32_t slot_id = jpg->huffman_code[j].slot_id; + for (const auto& code : jpg->huffman_code) { + uint32_t slot_id = code.slot_id; if (slot_id == scan_info.components[i].dc_tbl_idx) { found_dc_table = true; } else if (slot_id == scan_info.components[i].ac_tbl_idx + 16) { @@ -757,11 +756,9 @@ bool ProcessScan(const uint8_t* data, const size_t len, bool is_interleaved = (scan_info->num_components > 1); int max_h_samp_factor = 1; int max_v_samp_factor = 1; - for (size_t i = 0; i < jpg->components.size(); ++i) { - max_h_samp_factor = - std::max(max_h_samp_factor, jpg->components[i].h_samp_factor); - max_v_samp_factor = - std::max(max_v_samp_factor, jpg->components[i].v_samp_factor); + for (const auto& component : jpg->components) { + max_h_samp_factor = std::max(max_h_samp_factor, component.h_samp_factor); + max_v_samp_factor = std::max(max_v_samp_factor, component.v_samp_factor); } int MCU_rows = DivCeil(jpg->height, max_v_samp_factor * 8); diff --git a/third_party/jpeg-xl/lib/jxl/jpeg/jpeg_data.cc b/third_party/jpeg-xl/lib/jxl/jpeg/jpeg_data.cc index aeb9914cca..3217115acb 100644 --- a/third_party/jpeg-xl/lib/jxl/jpeg/jpeg_data.cc +++ b/third_party/jpeg-xl/lib/jxl/jpeg/jpeg_data.cc @@ -78,8 +78,8 @@ Status JPEGData::VisitFields(Visitor* visitor) { if (marker_order.size() > 16384) { return JXL_FAILURE("Too many markers: %" PRIuS "\n", marker_order.size()); } - for (size_t i = 0; i < marker_order.size(); i++) { - JXL_RETURN_IF_ERROR(VisitMarker(&marker_order[i], visitor, &info)); + for (uint8_t& marker : marker_order) { + JXL_RETURN_IF_ERROR(VisitMarker(&marker, visitor, &info)); } if (!marker_order.empty()) { // Last marker should always be EOI marker. @@ -175,8 +175,8 @@ Status JPEGData::VisitFields(Visitor* visitor) { components.resize(num_components); } if (component_type == JPEGComponentType::kCustom) { - for (size_t i = 0; i < components.size(); i++) { - JXL_RETURN_IF_ERROR(visitor->Bits(8, 0, &components[i].id)); + for (auto& component : components) { + JXL_RETURN_IF_ERROR(visitor->Bits(8, 0, &component.id)); } } else if (component_type == JPEGComponentType::kGray) { components[0].id = 1; @@ -322,11 +322,11 @@ Status JPEGData::VisitFields(Visitor* visitor) { scan.extra_zero_runs.resize(num_extra_zero_runs); } last_block_idx = -1; - for (size_t i = 0; i < scan.extra_zero_runs.size(); ++i) { - uint32_t& block_idx = scan.extra_zero_runs[i].block_idx; - JXL_RETURN_IF_ERROR(visitor->U32( - Val(1), BitsOffset(2, 2), BitsOffset(4, 5), BitsOffset(8, 20), 1, - &scan.extra_zero_runs[i].num_extra_zero_runs)); + for (auto& extra_zero_run : scan.extra_zero_runs) { + uint32_t& block_idx = extra_zero_run.block_idx; + JXL_RETURN_IF_ERROR(visitor->U32(Val(1), BitsOffset(2, 2), + BitsOffset(4, 5), BitsOffset(8, 20), 1, + &extra_zero_run.num_extra_zero_runs)); block_idx -= last_block_idx + 1; JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(3, 1), BitsOffset(5, 9), BitsOffset(28, 41), 0, diff --git a/third_party/jpeg-xl/lib/jxl/jxl_test.cc b/third_party/jpeg-xl/lib/jxl/jxl_test.cc index b0933d5d50..cf9857f462 100644 --- a/third_party/jpeg-xl/lib/jxl/jxl_test.cc +++ b/third_party/jpeg-xl/lib/jxl/jxl_test.cc @@ -179,7 +179,8 @@ TEST(JxlTest, RoundtripResample2MT) { cparams.AddOption(JXL_ENC_FRAME_SETTING_EFFORT, 3); // kFalcon PackedPixelFile ppf_out; - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, &pool, &ppf_out), 203300, 2000); + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf_out), 203300, + 2000); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 340); } @@ -286,8 +287,8 @@ TEST(JxlTest, RoundtripMultiGroup) { cparams.distance = target_distance; PackedPixelFile ppf_out; - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, &pool, &ppf_out), expected_size, - 700); + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf_out), + expected_size, 700); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), expected_distance); }; @@ -302,7 +303,7 @@ TEST(JxlTest, RoundtripRGBToGrayscale) { ThreadPoolForTests pool(4); const std::vector orig = ReadTestData("jxl/flower/flower.png"); CodecInOut io; - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, pool.get())); io.ShrinkTo(600, 1024); CompressParams cparams; @@ -316,7 +317,7 @@ TEST(JxlTest, RoundtripRGBToGrayscale) { EXPECT_FALSE(io.Main().IsGray()); size_t compressed_size; JXL_EXPECT_OK( - Roundtrip(&io, cparams, dparams, &io2, _, &compressed_size, &pool)); + Roundtrip(&io, cparams, dparams, &io2, _, &compressed_size, pool.get())); EXPECT_LE(compressed_size, 65000u); EXPECT_TRUE(io2.Main().IsGray()); @@ -341,7 +342,7 @@ TEST(JxlTest, RoundtripRGBToGrayscale) { EXPECT_SLIGHTLY_BELOW( ButteraugliDistance(io.frames, io2.frames, ButteraugliParams(), *JxlGetDefaultCms(), - /*distmap=*/nullptr, &pool), + /*distmap=*/nullptr, pool.get()), 1.4); } @@ -355,11 +356,12 @@ TEST(JxlTest, RoundtripLargeFast) { cparams.AddOption(JXL_ENC_FRAME_SETTING_EFFORT, 7); // kSquirrel PackedPixelFile ppf_out; - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, &pool, &ppf_out), 503000, 12000); + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf_out), 503000, + 12000); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 78); } -TEST(JxlTest, JXL_X86_64_TEST(RoundtripLargeEmptyModular)) { +JXL_X86_64_TEST(JxlTest, RoundtripLargeEmptyModular) { ThreadPoolForTests pool(8); TestImage t; t.SetDimensions(4096, 4096).SetDataType(JXL_TYPE_UINT8).SetChannels(4); @@ -380,7 +382,7 @@ TEST(JxlTest, JXL_X86_64_TEST(RoundtripLargeEmptyModular)) { cparams.AddOption(JXL_ENC_FRAME_SETTING_DECODING_SPEED, 2); PackedPixelFile ppf_out; - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, &pool, &ppf_out), 3474795, + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf_out), 3474795, 100000); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), #if JXL_HIGH_PRECISION @@ -403,8 +405,8 @@ TEST(JxlTest, RoundtripOutputColorSpace) { JXLDecompressParams dparams; dparams.color_space = "RGB_D65_DCI_Rel_709"; PackedPixelFile ppf_out; - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, dparams, &pool, &ppf_out), 503000, - 12000); + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, dparams, pool.get(), &ppf_out), + 503000, 12000); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 78); } @@ -421,7 +423,8 @@ TEST(JxlTest, RoundtripDotsForceEpf) { cparams.AddOption(JXL_ENC_FRAME_SETTING_DOTS, 1); PackedPixelFile ppf_out; - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, &pool, &ppf_out), 41355, 300); + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf_out), 41355, + 300); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 18); } @@ -443,10 +446,10 @@ TEST(JxlTest, RoundtripD2Consistent) { t.SetDimensions(xsize, 15); PackedPixelFile ppf2; - const size_t size2 = Roundtrip(t.ppf(), cparams, {}, &pool, &ppf2); + const size_t size2 = Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf2); PackedPixelFile ppf3; - const size_t size3 = Roundtrip(t.ppf(), cparams, {}, &pool, &ppf3); + const size_t size3 = Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf3); // Exact same compressed size. EXPECT_EQ(size2, size3); @@ -471,7 +474,7 @@ TEST(JxlTest, RoundtripLargeConsistent) { auto roundtrip_and_compare = [&]() { ThreadPoolForTests pool(8); PackedPixelFile ppf2; - size_t size = Roundtrip(t.ppf(), cparams, {}, &pool, &ppf2); + size_t size = Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf2); double dist = ComputeDistance2(t.ppf(), ppf2); return std::tuple(size, dist); }; @@ -985,7 +988,7 @@ TEST(JxlTest, RoundtripAlpha16) { PackedPixelFile ppf_out; // TODO(szabadka) Investigate big size difference on i686 // This still keeps happening (2023-04-18). - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, &pool, &ppf_out), 3666, 120); + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf_out), 3666, 120); EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(t.ppf(), ppf_out), 0.65); } @@ -1000,7 +1003,7 @@ JXLCompressParams CompressParamsForLossless() { } } // namespace -TEST(JxlTest, JXL_SLOW_TEST(RoundtripLossless8)) { +JXL_SLOW_TEST(JxlTest, RoundtripLossless8) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("external/wesaturate/500px/tmshre_riaphotographs_srgb8.png"); @@ -1012,11 +1015,11 @@ TEST(JxlTest, JXL_SLOW_TEST(RoundtripLossless8)) { dparams.accepted_formats.push_back(t.ppf().frames[0].color.format); PackedPixelFile ppf_out; - EXPECT_EQ(Roundtrip(t.ppf(), cparams, dparams, &pool, &ppf_out), 223058); + EXPECT_EQ(Roundtrip(t.ppf(), cparams, dparams, pool.get(), &ppf_out), 223058); EXPECT_EQ(ComputeDistance2(t.ppf(), ppf_out), 0.0); } -TEST(JxlTest, JXL_SLOW_TEST(RoundtripLossless8ThunderGradient)) { +JXL_SLOW_TEST(JxlTest, RoundtripLossless8ThunderGradient) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("external/wesaturate/500px/tmshre_riaphotographs_srgb8.png"); @@ -1030,11 +1033,11 @@ TEST(JxlTest, JXL_SLOW_TEST(RoundtripLossless8ThunderGradient)) { dparams.accepted_formats.push_back(t.ppf().frames[0].color.format); PackedPixelFile ppf_out; - EXPECT_EQ(Roundtrip(t.ppf(), cparams, dparams, &pool, &ppf_out), 261684); + EXPECT_EQ(Roundtrip(t.ppf(), cparams, dparams, pool.get(), &ppf_out), 261684); EXPECT_EQ(ComputeDistance2(t.ppf(), ppf_out), 0.0); } -TEST(JxlTest, JXL_SLOW_TEST(RoundtripLossless8LightningGradient)) { +JXL_SLOW_TEST(JxlTest, RoundtripLossless8LightningGradient) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("external/wesaturate/500px/tmshre_riaphotographs_srgb8.png"); @@ -1048,12 +1051,12 @@ TEST(JxlTest, JXL_SLOW_TEST(RoundtripLossless8LightningGradient)) { PackedPixelFile ppf_out; // Lax comparison because different SIMD will cause different compression. - EXPECT_SLIGHTLY_BELOW(Roundtrip(t.ppf(), cparams, dparams, &pool, &ppf_out), - 286848u); + EXPECT_SLIGHTLY_BELOW( + Roundtrip(t.ppf(), cparams, dparams, pool.get(), &ppf_out), 286848u); EXPECT_EQ(ComputeDistance2(t.ppf(), ppf_out), 0.0); } -TEST(JxlTest, JXL_SLOW_TEST(RoundtripLossless8Falcon)) { +JXL_SLOW_TEST(JxlTest, RoundtripLossless8Falcon) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("external/wesaturate/500px/tmshre_riaphotographs_srgb8.png"); @@ -1066,7 +1069,7 @@ TEST(JxlTest, JXL_SLOW_TEST(RoundtripLossless8Falcon)) { dparams.accepted_formats.push_back(t.ppf().frames[0].color.format); PackedPixelFile ppf_out; - EXPECT_EQ(Roundtrip(t.ppf(), cparams, dparams, &pool, &ppf_out), 230766); + EXPECT_EQ(Roundtrip(t.ppf(), cparams, dparams, pool.get(), &ppf_out), 230766); EXPECT_EQ(ComputeDistance2(t.ppf(), ppf_out), 0.0); } @@ -1348,15 +1351,15 @@ void RoundtripJpegToPixels(const std::vector& jpeg_in, nullptr, ppf_out, nullptr)); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompression444)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompression444) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_444.jpg"); // JPEG size is 696,659 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 568891u, 20); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 568891u, 20); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionToPixels)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionToPixels) { TEST_LIBJPEG_SUPPORT(); ThreadPoolForTests pool(8); const std::vector orig = @@ -1365,11 +1368,11 @@ TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionToPixels)) { t.DecodeFromBytes(orig); PackedPixelFile ppf_out; - RoundtripJpegToPixels(orig, {}, &pool, &ppf_out); + RoundtripJpegToPixels(orig, {}, pool.get(), &ppf_out); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 12); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionToPixels420)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionToPixels420) { TEST_LIBJPEG_SUPPORT(); ThreadPoolForTests pool(8); const std::vector orig = @@ -1378,12 +1381,12 @@ TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionToPixels420)) { t.DecodeFromBytes(orig); PackedPixelFile ppf_out; - RoundtripJpegToPixels(orig, {}, &pool, &ppf_out); + RoundtripJpegToPixels(orig, {}, pool.get(), &ppf_out); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 11); } -TEST(JxlTest, - JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionToPixels420EarlyFlush)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, + RoundtripJpegRecompressionToPixels420EarlyFlush) { TEST_LIBJPEG_SUPPORT(); ThreadPoolForTests pool(8); const std::vector orig = @@ -1395,12 +1398,11 @@ TEST(JxlTest, dparams.max_downsampling = 8; PackedPixelFile ppf_out; - RoundtripJpegToPixels(orig, dparams, &pool, &ppf_out); + RoundtripJpegToPixels(orig, dparams, pool.get(), &ppf_out); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 4410); } -TEST(JxlTest, - JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionToPixels420Mul16)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionToPixels420Mul16) { TEST_LIBJPEG_SUPPORT(); ThreadPoolForTests pool(8); const std::vector orig = @@ -1409,12 +1411,11 @@ TEST(JxlTest, t.DecodeFromBytes(orig); PackedPixelFile ppf_out; - RoundtripJpegToPixels(orig, {}, &pool, &ppf_out); + RoundtripJpegToPixels(orig, {}, pool.get(), &ppf_out); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 4); } -TEST(JxlTest, - JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionToPixels_asymmetric)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionToPixelsAsymmetric) { TEST_LIBJPEG_SUPPORT(); ThreadPoolForTests pool(8); const std::vector orig = @@ -1423,102 +1424,100 @@ TEST(JxlTest, t.DecodeFromBytes(orig); PackedPixelFile ppf_out; - RoundtripJpegToPixels(orig, {}, &pool, &ppf_out); + RoundtripJpegToPixels(orig, {}, pool.get(), &ppf_out); EXPECT_SLIGHTLY_BELOW(ComputeDistance2(t.ppf(), ppf_out), 10); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionGray)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionGray) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_gray.jpg"); // JPEG size is 456,528 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 387496u, 200); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 387496u, 200); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompression420)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompression420) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_420.jpg"); // JPEG size is 546,797 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 455510u, 20); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 455510u, 20); } -TEST(JxlTest, - JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompression_luma_subsample)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionLumaSubsample) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_luma_subsample.jpg"); // JPEG size is 400,724 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 325310u, 20); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 325310u, 20); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompression444_12)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompression444wh12) { // 444 JPEG that has an interesting sampling-factor (1x2, 1x2, 1x2). ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_444_1x2.jpg"); // JPEG size is 703,874 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 569630u, 20); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 569630u, 20); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompression422)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompression422) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_422.jpg"); // JPEG size is 522,057 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 499236u, 20); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 499236u, 20); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompression440)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompression440) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_440.jpg"); // JPEG size is 603,623 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 501101u, 20); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 501101u, 20); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompression_asymmetric)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionAsymmetric) { // 2x vertical downsample of one chroma channel, 2x horizontal downsample of // the other. ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_asymmetric.jpg"); // JPEG size is 604,601 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 500548u, 20); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 500548u, 20); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompression420Progr)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompression420Progr) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png.im_q85_420_progr.jpg"); // JPEG size is 522,057 bytes. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 455454u, 20); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 455454u, 20); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionMetadata)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionMetadata) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/jpeg_reconstruction/1x1_exif_xmp.jpg"); // JPEG size is 4290 bytes // 1370 on 386, so higher margin. - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 1334u, 100); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 1334u, 100); } -TEST(JxlTest, JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionRestarts)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionRestarts) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/jpeg_reconstruction/bicycles_restarts.jpg"); // JPEG size is 87478 bytes - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 76054u, 30); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 76054u, 30); } -TEST(JxlTest, - JXL_TRANSCODE_JPEG_TEST(RoundtripJpegRecompressionOrientationICC)) { +JXL_TRANSCODE_JPEG_TEST(JxlTest, RoundtripJpegRecompressionOrientationICC) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/jpeg_reconstruction/sideways_bench.jpg"); // JPEG size is 15252 bytes - EXPECT_NEAR(RoundtripJpeg(orig, &pool), 12000u, 470); + EXPECT_NEAR(RoundtripJpeg(orig, pool.get()), 12000u, 470); // TODO(jon): investigate why 'Cross-compiling i686-linux-gnu' produces a // larger result } @@ -1535,7 +1534,8 @@ TEST(JxlTest, RoundtripProgressive) { cparams.AddOption(JXL_ENC_FRAME_SETTING_RESPONSIVE, 1); PackedPixelFile ppf_out; - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, &pool, &ppf_out), 70544, 750); + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf_out), 70544, + 750); EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(t.ppf(), ppf_out), 1.4); } @@ -1552,7 +1552,8 @@ TEST(JxlTest, RoundtripProgressiveLevel2Slow) { cparams.AddOption(JXL_ENC_FRAME_SETTING_RESPONSIVE, 1); PackedPixelFile ppf_out; - EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, &pool, &ppf_out), 76666, 1000); + EXPECT_NEAR(Roundtrip(t.ppf(), cparams, {}, pool.get(), &ppf_out), 76666, + 1000); EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(t.ppf(), ppf_out), 1.17); } @@ -1639,7 +1640,7 @@ TEST_P(JxlTest, LosslessSmallFewColors) { dparams.accepted_formats.push_back(t.ppf().frames[0].color.format); PackedPixelFile ppf_out; - Roundtrip(t.ppf(), cparams, dparams, &pool, &ppf_out); + Roundtrip(t.ppf(), cparams, dparams, pool.get(), &ppf_out); EXPECT_EQ(ComputeDistance2(t.ppf(), ppf_out), 0.0); } @@ -1708,7 +1709,7 @@ TEST_P(JxlStreamingTest, Roundtrip) { ThreadPoolForTests pool(8); PackedPixelFile ppf_out; - Roundtrip(image.ppf(), cparams, {}, &pool, &ppf_out); + Roundtrip(image.ppf(), cparams, {}, pool.get(), &ppf_out); EXPECT_GT(jxl::test::ComputePSNR(image.ppf(), ppf_out), p.max_psnr()); } @@ -1763,7 +1764,7 @@ class JxlStreamingEncodingTest : public ::testing::TestWithParam {}; // This is broken on mingw32, so we only enable it for x86_64 now. -TEST_P(JxlStreamingEncodingTest, JXL_X86_64_TEST(StreamingSamePixels)) { +JXL_X86_64_TEST_P(JxlStreamingEncodingTest, StreamingSamePixels) { const auto param = GetParam(); const std::vector orig = ReadTestData(param.file); @@ -1780,11 +1781,11 @@ TEST_P(JxlStreamingEncodingTest, JXL_X86_64_TEST(StreamingSamePixels)) { ThreadPoolForTests pool(8); PackedPixelFile ppf_out; - Roundtrip(image.ppf(), cparams, {}, &pool, &ppf_out); + Roundtrip(image.ppf(), cparams, {}, pool.get(), &ppf_out); cparams.AddOption(JXL_ENC_FRAME_SETTING_BUFFERING, 3); PackedPixelFile ppf_out_streaming; - Roundtrip(image.ppf(), cparams, {}, &pool, &ppf_out_streaming); + Roundtrip(image.ppf(), cparams, {}, pool.get(), &ppf_out_streaming); EXPECT_TRUE(jxl::test::SamePixels(ppf_out, ppf_out_streaming)); } diff --git a/third_party/jpeg-xl/lib/jxl/lehmer_code_test.cc b/third_party/jpeg-xl/lib/jxl/lehmer_code_test.cc index acda762545..c7752d8cfc 100644 --- a/third_party/jpeg-xl/lib/jxl/lehmer_code_test.cc +++ b/third_party/jpeg-xl/lib/jxl/lehmer_code_test.cc @@ -88,10 +88,10 @@ void RoundtripSizeRange(ThreadPool* pool, uint32_t begin, uint32_t end) { TEST(LehmerCodeTest, TestRoundtrips) { test::ThreadPoolForTests pool(8); - RoundtripSizeRange(&pool, 1, 1026); + RoundtripSizeRange(pool.get(), 1, 1026); // Ensures PermutationT can fit > 16 bit values. - RoundtripSizeRange(&pool, 65536, 65540); + RoundtripSizeRange(pool.get(), 65536, 65540); } } // namespace diff --git a/third_party/jpeg-xl/lib/jxl/modular/encoding/context_predict.h b/third_party/jpeg-xl/lib/jxl/modular/encoding/context_predict.h index 7bec5128fc..df54a9425e 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/encoding/context_predict.h +++ b/third_party/jpeg-xl/lib/jxl/modular/encoding/context_predict.h @@ -63,7 +63,7 @@ struct State { pixel_type_w pred = 0; // *before* removing the added bits. std::vector pred_errors[kNumPredictors]; std::vector error; - const Header header; + const Header &header; // Allows to approximate division by a number from 1 to 64. // for (int i = 0; i < 64; i++) divlookup[i] = (1 << 24) / (i + 1); @@ -82,7 +82,7 @@ struct State { return static_cast(x) << kPredExtraBits; } - State(Header header, size_t xsize, size_t ysize) : header(header) { + State(const Header &header, size_t xsize, size_t ysize) : header(header) { // Extra margin to avoid out-of-bounds writes. // All have space for two rows of data. for (auto &pred_error : pred_errors) { diff --git a/third_party/jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc b/third_party/jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc index de629ad038..23100bba8b 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/encoding/enc_ma.cc @@ -197,7 +197,7 @@ void FindBestSplit(TreeSamples &tree_samples, float threshold, float rcost = std::numeric_limits::max(); Predictor lpred = Predictor::Zero; Predictor rpred = Predictor::Zero; - float Cost() { return lcost + rcost; } + float Cost() const { return lcost + rcost; } }; SplitInfo best_split_static_constant; @@ -242,14 +242,14 @@ void FindBestSplit(TreeSamples &tree_samples, float threshold, // The multiplier ranges cut halfway through the current ranges of static // properties. We do this even if the current node is not a leaf, to // minimize the number of nodes in the resulting tree. - for (size_t i = 0; i < mul_info.size(); i++) { + for (const auto &mmi : mul_info) { uint32_t axis; uint32_t val; IntersectionType t = - BoxIntersects(static_prop_range, mul_info[i].range, axis, val); + BoxIntersects(static_prop_range, mmi.range, axis, val); if (t == IntersectionType::kNone) continue; if (t == IntersectionType::kInside) { - (*tree)[pos].multiplier = mul_info[i].multiplier; + (*tree)[pos].multiplier = mmi.multiplier; break; } if (t == IntersectionType::kPartial) { diff --git a/third_party/jpeg-xl/lib/jxl/modular/encoding/encoding.cc b/third_party/jpeg-xl/lib/jxl/modular/encoding/encoding.cc index bb690b74ba..7e7aa019e3 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/encoding/encoding.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/encoding/encoding.cc @@ -113,7 +113,7 @@ FlatTree FilterTree(const Tree &global_tree, } } - for (size_t j = 0; j < 2; j++) mark_property(flat.properties[j]); + for (int16_t property : flat.properties) mark_property(property); mark_property(flat.property0); output.push_back(flat); } @@ -159,9 +159,9 @@ Status DecodeModularChannelMAANS(BitReader *br, ANSSymbolReader *reader, // From here on, tree lookup returns a *clustered* context ID. // This avoids an extra memory lookup after tree traversal. - for (size_t i = 0; i < tree.size(); i++) { - if (tree[i].property0 == -1) { - tree[i].childID = context_map[tree[i].childID]; + for (auto &node : tree) { + if (node.property0 == -1) { + node.childID = context_map[node.childID]; } } @@ -538,8 +538,8 @@ Status ModularDecode(BitReader *br, Image &image, GroupHeader &header, // Don't do/undo transforms if header is incomplete. header.transforms.clear(); image.transform = header.transforms; - for (size_t c = 0; c < image.channel.size(); c++) { - ZeroFillImage(&image.channel[c].plane); + for (auto &ch : image.channel) { + ZeroFillImage(&ch.plane); } return Status(StatusCode::kNotEnoughBytes); } diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/enc_palette.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/enc_palette.cc index 24c64f5aad..7f9399d3c4 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/enc_palette.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/enc_palette.cc @@ -68,8 +68,8 @@ static int QuantizeColorToImplicitPaletteIndex( int index = 0; if (high_quality) { int multiplier = 1; - for (size_t c = 0; c < color.size(); c++) { - int quantized = ((kLargeCube - 1) * color[c] + (1 << (bit_depth - 1))) / + for (int value : color) { + int quantized = ((kLargeCube - 1) * value + (1 << (bit_depth - 1))) / ((1 << bit_depth) - 1); JXL_ASSERT((quantized % kLargeCube) == quantized); index += quantized * multiplier; @@ -78,8 +78,7 @@ static int QuantizeColorToImplicitPaletteIndex( return index + palette_size + kLargeCubeOffset; } else { int multiplier = 1; - for (size_t c = 0; c < color.size(); c++) { - int value = color[c]; + for (int value : color) { value -= 1 << (std::max(0, bit_depth - 3)); value = std::max(0, value); int quantized = ((kLargeCube - 1) * value + (1 << (bit_depth - 1))) / @@ -171,6 +170,7 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, size_t w = input.channel[begin_c].w; size_t h = input.channel[begin_c].h; + if (!lossy && nb_colors < 2) return false; if (!lossy && nb == 1) { // Channel palette special case @@ -321,6 +321,20 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, } } + std::map, bool> implicit_color; + std::vector> implicit_colors; + implicit_colors.reserve(palette_internal::kImplicitPaletteSize); + for (size_t k = 0; k < palette_internal::kImplicitPaletteSize; k++) { + for (size_t i = 0; i < nb; i++) { + color[i] = palette_internal::GetPaletteValue(nullptr, k, i, 0, 0, + input.bitdepth); + } + implicit_color[color] = true; + implicit_colors.push_back(color); + } + + std::map, size_t> color_freq_map; + uint32_t implicit_colors_used = 0; for (size_t y = 0; y < h; y++) { for (uint32_t c = 0; c < nb; c++) { p_in[c] = input.channel[begin_c + c].Row(y); @@ -332,15 +346,39 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, } const bool new_color = candidate_palette.insert(color).second; if (new_color) { - candidate_palette_imageorder.push_back(color); - } - if (candidate_palette.size() > nb_colors) { - return false; // too many colors + if (implicit_color[color]) { + implicit_colors_used++; + } else { + candidate_palette_imageorder.push_back(color); + if (candidate_palette_imageorder.size() > nb_colors) { + return false; // too many colors + } + } } + color_freq_map[color] += 1; } } - nb_colors = nb_deltas + candidate_palette.size(); + nb_colors = nb_deltas + candidate_palette_imageorder.size(); + + // not useful to make a single-color palette + if (!lossy && nb_colors + implicit_colors_used == 1) return false; + // TODO(jon): if this happens (e.g. solid white group), special-case it for + // faster encode + + for (size_t k = 0; k < palette_internal::kImplicitPaletteSize; k++) { + color = implicit_colors[k]; + // still add the color to the explicit palette if it is frequent enough + if (color_freq_map[color] > 10) { + nb_colors++; + candidate_palette_imageorder.push_back(color); + } + } + for (size_t k = 0; k < palette_internal::kImplicitPaletteSize; k++) { + color = implicit_colors[k]; + inv_palette[color] = nb_colors + k; + } + JXL_DEBUG_V(6, "Channels %i-%i can be represented using a %i-color palette.", begin_c, end_c, nb_colors); @@ -360,25 +398,33 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, } } } - + // Separate the palette in two buckets, first the common colors, then the + // rare colors. + // Within each bucket, the colors are sorted on luma (times alpha). + float freq_threshold = 4; // arbitrary threshold int x = 0; if (ordered && nb >= 3) { JXL_DEBUG_V(7, "Palette of %i colors, using luma order", nb_colors); // sort on luma (multiplied by alpha if available) std::sort(candidate_palette_imageorder.begin(), candidate_palette_imageorder.end(), - [](std::vector ap, std::vector bp) { + [&](std::vector ap, std::vector bp) { float ay; float by; ay = (0.299f * ap[0] + 0.587f * ap[1] + 0.114f * ap[2] + 0.1f); if (ap.size() > 3) ay *= 1.f + ap[3]; by = (0.299f * bp[0] + 0.587f * bp[1] + 0.114f * bp[2] + 0.1f); if (bp.size() > 3) by *= 1.f + bp[3]; + // put common colors first, transparent dark to opaque bright, + // then rare colors, bright to dark + ay = color_freq_map[ap] > freq_threshold ? -ay : ay; + by = color_freq_map[bp] > freq_threshold ? -by : by; return ay < by; }); } else { JXL_DEBUG_V(7, "Palette of %i colors, using image order", nb_colors); } + for (auto pcol : candidate_palette_imageorder) { JXL_DEBUG_V(9, " Color %i : ", x); for (size_t i = 0; i < nb; i++) { @@ -398,10 +444,10 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, // beneficial for both precision and encoding speed. std::vector> error_row[3]; if (lossy) { - for (int i = 0; i < 3; ++i) { - error_row[i].resize(nb); + for (auto &row : error_row) { + row.resize(nb); for (size_t c = 0; c < nb; ++c) { - error_row[i][c].resize(w + 4); + row[c].resize(w + 4); } } } @@ -424,13 +470,11 @@ Status FwdPaletteIteration(Image &input, uint32_t begin_c, uint32_t end_c, std::vector ideal_residual(nb, 0); std::vector quantized_val(nb); std::vector predictions(nb); - static const double kDiffusionMultiplier[] = {0.55, 0.75}; - for (int diffusion_index = 0; diffusion_index < 2; ++diffusion_index) { + for (double diffusion_multiplier : {0.55, 0.75}) { for (size_t c = 0; c < nb; c++) { color_with_error[c] = p_in[c][x] + (palette_iteration_data.final_run ? 1 : 0) * - kDiffusionMultiplier[diffusion_index] * - error_row[0][c][x + 2]; + diffusion_multiplier * error_row[0][c][x + 2]; color[c] = Clamp1(lroundf(color_with_error[c]), 0l, (1l << input.bitdepth) - 1); } diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/enc_squeeze.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/enc_squeeze.cc index 0d924c0ace..7371830743 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/enc_squeeze.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/enc_squeeze.cc @@ -124,13 +124,13 @@ Status FwdSqueeze(Image &input, std::vector parameters, } // if nothing to do, don't do squeeze if (parameters.empty()) return false; - for (size_t i = 0; i < parameters.size(); i++) { + for (auto ¶meter : parameters) { JXL_RETURN_IF_ERROR( - CheckMetaSqueezeParams(parameters[i], input.channel.size())); - bool horizontal = parameters[i].horizontal; - bool in_place = parameters[i].in_place; - uint32_t beginc = parameters[i].begin_c; - uint32_t endc = parameters[i].begin_c + parameters[i].num_c - 1; + CheckMetaSqueezeParams(parameter, input.channel.size())); + bool horizontal = parameter.horizontal; + bool in_place = parameter.in_place; + uint32_t beginc = parameter.begin_c; + uint32_t endc = parameter.begin_c + parameter.num_c - 1; uint32_t offset; if (in_place) { offset = endc + 1; diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h b/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h index e0405a2162..2a9e5c71f4 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h @@ -30,6 +30,8 @@ static constexpr int kSmallCube = 4; static constexpr int kSmallCubeBits = 2; // kSmallCube ** 3 static constexpr int kLargeCubeOffset = kSmallCube * kSmallCube * kSmallCube; +static constexpr int kImplicitPaletteSize = + kLargeCubeOffset + kLargeCube * kLargeCube * kLargeCube; static inline pixel_type Scale(uint64_t value, uint64_t bit_depth, uint64_t denom) { diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.cc index 580829741a..b71c8dc248 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.cc @@ -385,21 +385,21 @@ void DefaultSqueezeParameters(std::vector *parameters, params.in_place = true; if (!wide) { - if (h > JXL_MAX_FIRST_PREVIEW_SIZE) { + if (h > kMaxFirstPreviewSize) { params.horizontal = false; parameters->push_back(params); h = (h + 1) / 2; JXL_DEBUG_V(7, "Vertical (%" PRIuS "x%" PRIuS "), ", w, h); } } - while (w > JXL_MAX_FIRST_PREVIEW_SIZE || h > JXL_MAX_FIRST_PREVIEW_SIZE) { - if (w > JXL_MAX_FIRST_PREVIEW_SIZE) { + while (w > kMaxFirstPreviewSize || h > kMaxFirstPreviewSize) { + if (w > kMaxFirstPreviewSize) { params.horizontal = true; parameters->push_back(params); w = (w + 1) / 2; JXL_DEBUG_V(7, "Horizontal (%" PRIuS "x%" PRIuS "), ", w, h); } - if (h > JXL_MAX_FIRST_PREVIEW_SIZE) { + if (h > kMaxFirstPreviewSize) { params.horizontal = false; parameters->push_back(params); h = (h + 1) / 2; @@ -424,13 +424,13 @@ Status MetaSqueeze(Image &image, std::vector *parameters) { DefaultSqueezeParameters(parameters, image); } - for (size_t i = 0; i < parameters->size(); i++) { + for (auto ¶meter : *parameters) { JXL_RETURN_IF_ERROR( - CheckMetaSqueezeParams((*parameters)[i], image.channel.size())); - bool horizontal = (*parameters)[i].horizontal; - bool in_place = (*parameters)[i].in_place; - uint32_t beginc = (*parameters)[i].begin_c; - uint32_t endc = (*parameters)[i].begin_c + (*parameters)[i].num_c - 1; + CheckMetaSqueezeParams(parameter, image.channel.size())); + bool horizontal = parameter.horizontal; + bool in_place = parameter.in_place; + uint32_t beginc = parameter.begin_c; + uint32_t endc = parameter.begin_c + parameter.num_c - 1; uint32_t offset; if (beginc < image.nb_meta_channels) { @@ -441,7 +441,7 @@ Status MetaSqueeze(Image &image, std::vector *parameters) { return JXL_FAILURE( "Invalid squeeze: meta channels require in-place residuals"); } - image.nb_meta_channels += (*parameters)[i].num_c; + image.nb_meta_channels += parameter.num_c; } if (in_place) { offset = endc + 1; diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.h b/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.h index bbd16c59c0..f0333da6fd 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.h +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/squeeze.h @@ -29,10 +29,10 @@ #include "lib/jxl/modular/modular_image.h" #include "lib/jxl/modular/transform/transform.h" -#define JXL_MAX_FIRST_PREVIEW_SIZE 8 - namespace jxl { +constexpr size_t kMaxFirstPreviewSize = 8; + /* int avg=(A+B)>>1; int diff=(A-B); diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc index 33f7a10cc9..a609cfb3fb 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc @@ -23,7 +23,7 @@ Transform::Transform(TransformId id) { } Status Transform::Inverse(Image &input, const weighted::Header &wp_header, - ThreadPool *pool) { + ThreadPool *pool) const { JXL_DEBUG_V(6, "Input channels (%" PRIuS ", %" PRIuS " meta): ", input.channel.size(), input.nb_meta_channels); switch (id) { diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/transform.h b/third_party/jpeg-xl/lib/jxl/modular/transform/transform.h index b68861706f..70c383834a 100644 --- a/third_party/jpeg-xl/lib/jxl/modular/transform/transform.h +++ b/third_party/jpeg-xl/lib/jxl/modular/transform/transform.h @@ -134,7 +134,7 @@ class Transform : public Fields { JXL_FIELDS_NAME(Transform) Status Inverse(Image &input, const weighted::Header &wp_header, - ThreadPool *pool = nullptr); + ThreadPool *pool = nullptr) const; Status MetaApply(Image &input); }; diff --git a/third_party/jpeg-xl/lib/jxl/modular_test.cc b/third_party/jpeg-xl/lib/jxl/modular_test.cc index bd1a947493..ceebf59c0b 100644 --- a/third_party/jpeg-xl/lib/jxl/modular_test.cc +++ b/third_party/jpeg-xl/lib/jxl/modular_test.cc @@ -80,15 +80,15 @@ void TestLosslessGroups(size_t group_size_shift) { TEST(ModularTest, RoundtripLosslessGroups128) { TestLosslessGroups(0); } -TEST(ModularTest, JXL_TSAN_SLOW_TEST(RoundtripLosslessGroups512)) { +JXL_TSAN_SLOW_TEST(ModularTest, RoundtripLosslessGroups512) { TestLosslessGroups(2); } -TEST(ModularTest, JXL_TSAN_SLOW_TEST(RoundtripLosslessGroups1024)) { +JXL_TSAN_SLOW_TEST(ModularTest, RoundtripLosslessGroups1024) { TestLosslessGroups(3); } -TEST(ModularTest, RoundtripLosslessCustomWP_PermuteRCT) { +TEST(ModularTest, RoundtripLosslessCustomWpPermuteRCT) { const std::vector orig = ReadTestData("external/wesaturate/500px/u76c0g_bliznaca_srgb8.png"); TestImage t; @@ -144,6 +144,7 @@ TEST(ModularTest, RoundtripLossyDeltaPaletteWP) { cparams.SetLossless(); cparams.lossy_palette = true; cparams.palette_colors = 0; + // TODO(jon): this is currently ignored, and Avg4 is always used instead cparams.options.predictor = jxl::Predictor::Weighted; CodecInOut io_out; @@ -154,12 +155,12 @@ TEST(ModularTest, RoundtripLossyDeltaPaletteWP) { size_t compressed_size; JXL_EXPECT_OK(Roundtrip(&io, cparams, {}, &io_out, _, &compressed_size)); - EXPECT_LE(compressed_size, 7000u); + EXPECT_LE(compressed_size, 6500u); EXPECT_SLIGHTLY_BELOW( ButteraugliDistance(io.frames, io_out.frames, ButteraugliParams(), *JxlGetDefaultCms(), /*distmap=*/nullptr), - 10.1); + 1.5); } TEST(ModularTest, RoundtripLossy) { @@ -346,8 +347,8 @@ TEST_P(ModularTestParam, RoundtripLossless) { const float* in = io.Main().color()->PlaneRow(c, y); const float* out = io2.Main().color()->PlaneRow(c, y); for (size_t x = 0; x < xsize; x++) { - uint32_t uin = in[x] * factor + 0.5; - uint32_t uout = out[x] * factor + 0.5; + uint32_t uin = std::lroundf(in[x] * factor); + uint32_t uout = std::lroundf(out[x] * factor); // check that the integer values are identical if (uin != uout) different++; } diff --git a/third_party/jpeg-xl/lib/jxl/passes_test.cc b/third_party/jpeg-xl/lib/jxl/passes_test.cc index cb9164706f..e7a7547a0c 100644 --- a/third_party/jpeg-xl/lib/jxl/passes_test.cc +++ b/third_party/jpeg-xl/lib/jxl/passes_test.cc @@ -80,7 +80,7 @@ TEST(PassesTest, RoundtripMultiGroupPasses) { CodecInOut io; { ThreadPoolForTests pool(4); - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, pool.get())); } io.ShrinkTo(600, 1024); // partial X, full Y group @@ -92,11 +92,11 @@ TEST(PassesTest, RoundtripMultiGroupPasses) { cparams.SetCms(*JxlGetDefaultCms()); CodecInOut io2; JXL_EXPECT_OK(Roundtrip(&io, cparams, {}, &io2, _, - /* compressed_size */ nullptr, &pool)); + /* compressed_size */ nullptr, pool.get())); EXPECT_SLIGHTLY_BELOW( ButteraugliDistance(io.frames, io2.frames, ButteraugliParams(), *JxlGetDefaultCms(), - /*distmap=*/nullptr, &pool), + /*distmap=*/nullptr, pool.get()), target_distance + threshold); }; @@ -108,7 +108,7 @@ TEST(PassesTest, RoundtripLargeFastPasses) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png"); CodecInOut io; - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, pool.get())); CompressParams cparams; cparams.speed_tier = SpeedTier::kSquirrel; @@ -117,7 +117,7 @@ TEST(PassesTest, RoundtripLargeFastPasses) { CodecInOut io2; JXL_EXPECT_OK(Roundtrip(&io, cparams, {}, &io2, _, - /* compressed_size */ nullptr, &pool)); + /* compressed_size */ nullptr, pool.get())); } // Checks for differing size/distance in two consecutive runs of distance 2, @@ -127,7 +127,7 @@ TEST(PassesTest, RoundtripProgressiveConsistent) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png"); CodecInOut io; - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, pool.get())); CompressParams cparams; cparams.speed_tier = SpeedTier::kSquirrel; @@ -141,11 +141,11 @@ TEST(PassesTest, RoundtripProgressiveConsistent) { CodecInOut io2; size_t size2; - JXL_EXPECT_OK(Roundtrip(&io, cparams, {}, &io2, _, &size2, &pool)); + JXL_EXPECT_OK(Roundtrip(&io, cparams, {}, &io2, _, &size2, pool.get())); CodecInOut io3; size_t size3; - JXL_EXPECT_OK(Roundtrip(&io, cparams, {}, &io3, _, &size3, &pool)); + JXL_EXPECT_OK(Roundtrip(&io, cparams, {}, &io3, _, &size3, pool.get())); // Exact same compressed size. EXPECT_EQ(size2, size3); @@ -153,10 +153,10 @@ TEST(PassesTest, RoundtripProgressiveConsistent) { // Exact same distance. const float dist2 = ButteraugliDistance( io.frames, io2.frames, ButteraugliParams(), *JxlGetDefaultCms(), - /*distmap=*/nullptr, &pool); + /*distmap=*/nullptr, pool.get()); const float dist3 = ButteraugliDistance( io.frames, io3.frames, ButteraugliParams(), *JxlGetDefaultCms(), - /*distmap=*/nullptr, &pool); + /*distmap=*/nullptr, pool.get()); EXPECT_EQ(dist2, dist3); } } @@ -166,7 +166,7 @@ TEST(PassesTest, AllDownsampleFeasible) { const std::vector orig = ReadTestData("external/wesaturate/500px/u76c0g_bliznaca_srgb8.png"); CodecInOut io; - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, pool.get())); std::vector compressed; @@ -174,7 +174,7 @@ TEST(PassesTest, AllDownsampleFeasible) { cparams.speed_tier = SpeedTier::kSquirrel; cparams.progressive_mode = Override::kOn; cparams.butteraugli_distance = 1.0; - ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, &pool)); + ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, pool.get())); EXPECT_LE(compressed.size(), 240000u); float target_butteraugli[9] = {}; @@ -202,7 +202,7 @@ TEST(PassesTest, AllDownsampleFeasible) { target_butteraugli[downsampling]) << "downsampling: " << downsampling; }; - EXPECT_TRUE(RunOnPool(&pool, 0, downsamplings.size(), ThreadPool::NoInit, + EXPECT_TRUE(RunOnPool(pool.get(), 0, downsamplings.size(), ThreadPool::NoInit, check, "TestDownsampling")); } @@ -211,7 +211,7 @@ TEST(PassesTest, AllDownsampleFeasibleQProgressive) { const std::vector orig = ReadTestData("external/wesaturate/500px/u76c0g_bliznaca_srgb8.png"); CodecInOut io; - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, pool.get())); std::vector compressed; @@ -219,7 +219,7 @@ TEST(PassesTest, AllDownsampleFeasibleQProgressive) { cparams.speed_tier = SpeedTier::kSquirrel; cparams.qprogressive_mode = Override::kOn; cparams.butteraugli_distance = 1.0; - ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, &pool)); + ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, pool.get())); EXPECT_LE(compressed.size(), 220000u); @@ -247,7 +247,7 @@ TEST(PassesTest, AllDownsampleFeasibleQProgressive) { target_butteraugli[downsampling]) << "downsampling: " << downsampling; }; - EXPECT_TRUE(RunOnPool(&pool, 0, downsamplings.size(), ThreadPool::NoInit, + EXPECT_TRUE(RunOnPool(pool.get(), 0, downsamplings.size(), ThreadPool::NoInit, check, "TestQProgressive")); } @@ -256,7 +256,7 @@ TEST(PassesTest, ProgressiveDownsample2DegradesCorrectlyGrayscale) { const std::vector orig = ReadTestData( "external/wesaturate/500px/cvo9xd_keong_macan_grayscale.png"); CodecInOut io_orig; - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io_orig, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io_orig, pool.get())); Rect rect(0, 0, io_orig.xsize(), 128); // need 2 DC groups for the DC frame to actually be progressive. JXL_ASSIGN_OR_DIE(Image3F large, Image3F::Create(4242, rect.ysize())); @@ -274,7 +274,7 @@ TEST(PassesTest, ProgressiveDownsample2DegradesCorrectlyGrayscale) { cparams.responsive = JXL_TRUE; cparams.qprogressive_mode = Override::kOn; cparams.butteraugli_distance = 1.0; - ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, &pool)); + ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, pool.get())); EXPECT_LE(compressed.size(), 10000u); @@ -300,7 +300,7 @@ TEST(PassesTest, ProgressiveDownsample2DegradesCorrectly) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png"); CodecInOut io_orig; - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io_orig, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io_orig, pool.get())); Rect rect(0, 0, io_orig.xsize(), 128); // need 2 DC groups for the DC frame to actually be progressive. JXL_ASSIGN_OR_DIE(Image3F large, Image3F::Create(4242, rect.ysize())); @@ -317,7 +317,7 @@ TEST(PassesTest, ProgressiveDownsample2DegradesCorrectly) { cparams.responsive = JXL_TRUE; cparams.qprogressive_mode = Override::kOn; cparams.butteraugli_distance = 1.0; - ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, &pool)); + ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, pool.get())); EXPECT_LE(compressed.size(), 220000u); @@ -343,7 +343,7 @@ TEST(PassesTest, NonProgressiveDCImage) { ThreadPoolForTests pool(8); const std::vector orig = ReadTestData("jxl/flower/flower.png"); CodecInOut io; - ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, &pool)); + ASSERT_TRUE(SetFromBytes(Bytes(orig), &io, pool.get())); std::vector compressed; @@ -351,14 +351,15 @@ TEST(PassesTest, NonProgressiveDCImage) { cparams.speed_tier = SpeedTier::kSquirrel; cparams.progressive_mode = Override::kOff; cparams.butteraugli_distance = 2.0; - ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, &pool)); + ASSERT_TRUE(test::EncodeFile(cparams, &io, &compressed, pool.get())); // Even in non-progressive mode, it should be possible to return a DC-only // image. extras::JXLDecompressParams dparams; dparams.max_downsampling = 100; CodecInOut output; - ASSERT_TRUE(test::DecodeFile(dparams, Bytes(compressed), &output, &pool)); + ASSERT_TRUE( + test::DecodeFile(dparams, Bytes(compressed), &output, pool.get())); EXPECT_EQ(output.xsize(), io.xsize()); EXPECT_EQ(output.ysize(), io.ysize()); } diff --git a/third_party/jpeg-xl/lib/jxl/quant_weights_test.cc b/third_party/jpeg-xl/lib/jxl/quant_weights_test.cc index e92cbf2151..776a1c776d 100644 --- a/third_party/jpeg-xl/lib/jxl/quant_weights_test.cc +++ b/third_party/jpeg-xl/lib/jxl/quant_weights_test.cc @@ -164,7 +164,7 @@ TEST(QuantWeightsTest, RAW) { QuantEncoding::Library(0)); std::vector matrix(3 * 32 * 32); Rng rng(0); - for (size_t i = 0; i < matrix.size(); i++) matrix[i] = rng.UniformI(1, 256); + for (int& v : matrix) v = rng.UniformI(1, 256); encodings[DequantMatrices::kQuantTable[AcStrategy::DCT32X32]] = QuantEncoding::RAW(matrix, 2); RoundtripMatrices(encodings); diff --git a/third_party/jpeg-xl/lib/jxl/render_pipeline/render_pipeline.cc b/third_party/jpeg-xl/lib/jxl/render_pipeline/render_pipeline.cc index 14bd363110..09e3dbab76 100644 --- a/third_party/jpeg-xl/lib/jxl/render_pipeline/render_pipeline.cc +++ b/third_party/jpeg-xl/lib/jxl/render_pipeline/render_pipeline.cc @@ -20,7 +20,7 @@ void RenderPipeline::Builder::AddStage( StatusOr> RenderPipeline::Builder::Finalize( FrameDimensions frame_dimensions) && { #if JXL_ENABLE_ASSERT - // Check that the last stage is not an kInOut stage for any channel, and that + // Check that the last stage is not a kInOut stage for any channel, and that // there is at least one stage. JXL_ASSERT(!stages_.empty()); for (size_t c = 0; c < num_c_; c++) { diff --git a/third_party/jpeg-xl/lib/jxl/render_pipeline/simple_render_pipeline.cc b/third_party/jpeg-xl/lib/jxl/render_pipeline/simple_render_pipeline.cc index 7f5a8ef00f..77ddb3d430 100644 --- a/third_party/jpeg-xl/lib/jxl/render_pipeline/simple_render_pipeline.cc +++ b/third_party/jpeg-xl/lib/jxl/render_pipeline/simple_render_pipeline.cc @@ -22,12 +22,12 @@ Status SimpleRenderPipeline::PrepareForThreadsInternal(size_t num, auto ch_size = [](size_t frame_size, size_t shift) { return DivCeil(frame_size, 1 << shift) + kRenderPipelineXOffset * 2; }; - for (size_t c = 0; c < channel_shifts_[0].size(); c++) { + for (auto& entry : channel_shifts_[0]) { JXL_ASSIGN_OR_RETURN( - ImageF ch, ImageF::Create(ch_size(frame_dimensions_.xsize_upsampled, - channel_shifts_[0][c].first), - ch_size(frame_dimensions_.ysize_upsampled, - channel_shifts_[0][c].second))); + ImageF ch, + ImageF::Create( + ch_size(frame_dimensions_.xsize_upsampled, entry.first), + ch_size(frame_dimensions_.ysize_upsampled, entry.second))); channel_data_.push_back(std::move(ch)); msan::PoisonImage(channel_data_.back()); } diff --git a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_cms.cc b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_cms.cc index 3202a03e44..9ce65e1644 100644 --- a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_cms.cc +++ b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_cms.cc @@ -45,7 +45,7 @@ class CmsStage : public RenderPipelineStage { size_t xextra, size_t xsize, size_t xpos, size_t ypos, size_t thread_id) const final { JXL_ASSERT(xsize <= xsize_); - // TODO(firsching): handle grey case seperately + // TODO(firsching): handle grey case separately // interleave float* JXL_RESTRICT row0 = GetInputRow(input_rows, 0, 0); float* JXL_RESTRICT row1 = GetInputRow(input_rows, 1, 0); diff --git a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_epf.cc b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_epf.cc index d3030b02cb..b281e41794 100644 --- a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_epf.cc +++ b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_epf.cc @@ -40,10 +40,10 @@ JXL_INLINE Vec Weight(Vec sad, Vec inv_sigma, Vec thres) { // this filter a 7x7 filter. class EPF0Stage : public RenderPipelineStage { public: - EPF0Stage(const LoopFilter& lf, const ImageF& sigma) + EPF0Stage(LoopFilter lf, const ImageF& sigma) : RenderPipelineStage(RenderPipelineStage::Settings::Symmetric( /*shift=*/0, /*border=*/3)), - lf_(lf), + lf_(std::move(lf)), sigma_(&sigma) {} template @@ -72,7 +72,7 @@ class EPF0Stage : public RenderPipelineStage { DF df; using V = decltype(Zero(df)); - V t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, tA, tB; + V t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, tA, tB; // NOLINT V* sads[12] = {&t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9, &tA, &tB}; xextra = RoundUpTo(xextra, Lanes(df)); @@ -114,7 +114,7 @@ class EPF0Stage : public RenderPipelineStage { const auto sm = Load(df, sad_mul + ix); const auto inv_sigma = Mul(Set(df, row_sigma[bx]), sm); - for (size_t i = 0; i < 12; i++) *sads[i] = Zero(df); + for (auto& sad : sads) *sad = Zero(df); constexpr std::array sads_off[12] = { {{-2, 0}}, {{-1, -1}}, {{-1, 0}}, {{-1, 1}}, {{0, -2}}, {{0, -1}}, {{0, 1}}, {{0, 2}}, {{1, -1}}, {{1, 0}}, {{1, 1}}, {{2, 0}}, @@ -128,12 +128,10 @@ class EPF0Stage : public RenderPipelineStage { auto sad = Zero(df); constexpr std::array plus_off[] = { {{0, 0}}, {{-1, 0}}, {{0, -1}}, {{1, 0}}, {{0, 1}}}; - for (size_t j = 0; j < 5; j++) { - const auto r11 = - LoadU(df, rows[c][3 + plus_off[j][0]] + x + plus_off[j][1]); - const auto c11 = - LoadU(df, rows[c][3 + sads_off[i][0] + plus_off[j][0]] + x + - sads_off[i][1] + plus_off[j][1]); + for (const auto& off : plus_off) { + const auto r11 = LoadU(df, rows[c][3 + off[0]] + x + off[1]); + const auto c11 = LoadU(df, rows[c][3 + sads_off[i][0] + off[0]] + + x + sads_off[i][1] + off[1]); sad = Add(sad, AbsDiff(r11, c11)); } *sads[i] = MulAdd(sad, scale, *sads[i]); @@ -181,10 +179,10 @@ class EPF0Stage : public RenderPipelineStage { // makes this filter a 5x5 filter. class EPF1Stage : public RenderPipelineStage { public: - EPF1Stage(const LoopFilter& lf, const ImageF& sigma) + EPF1Stage(LoopFilter lf, const ImageF& sigma) : RenderPipelineStage(RenderPipelineStage::Settings::Symmetric( /*shift=*/0, /*border=*/2)), - lf_(lf), + lf_(std::move(lf)), sigma_(&sigma) {} template @@ -362,10 +360,10 @@ class EPF1Stage : public RenderPipelineStage { // filter. class EPF2Stage : public RenderPipelineStage { public: - EPF2Stage(const LoopFilter& lf, const ImageF& sigma) + EPF2Stage(LoopFilter lf, const ImageF& sigma) : RenderPipelineStage(RenderPipelineStage::Settings::Symmetric( /*shift=*/0, /*border=*/1)), - lf_(lf), + lf_(std::move(lf)), sigma_(&sigma) {} template diff --git a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_upsampling.cc b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_upsampling.cc index 897b20c4c6..e868f9f8e0 100644 --- a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_upsampling.cc +++ b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_upsampling.cc @@ -110,7 +110,7 @@ class UpsamplingStage : public RenderPipelineStage { ssize_t x0, ssize_t x1) const { static HWY_FULL(float) df; using V = hwy::HWY_NAMESPACE::Vec; - V ups0, ups1, ups2, ups3, ups4, ups5, ups6, ups7; + V ups0, ups1, ups2, ups3, ups4, ups5, ups6, ups7; // NOLINT (void)ups2, (void)ups3, (void)ups4, (void)ups5, (void)ups6, (void)ups7; // Once we have C++17 available, change this back to `V* ups[N]` and // initialize using `if constexpr` below. diff --git a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_write.cc b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_write.cc index c5a91e8efd..05cdd786a9 100644 --- a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_write.cc +++ b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_write.cc @@ -11,6 +11,7 @@ #include "lib/jxl/base/common.h" #include "lib/jxl/base/status.h" #include "lib/jxl/dec_cache.h" +#include "lib/jxl/dec_xyb.h" #include "lib/jxl/image.h" #include "lib/jxl/image_bundle.h" #include "lib/jxl/sanitizers.h" @@ -556,11 +557,11 @@ HWY_EXPORT(GetWriteToOutputStage); namespace { class WriteToImageBundleStage : public RenderPipelineStage { public: - explicit WriteToImageBundleStage(ImageBundle* image_bundle, - ColorEncoding color_encoding) + explicit WriteToImageBundleStage( + ImageBundle* image_bundle, const OutputEncodingInfo& output_encoding_info) : RenderPipelineStage(RenderPipelineStage::Settings()), image_bundle_(image_bundle), - color_encoding_(std::move(color_encoding)) {} + color_encoding_(output_encoding_info.color_encoding) {} Status SetInputSizes( const std::vector>& input_sizes) override { @@ -658,9 +659,9 @@ class WriteToImage3FStage : public RenderPipelineStage { } // namespace std::unique_ptr GetWriteToImageBundleStage( - ImageBundle* image_bundle, ColorEncoding color_encoding) { + ImageBundle* image_bundle, const OutputEncodingInfo& output_encoding_info) { return jxl::make_unique(image_bundle, - std::move(color_encoding)); + output_encoding_info); } std::unique_ptr GetWriteToImage3FStage(Image3F* image) { diff --git a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_write.h b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_write.h index c5f844ebe8..ba2c51ee97 100644 --- a/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_write.h +++ b/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_write.h @@ -9,13 +9,14 @@ #include #include "lib/jxl/dec_cache.h" +#include "lib/jxl/dec_xyb.h" #include "lib/jxl/image_bundle.h" #include "lib/jxl/render_pipeline/render_pipeline_stage.h" namespace jxl { std::unique_ptr GetWriteToImageBundleStage( - ImageBundle* image_bundle, ColorEncoding color_encoding); + ImageBundle* image_bundle, const OutputEncodingInfo& output_encoding_info); // Gets a stage to write color channels to an Image3F. std::unique_ptr GetWriteToImage3FStage(Image3F* image); diff --git a/third_party/jpeg-xl/lib/jxl/roundtrip_test.cc b/third_party/jpeg-xl/lib/jxl/roundtrip_test.cc index a4a87bebb7..07e43e4ddf 100644 --- a/third_party/jpeg-xl/lib/jxl/roundtrip_test.cc +++ b/third_party/jpeg-xl/lib/jxl/roundtrip_test.cc @@ -941,7 +941,7 @@ TEST(RoundtripTest, TestICCProfile) { JxlDecoderDestroy(dec); } -TEST(RoundtripTest, JXL_TRANSCODE_JPEG_TEST(TestJPEGReconstruction)) { +JXL_TRANSCODE_JPEG_TEST(RoundtripTest, TestJPEGReconstruction) { TEST_LIBJPEG_SUPPORT(); const std::string jpeg_path = "jxl/flower/flower.png.im_q85_420.jpg"; const std::vector orig = jxl::test::ReadTestData(jpeg_path); diff --git a/third_party/jpeg-xl/lib/jxl/speed_tier_test.cc b/third_party/jpeg-xl/lib/jxl/speed_tier_test.cc index 381367b54d..8783faec8f 100644 --- a/third_party/jpeg-xl/lib/jxl/speed_tier_test.cc +++ b/third_party/jpeg-xl/lib/jxl/speed_tier_test.cc @@ -82,7 +82,6 @@ JXL_GTEST_INSTANTIATE_TEST_SUITE_P( TEST_P(SpeedTierTest, Roundtrip) { const SpeedTierTestParams& params = GetParam(); - test::ThreadPoolForTests pool(8); const std::vector orig = jxl::test::ReadTestData( "external/wesaturate/500px/u76c0g_bliznaca_srgb8.png"); test::TestImage t; diff --git a/third_party/jpeg-xl/lib/jxl/splines.cc b/third_party/jpeg-xl/lib/jxl/splines.cc index 1d4fc69e3e..2df2160d76 100644 --- a/third_party/jpeg-xl/lib/jxl/splines.cc +++ b/third_party/jpeg-xl/lib/jxl/splines.cc @@ -94,11 +94,11 @@ void DrawSegment(DF df, const SplineSegment& segment, const bool add, void DrawSegment(const SplineSegment& segment, const bool add, const size_t y, const ssize_t x0, ssize_t x1, float* JXL_RESTRICT rows[3]) { - ssize_t x = - std::max(x0, segment.center_x - segment.maximum_distance + 0.5f); + ssize_t x = std::max( + x0, std::llround(segment.center_x - segment.maximum_distance)); // one-past-the-end - x1 = - std::min(x1, segment.center_x + segment.maximum_distance + 1.5f); + x1 = std::min( + x1, std::llround(segment.center_x + segment.maximum_distance) + 1); HWY_FULL(float) df; for (; x + static_cast(Lanes(df)) <= x1; x += Lanes(df)) { DrawSegment(df, segment, add, y, x, rows); @@ -550,8 +550,8 @@ Status QuantizedSpline::Decode(const std::vector& context_map, } return true; }; - for (int c = 0; c < 3; ++c) { - JXL_RETURN_IF_ERROR(decode_dct(color_dct_[c])); + for (auto& dct : color_dct_) { + JXL_RETURN_IF_ERROR(decode_dct(dct)); } JXL_RETURN_IF_ERROR(decode_dct(sigma_dct_)); return true; diff --git a/third_party/jpeg-xl/lib/jxl/test_image.cc b/third_party/jpeg-xl/lib/jxl/test_image.cc index 42f028d53a..d2e17c6ab0 100644 --- a/third_party/jpeg-xl/lib/jxl/test_image.cc +++ b/third_party/jpeg-xl/lib/jxl/test_image.cc @@ -288,8 +288,7 @@ TestImage& TestImage::SetAllBitDepths(uint32_t bits_per_sample, ppf_.info.alpha_bits = bits_per_sample; ppf_.info.alpha_exponent_bits = exponent_bits_per_sample; } - for (size_t i = 0; i < ppf_.extra_channels_info.size(); ++i) { - extras::PackedExtraChannel& ec = ppf_.extra_channels_info[i]; + for (auto& ec : ppf_.extra_channels_info) { ec.ec_info.bits_per_sample = bits_per_sample; ec.ec_info.exponent_bits_per_sample = exponent_bits_per_sample; } diff --git a/third_party/jpeg-xl/lib/jxl/test_utils.h b/third_party/jpeg-xl/lib/jxl/test_utils.h index 15057cc92d..dc50490174 100644 --- a/third_party/jpeg-xl/lib/jxl/test_utils.h +++ b/third_party/jpeg-xl/lib/jxl/test_utils.h @@ -180,8 +180,7 @@ class ThreadPoolForTests { } ThreadPoolForTests(const ThreadPoolForTests&) = delete; ThreadPoolForTests& operator&(const ThreadPoolForTests&) = delete; - // TODO(eustas): avoid unary `&` overload? - ThreadPool* operator&() { return pool_.get(); } + ThreadPool* get() { return pool_.get(); } private: JxlThreadParallelRunnerPtr runner_; diff --git a/third_party/jpeg-xl/lib/jxl/testing.h b/third_party/jpeg-xl/lib/jxl/testing.h index 1fac352a78..6e4978eb60 100644 --- a/third_party/jpeg-xl/lib/jxl/testing.h +++ b/third_party/jpeg-xl/lib/jxl/testing.h @@ -13,33 +13,37 @@ #include "lib/jxl/common.h" #ifdef JXL_DISABLE_SLOW_TESTS -#define JXL_SLOW_TEST(X) DISABLED_##X +#define JXL_SLOW_TEST(T, C) TEST(T, DISABLED_##C) #else -#define JXL_SLOW_TEST(X) X +#define JXL_SLOW_TEST(T, C) TEST(T, C) #endif // JXL_DISABLE_SLOW_TESTS #if JPEGXL_ENABLE_TRANSCODE_JPEG -#define JXL_TRANSCODE_JPEG_TEST(X) X +#define JXL_TRANSCODE_JPEG_TEST(T, C) TEST(T, C) #else -#define JXL_TRANSCODE_JPEG_TEST(X) DISABLED_##X +#define JXL_TRANSCODE_JPEG_TEST(T, C) TEST(T, DISABLED_##C) #endif // JPEGXL_ENABLE_TRANSCODE_JPEG #if JPEGXL_ENABLE_BOXES -#define JXL_BOXES_TEST(X) X +#define JXL_BOXES_TEST(T, C) TEST(T, C) +#define JXL_BOXES_TEST_P(T, C) TEST_P(T, C) #else -#define JXL_BOXES_TEST(X) DISABLED_##X +#define JXL_BOXES_TEST(T, C) TEST(T, DISABLED_##C) +#define JXL_BOXES_TEST_P(T, C) TEST_P(T, DISABLED_##C) #endif // JPEGXL_ENABLE_BOXES #ifdef THREAD_SANITIZER -#define JXL_TSAN_SLOW_TEST(X) DISABLED_##X +#define JXL_TSAN_SLOW_TEST(T, C) TEST(T, DISABLED_##C) #else -#define JXL_TSAN_SLOW_TEST(X) X +#define JXL_TSAN_SLOW_TEST(T, C) TEST(T, C) #endif // THREAD_SANITIZER #if defined(__x86_64__) -#define JXL_X86_64_TEST(X) X +#define JXL_X86_64_TEST(T, C) TEST(T, C) +#define JXL_X86_64_TEST_P(T, C) TEST_P(T, C) #else -#define JXL_X86_64_TEST(X) DISABLED_##X +#define JXL_X86_64_TEST(T, C) TEST(T, DISABLED_##C) +#define JXL_X86_64_TEST_P(T, C) TEST_P(T, C) #endif // defined(__x86_64__) // googletest before 1.10 didn't define INSTANTIATE_TEST_SUITE_P() but instead diff --git a/third_party/jpeg-xl/lib/jxl/tf_gbench.cc b/third_party/jpeg-xl/lib/jxl/tf_gbench.cc index e93a936c90..6cfd3734bb 100644 --- a/third_party/jpeg-xl/lib/jxl/tf_gbench.cc +++ b/third_party/jpeg-xl/lib/jxl/tf_gbench.cc @@ -46,7 +46,9 @@ namespace { #define RUN_BENCHMARK_SCALAR(F, I) \ constexpr size_t kNum = 1 << 12; \ /* Three parallel runs, as this will run on R, G and B. */ \ - float sum1 = 0, sum2 = 0, sum3 = 0; \ + float sum1 = 0; \ + float sum2 = 0; \ + float sum3 = 0; \ for (auto _ : state) { \ float x = 1e-5; \ float v1 = 1e-5; \ diff --git a/third_party/jpeg-xl/lib/jxl/version.h.in b/third_party/jpeg-xl/lib/jxl/version.h.in index ad1eb24409..b5a462e52e 100644 --- a/third_party/jpeg-xl/lib/jxl/version.h.in +++ b/third_party/jpeg-xl/lib/jxl/version.h.in @@ -32,7 +32,7 @@ #define JPEGXL_COMPUTE_NUMERIC_VERSION(major,minor,patch) (((major)<<24) | ((minor)<<16) | ((patch)<<8) | 0) /* Numeric representation of the version */ -#define JPEGXL_NUMERIC_VERSION JPEGXL_COMPUTE_NUMERIC_VERSION(JPEGXL_MAJOR_VERSION,JPEGXL_MINOR_VERSION,JPEGXL_PATCH_VERSION) +#define JPEGXL_NUMERIC_VERSION JPEGXL_COMPUTE_NUMERIC_VERSION(JPEGXL_MAJOR_VERSION, JPEGXL_MINOR_VERSION, JPEGXL_PATCH_VERSION) #endif /* JXL_VERSION_H_ */ diff --git a/third_party/jpeg-xl/lib/jxl/xorshift128plus_test.cc b/third_party/jpeg-xl/lib/jxl/xorshift128plus_test.cc index 2ee4535284..c68ce4bb3b 100644 --- a/third_party/jpeg-xl/lib/jxl/xorshift128plus_test.cc +++ b/third_party/jpeg-xl/lib/jxl/xorshift128plus_test.cc @@ -294,7 +294,7 @@ void TestFloat() { const uint32_t kMaxSeed = 4096; #endif // JXL_DISABLE_SLOW_TESTS EXPECT_TRUE(RunOnPool( - &pool, 0, kMaxSeed, ThreadPool::NoInit, + pool.get(), 0, kMaxSeed, ThreadPool::NoInit, [](const uint32_t seed, size_t /*thread*/) { HWY_ALIGN Xorshift128Plus rng(seed); @@ -340,7 +340,7 @@ void TestNotZero() { const uint32_t kMaxSeed = 2000; #endif // JXL_DISABLE_SLOW_TESTS EXPECT_TRUE(RunOnPool( - &pool, 0, kMaxSeed, ThreadPool::NoInit, + pool.get(), 0, kMaxSeed, ThreadPool::NoInit, [](const uint32_t task, size_t /*thread*/) { HWY_ALIGN uint64_t lanes[Xorshift128Plus::N]; diff --git a/third_party/jpeg-xl/lib/jxl_cms.cmake b/third_party/jpeg-xl/lib/jxl_cms.cmake index 04980066c1..62d5b651fd 100644 --- a/third_party/jpeg-xl/lib/jxl_cms.cmake +++ b/third_party/jpeg-xl/lib/jxl_cms.cmake @@ -23,7 +23,7 @@ target_include_directories(jxl_cms PRIVATE generate_export_header(jxl_cms BASE_NAME JXL_CMS EXPORT_FILE_NAME include/jxl/jxl_cms_export.h) -target_include_directories(jxl_cms PUBLIC +target_include_directories(jxl_cms BEFORE PUBLIC "$") set(JPEGXL_CMS_LIBRARY_REQUIRES "") diff --git a/third_party/jpeg-xl/lib/jxl_extras.cmake b/third_party/jpeg-xl/lib/jxl_extras.cmake index 597f691554..747c07eb9c 100644 --- a/third_party/jpeg-xl/lib/jxl_extras.cmake +++ b/third_party/jpeg-xl/lib/jxl_extras.cmake @@ -118,7 +118,7 @@ foreach(LIB ${JXL_EXTRAS_OBJECT_LIBRARIES}) target_compile_options("${LIB}" PRIVATE "${JPEGXL_INTERNAL_FLAGS}") target_compile_definitions("${LIB}" PRIVATE -DJXL_EXPORT=) set_property(TARGET "${LIB}" PROPERTY POSITION_INDEPENDENT_CODE ON) - target_include_directories("${LIB}" PRIVATE + target_include_directories("${LIB}" BEFORE PRIVATE ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include diff --git a/third_party/jpeg-xl/lib/jxl_lists.bzl b/third_party/jpeg-xl/lib/jxl_lists.bzl index 6c98ca15ed..a66706aa83 100644 --- a/third_party/jpeg-xl/lib/jxl_lists.bzl +++ b/third_party/jpeg-xl/lib/jxl_lists.bzl @@ -551,7 +551,7 @@ libjxl_major_version = 0 libjxl_minor_version = 10 -libjxl_patch_version = 0 +libjxl_patch_version = 2 libjxl_public_headers = [ "include/jxl/cms.h", diff --git a/third_party/jpeg-xl/lib/threads/thread_parallel_runner_test.cc b/third_party/jpeg-xl/lib/threads/thread_parallel_runner_test.cc index 7c8e602764..0762b3299b 100644 --- a/third_party/jpeg-xl/lib/threads/thread_parallel_runner_test.cc +++ b/third_party/jpeg-xl/lib/threads/thread_parallel_runner_test.cc @@ -34,7 +34,7 @@ TEST(ThreadParallelRunnerTest, TestPool) { for (int begin = 0; begin < 32; ++begin) { std::fill(mementos.begin(), mementos.end(), 0); EXPECT_TRUE(RunOnPool( - &pool, begin, begin + num_tasks, jxl::ThreadPool::NoInit, + pool.get(), begin, begin + num_tasks, jxl::ThreadPool::NoInit, [begin, num_tasks, &mementos](const int task, const int thread) { // Parameter is in the given range EXPECT_GE(task, begin); @@ -63,7 +63,7 @@ TEST(ThreadParallelRunnerTest, TestSmallAssignments) { std::atomic num_calls{0}; EXPECT_TRUE(RunOnPool( - &pool, 0, num_threads, jxl::ThreadPool::NoInit, + pool.get(), 0, num_threads, jxl::ThreadPool::NoInit, [&num_calls, num_threads, &id_bits](const int task, const int thread) { num_calls.fetch_add(1, std::memory_order_relaxed); @@ -101,7 +101,7 @@ TEST(ThreadParallelRunnerTest, TestCounter) { const int kNumTasks = kNumThreads * 19; EXPECT_TRUE(RunOnPool( - &pool, 0, kNumTasks, jxl::ThreadPool::NoInit, + pool.get(), 0, kNumTasks, jxl::ThreadPool::NoInit, [&counters](const int task, const int thread) { counters[thread].counter += task; }, diff --git a/third_party/jpeg-xl/plugins/gimp/file-jxl-load.cc b/third_party/jpeg-xl/plugins/gimp/file-jxl-load.cc index 07acd524d2..41a5d45bfb 100644 --- a/third_party/jpeg-xl/plugins/gimp/file-jxl-load.cc +++ b/third_party/jpeg-xl/plugins/gimp/file-jxl-load.cc @@ -39,10 +39,10 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { GimpColorProfile *profile_icc = nullptr; GimpColorProfile *profile_int = nullptr; bool is_linear = false; - unsigned long xsize = 0; - unsigned long ysize = 0; - long crop_x0 = 0; - long crop_y0 = 0; + uint32_t xsize = 0; + uint32_t ysize = 0; + int32_t crop_x0 = 0; + int32_t crop_y0 = 0; size_t layer_idx = 0; uint32_t frame_duration = 0; double tps_denom = 1.f; diff --git a/third_party/jpeg-xl/plugins/gimp/file-jxl-save.cc b/third_party/jpeg-xl/plugins/gimp/file-jxl-save.cc index 284a9f2771..65b637d419 100644 --- a/third_party/jpeg-xl/plugins/gimp/file-jxl-save.cc +++ b/third_party/jpeg-xl/plugins/gimp/file-jxl-save.cc @@ -17,12 +17,12 @@ #define PLUG_IN_BINARY "file-jxl" #define SAVE_PROC "file-jxl-save" -#define SCALE_WIDTH 200 - namespace jxl { namespace { +constexpr size_t kScaleWidth = 200; + #ifndef g_clear_signal_handler // g_clear_signal_handler was added in glib 2.62 void g_clear_signal_handler(gulong* handler, gpointer instance) { @@ -292,7 +292,7 @@ bool JpegXlSaveGui::SaveDialog() { "\n\td\u00A0=\u00A06\tPoor"; entry_distance = reinterpret_cast( - gimp_scale_entry_new(GTK_TABLE(table), 0, 0, "Distance", SCALE_WIDTH, 0, + gimp_scale_entry_new(GTK_TABLE(table), 0, 0, "Distance", kScaleWidth, 0, jxl_save_opts.distance, 0.0, 15.0, 0.001, 1.0, 3, true, 0.0, 0.0, distance_help, SAVE_PROC)); gimp_scale_entry_set_logarithmic(reinterpret_cast(entry_distance), @@ -303,7 +303,7 @@ bool JpegXlSaveGui::SaveDialog() { "JPEG-style Quality is remapped to distance. " "Values roughly match libjpeg quality settings."; entry_quality = reinterpret_cast(gimp_scale_entry_new( - GTK_TABLE(table), 0, 1, "Quality", SCALE_WIDTH, 0, jxl_save_opts.quality, + GTK_TABLE(table), 0, 1, "Quality", kScaleWidth, 0, jxl_save_opts.quality, 8.26, 100.0, 1.0, 10.0, 2, true, 0.0, 0.0, quality_help, SAVE_PROC)); // Distance and Quality Signals @@ -325,7 +325,7 @@ bool JpegXlSaveGui::SaveDialog() { "As\u00A0a\u00A0result, image quality may be decreased. " "Default\u00A0=\u00A03."; entry_effort = reinterpret_cast( - gimp_scale_entry_new(GTK_TABLE(table), 0, 3, "Speed", SCALE_WIDTH, 0, + gimp_scale_entry_new(GTK_TABLE(table), 0, 3, "Speed", kScaleWidth, 0, 10 - jxl_save_opts.encoding_effort, 1, 9, 1, 2, 0, true, 0.0, 0.0, effort_help, SAVE_PROC)); @@ -419,7 +419,7 @@ bool JpegXlSaveGui::SaveDialog() { entry_faster = reinterpret_cast( gimp_scale_entry_new(GTK_TABLE(table), 0, 0, "Faster Decoding", - SCALE_WIDTH, 0, jxl_save_opts.faster_decoding, 0, 4, + kScaleWidth, 0, jxl_save_opts.faster_decoding, 0, 4, 1, 1, 0, true, 0.0, 0.0, faster_help, SAVE_PROC)); // Faster Decoding Signals diff --git a/third_party/libwebrtc/.vpython3 b/third_party/libwebrtc/.vpython3 index 3f571df261..2be8efaa0a 100644 --- a/third_party/libwebrtc/.vpython3 +++ b/third_party/libwebrtc/.vpython3 @@ -22,24 +22,24 @@ # Read more about `vpython` and how to modify this file here: # https://chromium.googlesource.com/infra/infra/+/main/doc/users/vpython.md -python_version: "3.8" +python_version: "3.11" # Used by: # third_party/catapult wheel: < name: "infra/python/wheels/psutil/${vpython_platform}" - version: "version:5.8.0.chromium.2" + version: "version:5.8.0.chromium.3" > # Used by tools_webrtc/perf/process_perf_results.py. wheel: < name: "infra/python/wheels/httplib2-py3" - version: "version:0.19.1" + version: "version:0.22.0" > wheel: < - name: "infra/python/wheels/pyparsing-py2_py3" - version: "version:2.4.7" + name: "infra/python/wheels/pyparsing-py3" + version: "version:3.1.1" > @@ -47,7 +47,7 @@ wheel: < # build/toolchain/win wheel: < name: "infra/python/wheels/pywin32/${vpython_platform}" - version: "version:300" + version: "version:306" match_tag: < platform: "win32" > @@ -59,48 +59,48 @@ wheel: < # GRPC used by iOS test. wheel: < name: "infra/python/wheels/grpcio/${vpython_platform}" - version: "version:1.44.0" + version: "version:1.57.0" > wheel: < name: "infra/python/wheels/six-py2_py3" - version: "version:1.15.0" + version: "version:1.16.0" > wheel: < name: "infra/python/wheels/pbr-py2_py3" - version: "version:3.0.0" + version: "version:5.9.0" > wheel: < name: "infra/python/wheels/funcsigs-py2_py3" version: "version:1.0.2" > wheel: < - name: "infra/python/wheels/mock-py2_py3" - version: "version:2.0.0" + name: "infra/python/wheels/mock-py3" + version: "version:4.0.3" > wheel: < name: "infra/python/wheels/protobuf-py3" - version: "version:3.20.0" + version: "version:4.25.1" > wheel: < name: "infra/python/wheels/requests-py3" version: "version:2.31.0" > wheel: < - name: "infra/python/wheels/idna-py2_py3" - version: "version:2.8" + name: "infra/python/wheels/idna-py3" + version: "version:3.4" > wheel: < - name: "infra/python/wheels/urllib3-py2_py3" - version: "version:1.26.6" + name: "infra/python/wheels/urllib3-py3" + version: "version:2.1.0" > wheel: < - name: "infra/python/wheels/certifi-py2_py3" - version: "version:2020.11.8" + name: "infra/python/wheels/certifi-py3" + version: "version:2023.11.17" > wheel: < name: "infra/python/wheels/charset_normalizer-py3" - version: "version:2.0.4" + version: "version:3.3.2" > wheel: < name: "infra/python/wheels/brotli/${vpython_platform}" diff --git a/third_party/libwebrtc/BUILD.gn b/third_party/libwebrtc/BUILD.gn index 7feca08e60..85ead4162f 100644 --- a/third_party/libwebrtc/BUILD.gn +++ b/third_party/libwebrtc/BUILD.gn @@ -580,6 +580,7 @@ if (!build_with_chromium) { if (build_with_mozilla) { deps += [ + "api/environment:environment_factory", "api/video:video_frame", "api/video:video_rtp_headers", "test:rtp_test_utils", diff --git a/third_party/libwebrtc/DEPS b/third_party/libwebrtc/DEPS index 0f25b04412..9f5cd9fd1f 100644 --- a/third_party/libwebrtc/DEPS +++ b/third_party/libwebrtc/DEPS @@ -10,7 +10,7 @@ vars = { # chromium waterfalls. More info at: crbug.com/570091. 'checkout_configuration': 'default', 'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"', - 'chromium_revision': '60cf2ce5ba3417695d02754c90bd919eb438e4b5', + 'chromium_revision': 'e1fb84c37d20b7b85bfdd24e4ab19967ce1b77df', # Fetch the prebuilt binaries for llvm-cov and llvm-profdata. Needed to # process the raw profiles produced by instrumented targets (built with @@ -25,7 +25,7 @@ vars = { # By default, download the fuchsia sdk from the public sdk directory. 'fuchsia_sdk_cipd_prefix': 'fuchsia/sdk/core/', - 'fuchsia_version': 'version:16.20231129.1.1', + 'fuchsia_version': 'version:17.20240120.1.1', # By default, download the fuchsia images from the fuchsia GCS bucket. 'fuchsia_images_bucket': 'fuchsia', 'checkout_fuchsia': False, @@ -40,7 +40,7 @@ vars = { # RBE instance to use for running remote builds 'rbe_instance': 'projects/rbe-webrtc-developer/instances/default_instance', # reclient CIPD package version - 'reclient_version': 're_client_version:0.121.0.e622934-gomaip', + 'reclient_version': 're_client_version:0.126.0.4aaef37-gomaip', # ninja CIPD package version # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja @@ -50,30 +50,30 @@ vars = { deps = { # TODO(kjellander): Move this to be Android-only. 'src/base': - 'https://chromium.googlesource.com/chromium/src/base@f0b935140fa4d6c206b3419056f8e647ec7e6583', + 'https://chromium.googlesource.com/chromium/src/base@36ecc8e397422620def3bb19a7ba392810ca2442', 'src/build': - 'https://chromium.googlesource.com/chromium/src/build@bb826aaf00833bb61244a7ab5c4ca8c69c51314a', + 'https://chromium.googlesource.com/chromium/src/build@28cd6ea727d171ec990e6174308451d4178d7f8e', 'src/buildtools': - 'https://chromium.googlesource.com/chromium/src/buildtools@b17c7e870e1d722d81f59738707392accf633011', + 'https://chromium.googlesource.com/chromium/src/buildtools@aadc2aa5f7382cdb5bc8e9309971356cf7722773', # Gradle 6.6.1. Used for testing Android Studio project generation for WebRTC. 'src/examples/androidtests/third_party/gradle': { 'url': 'https://chromium.googlesource.com/external/github.com/gradle/gradle.git@f2d1fb54a951d8b11d25748e4711bec8d128d7e3', 'condition': 'checkout_android', }, 'src/ios': { - 'url': 'https://chromium.googlesource.com/chromium/src/ios@f85ff5cfa70484822ca7181012597114ae7ad125', + 'url': 'https://chromium.googlesource.com/chromium/src/ios@e18cc47f9334d9dcf911c724467795542a472b51', 'condition': 'checkout_ios', }, 'src/testing': - 'https://chromium.googlesource.com/chromium/src/testing@189d923e10bfcb856eff08164d6140f93938d854', + 'https://chromium.googlesource.com/chromium/src/testing@450bfd79ee0369ac1a5465a12820b5d94a5956be', 'src/third_party': - 'https://chromium.googlesource.com/chromium/src/third_party@c35e8a3c66aaeb31689af01f6ef63509504b68ff', + 'https://chromium.googlesource.com/chromium/src/third_party@692fab5c0074bc6fa486dce1a4aa7b2cc5609928', 'src/buildtools/linux64': { 'packages': [ { 'package': 'gn/gn/linux-${{arch}}', - 'version': 'git_revision:7367b0df0a0aa25440303998d54045bda73935a5', + 'version': 'git_revision:f99e015ac35f689cfdbf46e4eb174e5d2da78d8e', } ], 'dep_type': 'cipd', @@ -83,7 +83,7 @@ deps = { 'packages': [ { 'package': 'gn/gn/mac-${{arch}}', - 'version': 'git_revision:7367b0df0a0aa25440303998d54045bda73935a5', + 'version': 'git_revision:f99e015ac35f689cfdbf46e4eb174e5d2da78d8e', } ], 'dep_type': 'cipd', @@ -93,7 +93,7 @@ deps = { 'packages': [ { 'package': 'gn/gn/windows-amd64', - 'version': 'git_revision:7367b0df0a0aa25440303998d54045bda73935a5', + 'version': 'git_revision:f99e015ac35f689cfdbf46e4eb174e5d2da78d8e', } ], 'dep_type': 'cipd', @@ -115,11 +115,11 @@ deps = { 'src/third_party/clang-format/script': 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/clang/tools/clang-format.git@e5337933f2951cacd3aeacd238ce4578163ca0b9', 'src/third_party/libc++/src': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxx.git@0ad014cff4509d293e62d1d8c7ffd080bcb2f2d6', + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxx.git@28aa23ffb4c7344914a5b4ac7169f12e5a12333f', 'src/third_party/libc++abi/src': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxxabi.git@4cb5c2cefedc025433f81735bacbc0f773fdcd8f', + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxxabi.git@ea028d4d2b8a901f6302f5371c68a24480766e2b', 'src/third_party/libunwind/src': - 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libunwind.git@bbe2764382995e4ec9a8c26c50018afc9520ea4f', + 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libunwind.git@f400fdb561d4416b59b8f8a33d8ec8b79da60495', 'src/third_party/ninja': { 'packages': [ @@ -185,11 +185,11 @@ deps = { }, 'src/third_party/boringssl/src': - 'https://boringssl.googlesource.com/boringssl.git@1b7fdbd9101dedc3e0aa3fcf4ff74eacddb34ecc', + 'https://boringssl.googlesource.com/boringssl.git@414f69504d30d0848b69f6453ea7fb5e88004cb4', 'src/third_party/breakpad/breakpad': - 'https://chromium.googlesource.com/breakpad/breakpad.git@f49c2f1a2023da0cb055874fba050563dfea57db', + 'https://chromium.googlesource.com/breakpad/breakpad.git@62ecd463583d09eb7d15b1d410055f30b2c7bcb4', 'src/third_party/catapult': - 'https://chromium.googlesource.com/catapult.git@ee967548fe6a699fc295d81bd05c8116bcaf5e7e', + 'https://chromium.googlesource.com/catapult.git@3e413d7b62c09fda8713146714ba2146a0369d86', 'src/third_party/ced/src': { 'url': 'https://chromium.googlesource.com/external/github.com/google/compact_enc_det.git@ba412eaaacd3186085babcd901679a48863c7dd5', }, @@ -202,9 +202,9 @@ deps = { 'src/third_party/crc32c/src': 'https://chromium.googlesource.com/external/github.com/google/crc32c.git@fa5ade41ee480003d9c5af6f43567ba22e4e17e6', 'src/third_party/depot_tools': - 'https://chromium.googlesource.com/chromium/tools/depot_tools.git@b5393e57bb81eb1b6fbecbd7f466abcb61d278b4', + 'https://chromium.googlesource.com/chromium/tools/depot_tools.git@46cb7d0aca592cd20ddc2f6cb16ee386b2abbf0d', 'src/third_party/ffmpeg': - 'https://chromium.googlesource.com/chromium/third_party/ffmpeg.git@866768f35c2226f4c805844207fd11c049ebe962', + 'https://chromium.googlesource.com/chromium/third_party/ffmpeg.git@17525de887d54b970ffdd421a0879c1db1952307', 'src/third_party/flatbuffers/src': 'https://chromium.googlesource.com/external/github.com/google/flatbuffers.git@bcb9ef187628fe07514e57756d05e6a6296f7dc5', 'src/third_party/grpc/src': { @@ -216,15 +216,15 @@ deps = { 'condition': 'checkout_linux', }, 'src/third_party/freetype/src': - 'https://chromium.googlesource.com/chromium/src/third_party/freetype2.git@8f255c89e14219ca2489043f699797ee106ec6e9', + 'https://chromium.googlesource.com/chromium/src/third_party/freetype2.git@57617782464411201ce7bbc93b086c1b4d7d84a5', 'src/third_party/harfbuzz-ng/src': - 'https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz.git@920c40cd43dd7b10b7ecba3d82a46f5fea88536f', + 'https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz.git@155015f4bec434ecc2f94621665844218f05ce51', 'src/third_party/google_benchmark/src': { 'url': 'https://chromium.googlesource.com/external/github.com/google/benchmark.git@b177433f3ee2513b1075140c723d73ab8901790f', }, # WebRTC-only dependency (not present in Chromium). 'src/third_party/gtest-parallel': - 'https://chromium.googlesource.com/external/github.com/google/gtest-parallel@f4d65b555894b301699c7c3c52906f72ea052e83', + 'https://chromium.googlesource.com/external/github.com/google/gtest-parallel@96f4f904922f9bf66689e749c40f314845baaac8', 'src/third_party/google-truth/src': { 'url': 'https://chromium.googlesource.com/external/github.com/google/truth.git@33387149b465f82712a817e6744847fe136949b3', 'condition': 'checkout_android', @@ -267,7 +267,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/kotlin_stdlib', - 'version': 'QEHg036Jc2HWG4-ao7usl1QUexRidGFFSgqqWUpmK-YC', + 'version': '7f5xFu_YQrbg_vacQ5mMcUFIkMPpvM_mQ8QERRKYBvUC', }, ], 'condition': 'checkout_android', @@ -278,7 +278,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/kotlinc', - 'version': 'WKNG-_aQcnsBG-F7SS-yUGLlN9roxcWYt1K_8uw27zQC', + 'version': '8nR_4qTn61NDCwL0G03LrNZzpgmsu5bbyRGior3fZX8C', }, ], 'condition': 'checkout_android', @@ -288,7 +288,7 @@ deps = { 'src/third_party/libFuzzer/src': 'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/compiler-rt/lib/fuzzer.git@758bd21f103a501b362b1ca46fa8fcb692eaa303', 'src/third_party/fuzztest/src': - 'https://chromium.googlesource.com/external/github.com/google/fuzztest.git@9e3dbc646516772c70f7a100be53967323d310cb', + 'https://chromium.googlesource.com/external/github.com/google/fuzztest.git@12e7428ab0847b1d1dc6c4b89203adfd1f16a1ad', 'src/third_party/libjpeg_turbo': 'https://chromium.googlesource.com/chromium/deps/libjpeg_turbo.git@9b894306ec3b28cea46e84c32b56773a98c483da', 'src/third_party/libsrtp': @@ -296,15 +296,15 @@ deps = { 'src/third_party/dav1d/libdav1d': 'https://chromium.googlesource.com/external/github.com/videolan/dav1d.git@47107e384bd1dc25674acf04d000a8cdc6195234', 'src/third_party/libaom/source/libaom': - 'https://aomedia.googlesource.com/aom.git@af3d2a707b5a89d5ffc77260698230505d9bcd35', + 'https://aomedia.googlesource.com/aom.git@646f28605eed1076d784451faa05a4e91e46ff6e', 'src/third_party/libunwindstack': { 'url': 'https://chromium.googlesource.com/chromium/src/third_party/libunwindstack.git@4dbfa0e8c844c8e243b297bc185e54a99ff94f9e', 'condition': 'checkout_android', }, 'src/third_party/perfetto': - 'https://android.googlesource.com/platform/external/perfetto.git@d8a8260e8a08b166547eecd5b6ffcbdb30421109', + 'https://android.googlesource.com/platform/external/perfetto.git@d6af17fef257af28ee2417216ef87d5c5b743a1b', 'src/third_party/libvpx/source/libvpx': - 'https://chromium.googlesource.com/webm/libvpx.git@741b8f6228984e888c99849d7675ea4132eaf268', + 'https://chromium.googlesource.com/webm/libvpx.git@b95d17572629c676bdcfd535fb3990b9f6f8fb11', 'src/third_party/libyuv': 'https://chromium.googlesource.com/libyuv/libyuv.git@04821d1e7d60845525e8db55c7bcd41ef5be9406', 'src/third_party/lss': { @@ -318,20 +318,20 @@ deps = { # Used by boringssl. 'src/third_party/nasm': { - 'url': 'https://chromium.googlesource.com/chromium/deps/nasm.git@7fc833e889d1afda72c06220e5bed8fb43b2e5ce' + 'url': 'https://chromium.googlesource.com/chromium/deps/nasm.git@f477acb1049f5e043904b87b825c5915084a9a29' }, 'src/third_party/openh264/src': 'https://chromium.googlesource.com/external/github.com/cisco/openh264@09a4f3ec842a8932341b195c5b01e141c8a16eb7', 'src/third_party/re2/src': - 'https://chromium.googlesource.com/external/github.com/google/re2.git@7e0c1a9e2417e70e5f0efc323267ac71d1fa0685', + 'https://chromium.googlesource.com/external/github.com/google/re2.git@826ad10e58a042faf57d7c329b0fd0a04b797e0b', 'src/third_party/r8': { 'packages': [ { 'package': 'chromium/third_party/r8', - 'version': 'wtFJRWzGTig_UR3UW82YW63l-sTznrAPEatq-o7zNqYC', + 'version': 'K1NPmXz0aZCAGGtC5UESEmqwT5-x6QNNb0Jo0umsez4C', }, ], 'condition': 'checkout_android', @@ -355,7 +355,7 @@ deps = { 'condition': 'checkout_android', }, 'src/tools': - 'https://chromium.googlesource.com/chromium/src/tools@bcc6c5bc9871bcf8842e6a42397939235fa04860', + 'https://chromium.googlesource.com/chromium/src/tools@51d5368f2225c34a47d1be4feafebba3b6d19579', 'src/third_party/accessibility_test_framework': { 'packages': [ @@ -394,7 +394,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_toolchain/android_toolchain', - 'version': 'NSOM616pOQCfRfDAhC72ltgjyUQp9lAWCMzlmgB18dAC', + 'version': 'wpJvg81kuXdMM66r_l9Doa-pLfR6S26Jd1x40LpwWEoC', }, ], 'condition': 'checkout_android', @@ -405,7 +405,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'fBcslNfNCVI61lUhYka626dfmzui_5hT7AWrfFSdkgMC', + 'version': 'BW2v6j8vjcVQrdX9fXmf686JtkLjxn-KCWhAE1XT_n4C', }, ], 'condition': 'checkout_android', @@ -416,7 +416,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_build_tools/manifest_merger', - 'version': 'SdNR04V227YL22FMmKoS4AdLYwv6MJe8HBAZKNhXoCsC', + 'version': 'tFbjqslkduDT_-y8WEZlsl9iulzcm3mgienslcU71poC', }, ], 'condition': 'checkout_android', @@ -443,7 +443,7 @@ deps = { }, { 'package': 'chromium/third_party/android_sdk/public/cmdline-tools', - 'version': 'Sy00LuyBIUJdRGYKwg0zjWH8eAIUvgnnNiPkI8etaZYC', + 'version': 'BRpfUGFd3WoveSGTLVgkQF7ugIVyywGneVICP4c0010C', }, ], 'condition': 'checkout_android', @@ -498,7 +498,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/turbine', - 'version': 'e8ccyNXO5wVjI0vv5W8kfA101BaaLNjNiVH1JddpdWkC', + 'version': 'ABguU2WKErRBdXX1LMt0zqZListLS_05X0Rp_V7pwAYC', }, ], 'condition': 'checkout_android', @@ -509,11 +509,11 @@ deps = { 'packages': [ { 'package': 'infra/tools/luci/isolate/${{platform}}', - 'version': 'git_revision:1ea45c1829514ff20c476f083462e7b8fdfaf9ae', + 'version': 'git_revision:0d11be367258bfe14a13ff1afcf43a0bc6aedb45', }, { 'package': 'infra/tools/luci/swarming/${{platform}}', - 'version': 'git_revision:1ea45c1829514ff20c476f083462e7b8fdfaf9ae', + 'version': 'git_revision:0d11be367258bfe14a13ff1afcf43a0bc6aedb45', }, ], 'dep_type': 'cipd', @@ -893,7 +893,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework', - 'version': 'version:2@4.0.0.cr1', + 'version': 'version:2@4.1.0.cr1', }, ], 'condition': 'checkout_android', @@ -1729,7 +1729,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/net_bytebuddy_byte_buddy', - 'version': 'version:2@1.14.5.cr1', + 'version': 'version:2@1.14.10.cr1', }, ], 'condition': 'checkout_android', @@ -1740,7 +1740,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent', - 'version': 'version:2@1.14.5.cr1', + 'version': 'version:2@1.14.10.cr1', }, ], 'condition': 'checkout_android', @@ -1949,7 +1949,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_mockito_mockito_android', - 'version': 'version:2@5.4.0.cr1', + 'version': 'version:2@5.8.0.cr1', }, ], 'condition': 'checkout_android', @@ -1960,7 +1960,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_mockito_mockito_core', - 'version': 'version:2@5.4.0.cr1', + 'version': 'version:2@5.8.0.cr1', }, ], 'condition': 'checkout_android', @@ -1971,7 +1971,7 @@ deps = { 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/org_mockito_mockito_subclass', - 'version': 'version:2@5.4.0.cr1', + 'version': 'version:2@5.8.0.cr1', }, ], 'condition': 'checkout_android', diff --git a/third_party/libwebrtc/README.moz-ff-commit b/third_party/libwebrtc/README.moz-ff-commit index 4a3b8c67ea..92e573e293 100644 --- a/third_party/libwebrtc/README.moz-ff-commit +++ b/third_party/libwebrtc/README.moz-ff-commit @@ -27690,3 +27690,849 @@ ece5cb8371 # MOZ_LIBWEBRTC_SRC=/Users/jan-ivar/moz/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh # base of lastest vendoring 6713461a2f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e79e722834 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +61c5e86dca +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e125a3371f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f887e07234 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +242ed95fd7 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3d9c3687a4 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +91a7beb057 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +efe02a5a92 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +15e6c17174 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +659fe7e6f2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +8a29d89e99 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d6601ce66b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +539bca9ebb +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +abd7814e47 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +9384c9ea66 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +65bee96054 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +33c7edd58a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f8e67ba680 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +8c30149f46 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +223334933f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b54bf8a9af +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5f3ac43551 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +151003d341 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +a88ea8a36f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +63e273ad4b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5e3eb52497 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +eb14497d7c +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +86b1cf776e +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b17d53d971 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +a3d2c58e38 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +42b0184458 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5f9239bfd5 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ae86daf830 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +dfb54b5747 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +cdd92da549 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7b4b39809f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b875b8b98b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +fa5d9b6df0 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +9ae1e41205 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ddf6084096 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +bb91f77858 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b3488d08db +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +23c653d2d8 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ca98de9714 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +601ac2eea8 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +776fe6d923 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +871af9225f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f418f48702 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5fe4953d2b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +21edbe5d0d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ce73d3795b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +a3e26ad6b2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d7ccf6df4d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +14a7e8b300 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0b11bd4c2e +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e6df126b79 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +a8cd2babcd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d76e0898a9 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +161d2c8452 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +63d03f586b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +399a9768f2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6c9c958c69 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +336fb4faf4 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +042e57deea +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +2c03790842 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ce98e62974 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d92e95c26e +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6a5d925b48 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d9e2cc2bbd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c202f9635e +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6f0f158af0 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3ba809d6a6 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d093d0db7f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +07e05efe1a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5176511644 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +1f8914d240 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c30fb63f95 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f0ddae8c22 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ac60ad7acd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +8f59f54120 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0f86cd126b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c9d44b3fb9 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5cfce0efba +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +57b06646be +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ac2541be3a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +acdc89d653 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +944b01eb97 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e0e03ba73a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ca8353648d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3e801c3208 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +2b311ea96a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +52da14c44f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3bb0ead42d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c3c455cfee +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c5daa63cef +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ca58f0eb9d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e56055220b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +70ad987c64 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b9ba02c025 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +8f4df7bec9 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b2e9babeb7 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3216c28493 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +06a8ecadf2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5692649b9b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f698a39eec +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +afedc5e7a3 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ee27f38be9 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c5d921899b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +aab4a4c753 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6f6bb66108 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +de464c2f56 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +18a42e3272 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5366794f3a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +4931512cb0 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +771b524606 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +51563cc36c +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +267f9bdd53 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c039e836f3 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +662863ec93 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +331065829a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b74a3e591f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +8ac008119c +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +66344aca9c +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +9e5c979743 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0a01ffcd3f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e6f244e003 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +4d6e8ad95c +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +268ca56196 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +25c454a3e2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +025a675577 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +448c4967e2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b57b6a299b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0f26166648 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3cce50ae4b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d2a19311f1 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ee2fcbab42 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +849a624c33 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f27515bfe3 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +97439b9531 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +932e12d0fd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f40443424e +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0f075331e2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0f2e3e1f99 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d2771c6153 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b78dd9373f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6dd30183a2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +764ac7ec0a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +8a74636d46 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ae46957a51 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +67f0de8614 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7121680f38 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +de17252e8e +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +8e2ab67045 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b39c2a8464 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6b559cd1a7 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +78a57efb29 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c41977d303 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +293af4b5e0 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +a3bde0a844 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3c8c1afaea +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +dc64596510 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b64eef1234 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +55a61898a8 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f089d7ea54 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +80a8683e30 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +9702f6c9fb +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6791c9d17e +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +1d6bf3156b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0a96289bcb +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b9405c4748 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +956879d86f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5d091cec5d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3a20023719 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b7ec05777a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +dda037db07 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c95ad5fe9d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d0ad6ef0bf +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +441fb375f4 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ff76f1ca48 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +a742df24fd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +98b0da181b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f81af2f8fd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +187ca72ab7 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b330a79559 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +21b3c5a5ad +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +1ecf29c1ce +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +bb0044eb90 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +844225a76a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +4e3b101bc9 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c56052001d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +24b034c51b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7978cf1b43 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5aea42860b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +634cb403e6 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +bfee961786 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +77605363b9 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0bf7a6080f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d123ca8e41 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +2ab1997d9d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +40dcdf7fac +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +60885b5d89 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7cb56f5fbd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e707bc40ab +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +dc48289b46 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f8587da72b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7852f5d37f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +36fe51014d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +a1e5ce67b6 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +239d5e8f24 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e5d60f8621 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +edd804816c +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +caf9f1bf83 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e052eee7a3 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +cddcbccb23 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3b7afb284f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5aaa9ed41e +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +e126e45403 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +eb4a3140fd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +1ac0bea35f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +199fd755bd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +972546ed50 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f868b76376 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3b500e60e8 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3b8347e37d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +84c48ae751 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +9e4a97bb02 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +18d1d0f793 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b51c4b01f6 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +54be7084e0 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +2c22da6220 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +1fee69cfff +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d257cb7333 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +111e381822 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +361d74bc36 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +df3b3bd06f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +02d9eceb3c +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7f457533a2 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +787c8f8845 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7aff4d1a40 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0f1b9a9589 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +c0ac4df7a5 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +680025a612 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +192c0628cb +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +b1799b0814 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +68b580f116 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0b6899272c +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7d637a9788 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +fb99c6ebb5 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +df0b363cf0 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3abf8be180 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +55cdc29b9d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +4d706a9fd1 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3b2b2afdaa +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f49d96d6e4 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +434f4cb44f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +3e623ef57d +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +d7478a8453 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +ed1d084d0a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +4c335b70e8 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7209548090 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +37e9b378fd +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0206a971f5 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +0a7fc84887 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +a9ef127f6f +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6a992129fb +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +67ea392f27 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +25be2f802a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7ee67e1ee9 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +1c1c2602cb +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +5dc6c14747 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +798e451878 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +7a1f85fb85 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +11f87b2b29 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +1768705d99 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +9074f0b7d7 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +348438154a +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +f1fc6ab3ba +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +79ac694d9b +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6fa743fbab +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +fd54a619a5 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +be2786cd23 +# MOZ_LIBWEBRTC_SRC=/Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc MOZ_LIBWEBRTC_BRANCH=mozpatches bash dom/media/webrtc/third_party_build/fast-forward-libwebrtc.sh +# base of lastest vendoring +6b419a0536 diff --git a/third_party/libwebrtc/README.mozilla b/third_party/libwebrtc/README.mozilla index 655cb25566..5c7f6efb78 100644 --- a/third_party/libwebrtc/README.mozilla +++ b/third_party/libwebrtc/README.mozilla @@ -18484,3 +18484,567 @@ libwebrtc updated from /Users/jan-ivar/moz/elm/.moz-fast-forward/moz-libwebrtc c libwebrtc updated from /Users/jan-ivar/moz/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-02-12T16:42:26.420193. # ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/jan-ivar/moz/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc libwebrtc updated from /Users/jan-ivar/moz/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-02-12T16:43:32.839122. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-13T22:00:42.108496. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T15:42:35.942170. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T15:44:18.824799. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T15:45:34.915101. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T15:47:20.492179. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T15:49:40.891794. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T16:43:37.008021. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T16:45:09.965177. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T16:46:21.422057. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T16:47:33.409515. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T16:48:45.871351. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T16:50:01.271275. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T16:51:16.827894. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T18:07:26.463390. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:11:33.791917. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:13:00.017045. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:14:25.413262. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:16:12.942136. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:18:19.356774. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:19:40.082034. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:22:14.069601. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:24:02.087471. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:25:53.484374. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:27:15.109589. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:28:34.573821. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:29:54.571786. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:31:43.988030. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:33:04.325559. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:34:37.715350. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:35:59.384845. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:37:19.083468. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:38:40.366112. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:40:01.042328. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:41:22.922579. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:42:40.796168. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:44:01.866969. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:46:14.227464. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:47:34.259756. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:48:54.539611. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:50:16.000949. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:51:41.447662. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:53:00.923973. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:54:29.395657. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:55:54.283391. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:57:15.422985. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T19:58:38.669645. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:00:03.568520. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:01:50.828135. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:04:03.879758. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:05:26.189276. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:06:45.060687. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:07:58.859477. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:09:20.464570. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:10:42.288639. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:11:59.570671. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:14:03.511857. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:15:17.072186. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:16:34.066379. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:17:48.349602. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:19:42.628346. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:21:17.631303. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:22:31.624316. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:24:13.983809. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:25:22.658161. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:26:34.806604. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:27:46.859589. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:28:59.283970. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:30:11.996104. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:31:21.123596. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:33:21.352530. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:35:41.428688. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:37:17.141894. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:38:30.450293. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:39:46.198877. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:40:54.608394. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:42:04.066296. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:43:15.727034. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:45:10.690840. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:46:21.969373. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:47:30.322254. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:49:23.347032. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:50:32.312229. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:51:48.335711. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:53:02.866331. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:54:14.902975. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:55:30.333394. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:56:40.984188. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:57:55.287810. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T20:59:35.071902. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:01:15.149628. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:02:48.941874. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:03:58.318794. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:05:11.087856. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:06:19.770456. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:07:28.648026. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:08:41.460348. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:10:19.590293. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:11:30.905331. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:12:39.401379. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:14:45.074265. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:15:54.093476. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:17:09.104785. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:18:23.374947. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:19:37.059314. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:20:49.749727. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:22:02.610021. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:23:15.703287. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:25:42.759867. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:26:57.339704. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:28:07.729493. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:29:17.690896. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:30:32.663485. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:31:58.591610. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:33:08.677685. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:34:21.327660. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:35:51.700412. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:37:03.723493. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:38:15.965816. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:39:24.733197. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:40:36.169342. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:41:48.840415. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:43:05.348977. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:44:16.927159. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:46:43.933424. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:49:04.079413. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:50:20.806726. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:51:38.242942. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:52:49.351266. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:53:59.120973. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:55:15.092838. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:56:26.884545. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:57:42.444562. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T21:58:50.455390. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:00:05.021969. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:01:17.658072. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:02:30.948278. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:03:39.598365. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:04:47.277094. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:05:58.770776. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:07:14.147734. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:08:27.293988. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:09:36.656223. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:10:50.773764. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:12:01.496938. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:13:16.476585. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:14:26.643582. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:15:36.007691. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:16:51.216373. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:18:04.616987. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:19:16.858324. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:20:28.437676. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:21:45.360819. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:24:10.642287. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:26:22.740877. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:27:55.306685. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:29:03.531038. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:30:38.750451. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:32:38.015290. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:33:49.698722. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:34:59.426162. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:36:11.543930. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:38:10.651773. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:40:27.065384. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:42:52.666535. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:45:16.926825. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:46:31.574236. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:47:43.520106. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:49:42.234752. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:51:54.139078. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:53:51.763723. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:56:18.736341. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T22:58:17.685315. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:00:20.336945. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:01:31.801002. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:02:49.010124. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:04:51.553999. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:07:16.277804. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:08:29.411608. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:09:40.110611. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:10:52.217149. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:11:59.781588. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:14:13.783835. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:16:31.155469. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:17:42.501234. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:18:54.664507. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:20:04.000127. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:22:42.622489. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:25:03.350868. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:26:35.305987. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:28:53.839989. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:30:32.808935. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:31:51.981203. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:34:11.995582. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:35:29.616214. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:37:08.592909. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:38:26.553567. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:39:37.552013. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:40:49.290676. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:41:58.571401. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:43:10.926279. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:44:20.946693. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:45:31.633098. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:46:47.932562. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:48:05.458053. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:49:21.560351. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:50:35.400140. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:51:50.067513. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:53:03.998623. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:54:15.805017. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:55:25.997255. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:56:38.134731. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:58:50.539558. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-15T23:59:58.788052. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:34:04.295199. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:35:15.314915. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:36:28.420177. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:38:59.864702. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:40:12.824543. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:41:24.295214. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:42:35.675361. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:43:47.045677. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:45:44.550449. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:46:55.862291. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:48:06.902438. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:49:19.515185. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:50:49.741108. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:52:18.193963. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:54:02.333387. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:56:02.782038. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:57:30.595976. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T01:59:46.180543. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:01:23.845280. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:02:54.585533. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:04:31.690496. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:05:40.809989. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:07:14.458090. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:09:21.725567. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:11:16.348403. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:12:28.063395. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:14:06.362961. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:15:34.201576. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:16:52.691778. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:18:23.146178. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:20:06.149543. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T02:22:21.730477. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:37:22.392687. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:44:23.387567. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:46:35.379421. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:48:18.309663. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:49:44.685365. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:51:05.591347. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:52:38.734868. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:54:20.944106. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:55:40.633564. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T14:58:04.545142. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T15:00:24.783166. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:06:35.472245. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:17:25.186617. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:18:58.510262. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:21:17.255249. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:22:36.187201. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:24:57.656964. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:27:22.764887. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:28:43.118617. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:30:02.691240. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:31:39.850466. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:33:39.717278. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:34:58.906200. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:36:13.778028. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:37:28.295151. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:38:46.778997. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:40:05.274113. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:41:19.021637. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:42:37.489739. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:44:38.711283. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:45:53.859240. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:47:13.439963. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:49:36.898617. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:51:07.133641. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:52:18.956418. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:53:57.098291. +# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2024-03-16T18:55:14.637807. diff --git a/third_party/libwebrtc/api/BUILD.gn b/third_party/libwebrtc/api/BUILD.gn index 10a4c8c95f..1628660c3c 100644 --- a/third_party/libwebrtc/api/BUILD.gn +++ b/third_party/libwebrtc/api/BUILD.gn @@ -26,15 +26,6 @@ rtc_source_set("call_api") { sources = [ "call/audio_sink.h" ] } -rtc_source_set("callfactory_api") { - visibility = [ "*" ] - sources = [ "call/call_factory_interface.h" ] - deps = [ - "../call:rtp_interfaces", - "../rtc_base/system:rtc_export", - ] -} - rtc_source_set("enable_media") { visibility = [ "*" ] sources = [ @@ -545,6 +536,7 @@ rtc_library("rtp_parameters") { ":array_view", ":priority", ":rtp_transceiver_direction", + "../media:media_constants", "../rtc_base:checks", "../rtc_base:stringutils", "../rtc_base/system:rtc_export", @@ -604,7 +596,6 @@ if (!build_with_mozilla) { deps = [ ":array_view", ":audio_quality_analyzer_api", - ":callfactory_api", ":fec_controller_api", ":frame_generator_api", ":function_view", @@ -673,6 +664,7 @@ if (rtc_include_tests) { "test/create_network_emulation_manager.h", ] deps = [ + ":field_trials_view", ":network_emulation_manager_api", "../test/network:emulated_network", ] @@ -811,8 +803,10 @@ rtc_source_set("rtc_stats_api") { visibility = [ "*" ] cflags = [] sources = [ + "stats/attribute.h", "stats/rtc_stats.h", "stats/rtc_stats_collector_callback.h", + "stats/rtc_stats_member.h", "stats/rtc_stats_report.h", "stats/rtcstats_objects.h", ] @@ -828,7 +822,10 @@ rtc_source_set("rtc_stats_api") { "units:timestamp", ] - absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/types:optional", + "//third_party/abseil-cpp/absl/types:variant", + ] } rtc_library("audio_options_api") { @@ -930,6 +927,7 @@ rtc_source_set("fec_controller_api") { deps = [ "../modules:module_fec_api", + "environment", "video:video_frame_type", ] } @@ -1434,12 +1432,12 @@ if (rtc_include_tests) { ":time_controller", "../call", "../call:call_interfaces", - "../call:rtp_interfaces", "../pc:media_factory", "../rtc_base:checks", "../system_wrappers", "../test/time_controller", "environment", + "environment:environment_factory", ] absl_deps = [ "//third_party/abseil-cpp/absl/base:nullability" ] } diff --git a/third_party/libwebrtc/api/DEPS b/third_party/libwebrtc/api/DEPS index 3a650b6253..5a5c285856 100644 --- a/third_party/libwebrtc/api/DEPS +++ b/third_party/libwebrtc/api/DEPS @@ -159,13 +159,6 @@ specific_include_rules = { "+modules/audio_processing/include/audio_processing.h", ], - "fake_metronome\.h": [ - "+rtc_base/synchronization/mutex.h", - "+rtc_base/task_queue.h", - "+rtc_base/task_utils/repeating_task.h", - "+rtc_base/thread_annotations.h", - ], - "make_ref_counted\.h": [ "+rtc_base/ref_counted_object.h", ], diff --git a/third_party/libwebrtc/api/audio_codecs/BUILD.gn b/third_party/libwebrtc/api/audio_codecs/BUILD.gn index 158ab74cce..2719942488 100644 --- a/third_party/libwebrtc/api/audio_codecs/BUILD.gn +++ b/third_party/libwebrtc/api/audio_codecs/BUILD.gn @@ -35,6 +35,7 @@ rtc_library("audio_codecs_api") { "..:ref_count", "..:scoped_refptr", "../../api:field_trials_view", + "../../api:rtp_parameters", "../../rtc_base:buffer", "../../rtc_base:checks", "../../rtc_base:event_tracer", diff --git a/third_party/libwebrtc/api/audio_codecs/audio_format.cc b/third_party/libwebrtc/api/audio_codecs/audio_format.cc index 2a529a49ee..8dc11fd80f 100644 --- a/third_party/libwebrtc/api/audio_codecs/audio_format.cc +++ b/third_party/libwebrtc/api/audio_codecs/audio_format.cc @@ -27,7 +27,7 @@ SdpAudioFormat::SdpAudioFormat(absl::string_view name, SdpAudioFormat::SdpAudioFormat(absl::string_view name, int clockrate_hz, size_t num_channels, - const Parameters& param) + const CodecParameterMap& param) : name(name), clockrate_hz(clockrate_hz), num_channels(num_channels), @@ -36,7 +36,7 @@ SdpAudioFormat::SdpAudioFormat(absl::string_view name, SdpAudioFormat::SdpAudioFormat(absl::string_view name, int clockrate_hz, size_t num_channels, - Parameters&& param) + CodecParameterMap&& param) : name(name), clockrate_hz(clockrate_hz), num_channels(num_channels), diff --git a/third_party/libwebrtc/api/audio_codecs/audio_format.h b/third_party/libwebrtc/api/audio_codecs/audio_format.h index 0cf67799b8..edccc17e7d 100644 --- a/third_party/libwebrtc/api/audio_codecs/audio_format.h +++ b/third_party/libwebrtc/api/audio_codecs/audio_format.h @@ -17,6 +17,7 @@ #include #include "absl/strings/string_view.h" +#include "api/rtp_parameters.h" #include "rtc_base/checks.h" #include "rtc_base/system/rtc_export.h" @@ -24,7 +25,8 @@ namespace webrtc { // SDP specification for a single audio codec. struct RTC_EXPORT SdpAudioFormat { - using Parameters = std::map; + using Parameters [[deprecated(("Use webrtc::CodecParameterMap"))]] = + std::map; SdpAudioFormat(const SdpAudioFormat&); SdpAudioFormat(SdpAudioFormat&&); @@ -32,11 +34,11 @@ struct RTC_EXPORT SdpAudioFormat { SdpAudioFormat(absl::string_view name, int clockrate_hz, size_t num_channels, - const Parameters& param); + const CodecParameterMap& param); SdpAudioFormat(absl::string_view name, int clockrate_hz, size_t num_channels, - Parameters&& param); + CodecParameterMap&& param); ~SdpAudioFormat(); // Returns true if this format is compatible with `o`. In SDP terminology: @@ -55,7 +57,7 @@ struct RTC_EXPORT SdpAudioFormat { std::string name; int clockrate_hz; size_t num_channels; - Parameters parameters; + CodecParameterMap parameters; }; // Information about how an audio format is treated by the codec implementation. diff --git a/third_party/libwebrtc/api/call/call_factory_interface.h b/third_party/libwebrtc/api/call/call_factory_interface.h deleted file mode 100644 index db53d724a6..0000000000 --- a/third_party/libwebrtc/api/call/call_factory_interface.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef API_CALL_CALL_FACTORY_INTERFACE_H_ -#define API_CALL_CALL_FACTORY_INTERFACE_H_ - -#include - -#include "rtc_base/system/rtc_export.h" - -namespace webrtc { - -// These classes are not part of the API, and are treated as opaque pointers. -class Call; -struct CallConfig; - -// This interface exists to allow webrtc to be optionally built without media -// support (i.e., if only being used for data channels). PeerConnectionFactory -// is constructed with a CallFactoryInterface, which may or may not be null. -// TODO(bugs.webrtc.org/15574): Delete this interface when -// `PeerConnectionFactoryDependencies::call_factory` is removed in favor of -// `PeerConnectionFactoryDependencies::media_factory`. -class CallFactoryInterface { - public: - virtual ~CallFactoryInterface() = default; - - virtual std::unique_ptr CreateCall(const CallConfig& config) = 0; -}; - -[[deprecated("bugs.webrtc.org/15574")]] // -RTC_EXPORT std::unique_ptr -CreateCallFactory(); - -} // namespace webrtc - -#endif // API_CALL_CALL_FACTORY_INTERFACE_H_ diff --git a/third_party/libwebrtc/api/callfactory_api_gn/moz.build b/third_party/libwebrtc/api/callfactory_api_gn/moz.build deleted file mode 100644 index 157a34ec8e..0000000000 --- a/third_party/libwebrtc/api/callfactory_api_gn/moz.build +++ /dev/null @@ -1,213 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ### - ### DO NOT edit it by hand. ### - -COMPILE_FLAGS["OS_INCLUDES"] = [] -AllowCompilerWarnings() - -DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1" -DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True -DEFINES["RTC_ENABLE_VP9"] = True -DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" -DEFINES["WEBRTC_LIBRARY_IMPL"] = True -DEFINES["WEBRTC_MOZILLA_BUILD"] = True -DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" -DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" - -FINAL_LIBRARY = "webrtc" - - -LOCAL_INCLUDES += [ - "!/ipc/ipdl/_ipdlheaders", - "!/third_party/libwebrtc/gen", - "/ipc/chromium/src", - "/third_party/libwebrtc/", - "/third_party/libwebrtc/third_party/abseil-cpp/", - "/tools/profiler/public" -] - -if not CONFIG["MOZ_DEBUG"]: - - DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0" - DEFINES["NDEBUG"] = True - DEFINES["NVALGRIND"] = True - -if CONFIG["MOZ_DEBUG"] == "1": - - DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1" - -if CONFIG["OS_TARGET"] == "Android": - - DEFINES["ANDROID"] = True - DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1" - DEFINES["HAVE_SYS_UIO_H"] = True - DEFINES["WEBRTC_ANDROID"] = True - DEFINES["WEBRTC_ANDROID_OPENSLES"] = True - DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True - DEFINES["WEBRTC_LINUX"] = True - DEFINES["WEBRTC_POSIX"] = True - DEFINES["_GNU_SOURCE"] = True - DEFINES["__STDC_CONSTANT_MACROS"] = True - DEFINES["__STDC_FORMAT_MACROS"] = True - - OS_LIBS += [ - "log" - ] - -if CONFIG["OS_TARGET"] == "Darwin": - - DEFINES["WEBRTC_MAC"] = True - DEFINES["WEBRTC_POSIX"] = True - DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True - DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0" - DEFINES["__STDC_CONSTANT_MACROS"] = True - DEFINES["__STDC_FORMAT_MACROS"] = True - -if CONFIG["OS_TARGET"] == "Linux": - - DEFINES["USE_AURA"] = "1" - DEFINES["USE_GLIB"] = "1" - DEFINES["USE_NSS_CERTS"] = "1" - DEFINES["USE_OZONE"] = "1" - DEFINES["USE_UDEV"] = True - DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True - DEFINES["WEBRTC_LINUX"] = True - DEFINES["WEBRTC_POSIX"] = True - DEFINES["_FILE_OFFSET_BITS"] = "64" - DEFINES["_LARGEFILE64_SOURCE"] = True - DEFINES["_LARGEFILE_SOURCE"] = True - DEFINES["__STDC_CONSTANT_MACROS"] = True - DEFINES["__STDC_FORMAT_MACROS"] = True - - OS_LIBS += [ - "rt" - ] - -if CONFIG["OS_TARGET"] == "OpenBSD": - - DEFINES["USE_GLIB"] = "1" - DEFINES["USE_OZONE"] = "1" - DEFINES["USE_X11"] = "1" - DEFINES["WEBRTC_BSD"] = True - DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True - DEFINES["WEBRTC_POSIX"] = True - DEFINES["_FILE_OFFSET_BITS"] = "64" - DEFINES["_LARGEFILE64_SOURCE"] = True - DEFINES["_LARGEFILE_SOURCE"] = True - DEFINES["__STDC_CONSTANT_MACROS"] = True - DEFINES["__STDC_FORMAT_MACROS"] = True - -if CONFIG["OS_TARGET"] == "WINNT": - - DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True - DEFINES["NOMINMAX"] = True - DEFINES["NTDDI_VERSION"] = "0x0A000000" - DEFINES["PSAPI_VERSION"] = "2" - DEFINES["RTC_ENABLE_WIN_WGC"] = True - DEFINES["UNICODE"] = True - DEFINES["USE_AURA"] = "1" - DEFINES["WEBRTC_WIN"] = True - DEFINES["WIN32"] = True - DEFINES["WIN32_LEAN_AND_MEAN"] = True - DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP" - DEFINES["WINVER"] = "0x0A00" - DEFINES["_ATL_NO_OPENGL"] = True - DEFINES["_CRT_RAND_S"] = True - DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True - DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True - DEFINES["_HAS_EXCEPTIONS"] = "0" - DEFINES["_HAS_NODISCARD"] = True - DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True - DEFINES["_SECURE_ATL"] = True - DEFINES["_UNICODE"] = True - DEFINES["_WIN32_WINNT"] = "0x0A00" - DEFINES["_WINDOWS"] = True - DEFINES["__STD_C"] = True - - OS_LIBS += [ - "crypt32", - "iphlpapi", - "secur32", - "winmm" - ] - -if CONFIG["TARGET_CPU"] == "aarch64": - - DEFINES["WEBRTC_ARCH_ARM64"] = True - DEFINES["WEBRTC_HAS_NEON"] = True - -if CONFIG["TARGET_CPU"] == "arm": - - DEFINES["WEBRTC_ARCH_ARM"] = True - DEFINES["WEBRTC_ARCH_ARM_V7"] = True - DEFINES["WEBRTC_HAS_NEON"] = True - -if CONFIG["TARGET_CPU"] == "mips32": - - DEFINES["MIPS32_LE"] = True - DEFINES["MIPS_FPU_LE"] = True - DEFINES["_GNU_SOURCE"] = True - -if CONFIG["TARGET_CPU"] == "mips64": - - DEFINES["_GNU_SOURCE"] = True - -if CONFIG["TARGET_CPU"] == "x86": - - DEFINES["WEBRTC_ENABLE_AVX2"] = True - -if CONFIG["TARGET_CPU"] == "x86_64": - - DEFINES["WEBRTC_ENABLE_AVX2"] = True - -if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android": - - DEFINES["_DEBUG"] = True - -if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin": - - DEFINES["_DEBUG"] = True - -if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux": - - DEFINES["_DEBUG"] = True - -if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD": - - DEFINES["_DEBUG"] = True - -if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT": - - DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" - -if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux": - - DEFINES["USE_X11"] = "1" - -if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": - - OS_LIBS += [ - "unwind" - ] - -if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": - - DEFINES["_GNU_SOURCE"] = True - -if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": - - DEFINES["_GNU_SOURCE"] = True - -if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": - - DEFINES["_GNU_SOURCE"] = True - -if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": - - DEFINES["_GNU_SOURCE"] = True - -Library("callfactory_api_gn") diff --git a/third_party/libwebrtc/api/candidate.cc b/third_party/libwebrtc/api/candidate.cc index 90cb326823..865f8e5787 100644 --- a/third_party/libwebrtc/api/candidate.cc +++ b/third_party/libwebrtc/api/candidate.cc @@ -17,6 +17,11 @@ namespace cricket { +const char LOCAL_PORT_TYPE[] = "local"; +const char STUN_PORT_TYPE[] = "stun"; +const char PRFLX_PORT_TYPE[] = "prflx"; +const char RELAY_PORT_TYPE[] = "relay"; + Candidate::Candidate() : id_(rtc::CreateRandomString(8)), component_(0), @@ -57,6 +62,19 @@ Candidate::Candidate(const Candidate&) = default; Candidate::~Candidate() = default; +bool Candidate::is_local() const { + return type_ == LOCAL_PORT_TYPE; +} +bool Candidate::is_stun() const { + return type_ == STUN_PORT_TYPE; +} +bool Candidate::is_prflx() const { + return type_ == PRFLX_PORT_TYPE; +} +bool Candidate::is_relay() const { + return type_ == RELAY_PORT_TYPE; +} + bool Candidate::IsEquivalent(const Candidate& c) const { // We ignore the network name, since that is just debug information, and // the priority and the network cost, since they should be the same if the diff --git a/third_party/libwebrtc/api/candidate.h b/third_party/libwebrtc/api/candidate.h index 8141d8ce38..d48f4fc559 100644 --- a/third_party/libwebrtc/api/candidate.h +++ b/third_party/libwebrtc/api/candidate.h @@ -26,6 +26,13 @@ namespace cricket { +// TODO(tommi): These are temporarily here, moved from `port.h` and will +// eventually be removed once we use enums instead of strings for these values. +RTC_EXPORT extern const char LOCAL_PORT_TYPE[]; +RTC_EXPORT extern const char STUN_PORT_TYPE[]; +RTC_EXPORT extern const char PRFLX_PORT_TYPE[]; +RTC_EXPORT extern const char RELAY_PORT_TYPE[]; + // TURN servers are limited to 32 in accordance with // https://w3c.github.io/webrtc-pc/#dom-rtcconfiguration-iceservers static constexpr size_t kMaxTurnServers = 32; @@ -73,27 +80,6 @@ class RTC_EXPORT Candidate { uint32_t priority() const { return priority_; } void set_priority(const uint32_t priority) { priority_ = priority; } - // TODO(pthatcher): Remove once Chromium's jingle/glue/utils.cc - // doesn't use it. - // Maps old preference (which was 0.0-1.0) to match priority (which - // is 0-2^32-1) to to match RFC 5245, section 4.1.2.1. Also see - // https://docs.google.com/a/google.com/document/d/ - // 1iNQDiwDKMh0NQOrCqbj3DKKRT0Dn5_5UJYhmZO-t7Uc/edit - float preference() const { - // The preference value is clamped to two decimal precision. - return static_cast(((priority_ >> 24) * 100 / 127) / 100.0); - } - - // TODO(pthatcher): Remove once Chromium's jingle/glue/utils.cc - // doesn't use it. - void set_preference(float preference) { - // Limiting priority to UINT_MAX when value exceeds uint32_t max. - // This can happen for e.g. when preference = 3. - uint64_t prio_val = static_cast(preference * 127) << 24; - priority_ = static_cast( - std::min(prio_val, static_cast(UINT_MAX))); - } - // TODO(honghaiz): Change to usernameFragment or ufrag. const std::string& username() const { return username_; } void set_username(absl::string_view username) { Assign(username_, username); } @@ -111,6 +97,32 @@ class RTC_EXPORT Candidate { Assign(type_, type); } + // Provide these simple checkers to abstract away dependency on the port types + // that are currently defined outside of Candidate. This will ease the change + // from the string type to an enum. + bool is_local() const; + bool is_stun() const; + bool is_prflx() const; + bool is_relay() const; + + // Returns the type preference, a value between 0-126 inclusive, with 0 being + // the lowest preference value, as described in RFC 5245. + // https://datatracker.ietf.org/doc/html/rfc5245#section-4.1.2.1 + int type_preference() const { + // From https://datatracker.ietf.org/doc/html/rfc5245#section-4.1.4 : + // It is RECOMMENDED that default candidates be chosen based on the + // likelihood of those candidates to work with the peer that is being + // contacted. + // I.e. it is recommended that relayed > reflexive > host. + if (is_local()) + return 1; // Host. + if (is_stun()) + return 2; // Reflexive. + if (is_relay()) + return 3; // Relayed. + return 0; // Unknown, lowest preference. + } + const std::string& network_name() const { return network_name_; } void set_network_name(absl::string_view network_name) { Assign(network_name_, network_name); diff --git a/third_party/libwebrtc/api/create_peerconnection_factory.cc b/third_party/libwebrtc/api/create_peerconnection_factory.cc index 5d3aace05f..bd77f74882 100644 --- a/third_party/libwebrtc/api/create_peerconnection_factory.cc +++ b/third_party/libwebrtc/api/create_peerconnection_factory.cc @@ -48,8 +48,7 @@ rtc::scoped_refptr CreatePeerConnectionFactory( dependencies.signaling_thread = signaling_thread; dependencies.task_queue_factory = CreateDefaultTaskQueueFactory(field_trials.get()); - dependencies.event_log_factory = std::make_unique( - dependencies.task_queue_factory.get()); + dependencies.event_log_factory = std::make_unique(); dependencies.trials = std::move(field_trials); if (network_thread) { diff --git a/third_party/libwebrtc/api/enable_media.cc b/third_party/libwebrtc/api/enable_media.cc index a05b1b328a..91938cc320 100644 --- a/third_party/libwebrtc/api/enable_media.cc +++ b/third_party/libwebrtc/api/enable_media.cc @@ -15,7 +15,7 @@ #include "api/environment/environment.h" #include "api/peer_connection_interface.h" -#include "call/call_factory.h" +#include "call/create_call.h" #include "media/engine/webrtc_media_engine.h" #include "media/engine/webrtc_video_engine.h" #include "media/engine/webrtc_voice_engine.h" @@ -37,8 +37,7 @@ class MediaFactoryImpl : public MediaFactory { ~MediaFactoryImpl() override = default; std::unique_ptr CreateCall(const CallConfig& config) override { - CallFactory call_factory; - return static_cast(call_factory).CreateCall(config); + return webrtc::CreateCall(config); } std::unique_ptr CreateMediaEngine( diff --git a/third_party/libwebrtc/api/environment/environment_factory.cc b/third_party/libwebrtc/api/environment/environment_factory.cc index c0b681aa08..6f0ec40dbe 100644 --- a/third_party/libwebrtc/api/environment/environment_factory.cc +++ b/third_party/libwebrtc/api/environment/environment_factory.cc @@ -97,12 +97,22 @@ Environment EnvironmentFactory::CreateWithDefaults() && { if (field_trials_ == nullptr) { Set(std::make_unique()); } +#if defined(WEBRTC_MOZILLA_BUILD) + // We want to use our clock, not GetRealTimeClockRaw, and we avoid + // building the code under third_party/libwebrtc/task_queue. To + // ensure we're setting up things correctly, namely providing an + // Environment object with a preset task_queue_factory and clock, + // we'll do a release assert here. + RTC_CHECK(clock_); + RTC_CHECK(task_queue_factory_); +#else if (clock_ == nullptr) { Set(Clock::GetRealTimeClock()); } if (task_queue_factory_ == nullptr) { Set(CreateDefaultTaskQueueFactory(field_trials_)); } +#endif if (event_log_ == nullptr) { Set(std::make_unique()); } diff --git a/third_party/libwebrtc/api/environment/environment_factory_gn/moz.build b/third_party/libwebrtc/api/environment/environment_factory_gn/moz.build new file mode 100644 index 0000000000..77a2224baf --- /dev/null +++ b/third_party/libwebrtc/api/environment/environment_factory_gn/moz.build @@ -0,0 +1,231 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + + ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ### + ### DO NOT edit it by hand. ### + +COMPILE_FLAGS["OS_INCLUDES"] = [] +AllowCompilerWarnings() + +DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" +DEFINES["WEBRTC_LIBRARY_IMPL"] = True +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" + +FINAL_LIBRARY = "webrtc" + + +LOCAL_INCLUDES += [ + "!/ipc/ipdl/_ipdlheaders", + "!/third_party/libwebrtc/gen", + "/ipc/chromium/src", + "/third_party/libwebrtc/", + "/third_party/libwebrtc/third_party/abseil-cpp/", + "/tools/profiler/public" +] + +UNIFIED_SOURCES += [ + "/third_party/libwebrtc/api/environment/environment_factory.cc" +] + +if not CONFIG["MOZ_DEBUG"]: + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0" + DEFINES["NDEBUG"] = True + DEFINES["NVALGRIND"] = True + +if CONFIG["MOZ_DEBUG"] == "1": + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1" + +if CONFIG["OS_TARGET"] == "Android": + + DEFINES["ANDROID"] = True + DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1" + DEFINES["HAVE_SYS_UIO_H"] = True + DEFINES["WEBRTC_ANDROID"] = True + DEFINES["WEBRTC_ANDROID_OPENSLES"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_GNU_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + + OS_LIBS += [ + "log" + ] + +if CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["WEBRTC_MAC"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True + DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0" + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_AURA"] = "1" + DEFINES["USE_GLIB"] = "1" + DEFINES["USE_NSS_CERTS"] = "1" + DEFINES["USE_OZONE"] = "1" + DEFINES["USE_UDEV"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + DEFINES["_LARGEFILE64_SOURCE"] = True + DEFINES["_LARGEFILE_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + + OS_LIBS += [ + "rt" + ] + +if CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["USE_GLIB"] = "1" + DEFINES["USE_OZONE"] = "1" + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + DEFINES["_LARGEFILE64_SOURCE"] = True + DEFINES["_LARGEFILE_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "WINNT": + + DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True + DEFINES["NOMINMAX"] = True + DEFINES["NTDDI_VERSION"] = "0x0A000000" + DEFINES["PSAPI_VERSION"] = "2" + DEFINES["RTC_ENABLE_WIN_WGC"] = True + DEFINES["UNICODE"] = True + DEFINES["USE_AURA"] = "1" + DEFINES["WEBRTC_WIN"] = True + DEFINES["WIN32"] = True + DEFINES["WIN32_LEAN_AND_MEAN"] = True + DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP" + DEFINES["WINVER"] = "0x0A00" + DEFINES["_ATL_NO_OPENGL"] = True + DEFINES["_CRT_RAND_S"] = True + DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True + DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True + DEFINES["_HAS_EXCEPTIONS"] = "0" + DEFINES["_HAS_NODISCARD"] = True + DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True + DEFINES["_SECURE_ATL"] = True + DEFINES["_UNICODE"] = True + DEFINES["_WIN32_WINNT"] = "0x0A00" + DEFINES["_WINDOWS"] = True + DEFINES["__STD_C"] = True + + OS_LIBS += [ + "crypt32", + "iphlpapi", + "secur32", + "winmm" + ] + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT": + + DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" + +if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_X11"] = "1" + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("environment_factory_gn") diff --git a/third_party/libwebrtc/api/fec_controller.h b/third_party/libwebrtc/api/fec_controller.h index a9be656d6e..5c2aa3b786 100644 --- a/third_party/libwebrtc/api/fec_controller.h +++ b/third_party/libwebrtc/api/fec_controller.h @@ -14,6 +14,7 @@ #include #include +#include "api/environment/environment.h" #include "api/video/video_frame_type.h" #include "modules/include/module_fec_types.h" @@ -87,8 +88,10 @@ class FecController { class FecControllerFactoryInterface { public: - virtual std::unique_ptr CreateFecController() = 0; virtual ~FecControllerFactoryInterface() = default; + + virtual std::unique_ptr CreateFecController( + const Environment& env) = 0; }; } // namespace webrtc diff --git a/third_party/libwebrtc/api/metronome/BUILD.gn b/third_party/libwebrtc/api/metronome/BUILD.gn index 3d3d876df0..f879d5f2fb 100644 --- a/third_party/libwebrtc/api/metronome/BUILD.gn +++ b/third_party/libwebrtc/api/metronome/BUILD.gn @@ -13,7 +13,7 @@ rtc_source_set("metronome") { sources = [ "metronome.h" ] deps = [ "../../rtc_base/system:rtc_export", - "../task_queue", "../units:time_delta", ] + absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ] } diff --git a/third_party/libwebrtc/api/metronome/metronome.h b/third_party/libwebrtc/api/metronome/metronome.h index a312b1c862..4d50a3ecd0 100644 --- a/third_party/libwebrtc/api/metronome/metronome.h +++ b/third_party/libwebrtc/api/metronome/metronome.h @@ -11,7 +11,7 @@ #ifndef API_METRONOME_METRONOME_H_ #define API_METRONOME_METRONOME_H_ -#include "api/task_queue/task_queue_base.h" +#include "absl/functional/any_invocable.h" #include "api/units/time_delta.h" #include "rtc_base/system/rtc_export.h" diff --git a/third_party/libwebrtc/api/metronome/test/BUILD.gn b/third_party/libwebrtc/api/metronome/test/BUILD.gn index f415d98a0b..94ecf9f727 100644 --- a/third_party/libwebrtc/api/metronome/test/BUILD.gn +++ b/third_party/libwebrtc/api/metronome/test/BUILD.gn @@ -16,15 +16,8 @@ rtc_library("fake_metronome") { ] deps = [ "..:metronome", - "../..:priority", - "../..:sequence_checker", - "../../../rtc_base:macromagic", - "../../../rtc_base:rtc_event", - "../../../rtc_base:rtc_task_queue", - "../../../rtc_base/synchronization:mutex", - "../../../rtc_base/task_utils:repeating_task", - "../../../test:test_support", "../../task_queue", "../../units:time_delta", ] + absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ] } diff --git a/third_party/libwebrtc/api/metronome/test/fake_metronome.cc b/third_party/libwebrtc/api/metronome/test/fake_metronome.cc index 025f7ce5a6..bd54d5b0ba 100644 --- a/third_party/libwebrtc/api/metronome/test/fake_metronome.cc +++ b/third_party/libwebrtc/api/metronome/test/fake_metronome.cc @@ -13,13 +13,9 @@ #include #include -#include "api/priority.h" -#include "api/sequence_checker.h" +#include "absl/functional/any_invocable.h" #include "api/task_queue/task_queue_base.h" -#include "api/task_queue/task_queue_factory.h" #include "api/units/time_delta.h" -#include "rtc_base/event.h" -#include "rtc_base/task_utils/repeating_task.h" namespace webrtc::test { @@ -49,6 +45,10 @@ void ForcedTickMetronome::Tick() { FakeMetronome::FakeMetronome(TimeDelta tick_period) : tick_period_(tick_period) {} +void FakeMetronome::SetTickPeriod(TimeDelta tick_period) { + tick_period_ = tick_period; +} + void FakeMetronome::RequestCallOnNextTick( absl::AnyInvocable callback) { TaskQueueBase* current = TaskQueueBase::Current(); diff --git a/third_party/libwebrtc/api/metronome/test/fake_metronome.h b/third_party/libwebrtc/api/metronome/test/fake_metronome.h index 73c938e9cd..9702062cf6 100644 --- a/third_party/libwebrtc/api/metronome/test/fake_metronome.h +++ b/third_party/libwebrtc/api/metronome/test/fake_metronome.h @@ -11,18 +11,12 @@ #ifndef API_METRONOME_TEST_FAKE_METRONOME_H_ #define API_METRONOME_TEST_FAKE_METRONOME_H_ -#include -#include +#include #include +#include "absl/functional/any_invocable.h" #include "api/metronome/metronome.h" -#include "api/task_queue/task_queue_base.h" -#include "api/task_queue/task_queue_factory.h" #include "api/units/time_delta.h" -#include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" -#include "rtc_base/task_utils/repeating_task.h" -#include "rtc_base/thread_annotations.h" namespace webrtc::test { @@ -48,19 +42,18 @@ class ForcedTickMetronome : public Metronome { // FakeMetronome is a metronome that ticks based on a repeating task at the // `tick_period` provided in the constructor. It is designed for use with // simulated task queues for unit tests. -// -// `Stop()` must be called before destruction, as it cancels the metronome tick -// on the proper task queue. class FakeMetronome : public Metronome { public: explicit FakeMetronome(TimeDelta tick_period); + void SetTickPeriod(TimeDelta tick_period); + // Metronome implementation. void RequestCallOnNextTick(absl::AnyInvocable callback) override; TimeDelta TickPeriod() const override; private: - const TimeDelta tick_period_; + TimeDelta tick_period_; std::vector> callbacks_; }; diff --git a/third_party/libwebrtc/api/peer_connection_interface.h b/third_party/libwebrtc/api/peer_connection_interface.h index 74c4702cd2..3c225eb28a 100644 --- a/third_party/libwebrtc/api/peer_connection_interface.h +++ b/third_party/libwebrtc/api/peer_connection_interface.h @@ -686,7 +686,6 @@ class RTC_EXPORT PeerConnectionInterface : public webrtc::RefCountInterface { PortAllocatorConfig port_allocator_config; // The burst interval of the pacer, see TaskQueuePacedSender constructor. - // TODO(hbos): Deprecated, Remove once Chromium is not setting it. absl::optional pacer_burst_interval; // @@ -1441,7 +1440,12 @@ struct RTC_EXPORT PeerConnectionFactoryDependencies final { std::unique_ptr trials; std::unique_ptr transport_controller_send_factory; - std::unique_ptr metronome; + // Metronome used for decoding, must be called on the worker thread. + std::unique_ptr decode_metronome; + // Metronome used for encoding, must be called on the worker thread. + // TODO(b/304158952): Consider merging into a single metronome for all codec + // usage. + std::unique_ptr encode_metronome; // Media specific dependencies. Unused when `media_factory == nullptr`. rtc::scoped_refptr adm; diff --git a/third_party/libwebrtc/api/rtc_event_log/rtc_event_log_factory.cc b/third_party/libwebrtc/api/rtc_event_log/rtc_event_log_factory.cc index 30fc6f126f..bfe272d2a8 100644 --- a/third_party/libwebrtc/api/rtc_event_log/rtc_event_log_factory.cc +++ b/third_party/libwebrtc/api/rtc_event_log/rtc_event_log_factory.cc @@ -31,12 +31,7 @@ absl::Nonnull> RtcEventLogFactory::Create( if (env.field_trials().IsEnabled("WebRTC-RtcEventLogKillSwitch")) { return std::make_unique(); } - RtcEventLog::EncodingType encoding_type = - env.field_trials().IsDisabled("WebRTC-RtcEventLogNewFormat") - ? RtcEventLog::EncodingType::Legacy - : RtcEventLog::EncodingType::NewFormat; - return std::make_unique( - RtcEventLogImpl::CreateEncoder(encoding_type), &env.task_queue_factory()); + return std::make_unique(env); #endif } diff --git a/third_party/libwebrtc/api/rtc_event_log/rtc_event_log_factory.h b/third_party/libwebrtc/api/rtc_event_log/rtc_event_log_factory.h index 21a670e1a7..1deb0612bf 100644 --- a/third_party/libwebrtc/api/rtc_event_log/rtc_event_log_factory.h +++ b/third_party/libwebrtc/api/rtc_event_log/rtc_event_log_factory.h @@ -26,10 +26,9 @@ class RTC_EXPORT RtcEventLogFactory : public RtcEventLogFactoryInterface { public: RtcEventLogFactory() = default; - // TODO(bugs.webrtc.org/15656): deprecate and delete constructor taking - // task queue factory in favor of using task queue factory provided through - // the Environment parameter in Create function. + [[deprecated("Use default constructor")]] // explicit RtcEventLogFactory(TaskQueueFactory* task_queue_factory) {} + ~RtcEventLogFactory() override = default; absl::Nonnull> Create( diff --git a/third_party/libwebrtc/api/rtp_parameters.cc b/third_party/libwebrtc/api/rtp_parameters.cc index cf8b3ad3dc..ad0f3c9396 100644 --- a/third_party/libwebrtc/api/rtp_parameters.cc +++ b/third_party/libwebrtc/api/rtp_parameters.cc @@ -15,6 +15,7 @@ #include #include "api/array_view.h" +#include "media/base/media_constants.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { @@ -47,6 +48,14 @@ RtcpFeedback::~RtcpFeedback() = default; RtpCodec::RtpCodec() = default; RtpCodec::RtpCodec(const RtpCodec&) = default; RtpCodec::~RtpCodec() = default; +bool RtpCodec::IsResiliencyCodec() const { + return name == cricket::kRtxCodecName || name == cricket::kRedCodecName || + name == cricket::kUlpfecCodecName || + name == cricket::kFlexfecCodecName; +} +bool RtpCodec::IsMediaCodec() const { + return !IsResiliencyCodec() && name != cricket::kComfortNoiseCodecName; +} RtpCodecCapability::RtpCodecCapability() = default; RtpCodecCapability::~RtpCodecCapability() = default; diff --git a/third_party/libwebrtc/api/rtp_parameters.h b/third_party/libwebrtc/api/rtp_parameters.h index 09473a6ce9..025817cf37 100644 --- a/third_party/libwebrtc/api/rtp_parameters.h +++ b/third_party/libwebrtc/api/rtp_parameters.h @@ -29,6 +29,8 @@ namespace webrtc { +using CodecParameterMap = std::map; + // These structures are intended to mirror those defined by: // http://draft.ortc.org/#rtcrtpdictionaries* // Contains everything specified as of 2017 Jan 24. @@ -165,6 +167,8 @@ struct RTC_EXPORT RtpCodec { parameters == o.parameters; } bool operator!=(const RtpCodec& o) const { return !(*this == o); } + bool IsResiliencyCodec() const; + bool IsMediaCodec() const; }; // RtpCodecCapability is to RtpCodecParameters as RtpCapabilities is to diff --git a/third_party/libwebrtc/api/stats/attribute.h b/third_party/libwebrtc/api/stats/attribute.h new file mode 100644 index 0000000000..09211f469c --- /dev/null +++ b/third_party/libwebrtc/api/stats/attribute.h @@ -0,0 +1,96 @@ +/* + * Copyright 2024 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_STATS_ATTRIBUTE_H_ +#define API_STATS_ATTRIBUTE_H_ + +#include +#include +#include +#include + +#include "absl/types/variant.h" +#include "api/stats/rtc_stats_member.h" +#include "rtc_base/system/rtc_export.h" + +namespace webrtc { + +// A light-weight wrapper of an RTCStats attribute (an individual metric). +class RTC_EXPORT Attribute { + public: + // TODO(https://crbug.com/webrtc/15164): Replace uses of RTCStatsMember + // with absl::optional and update these pointer types. + typedef absl::variant*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*, + const RTCStatsMember>*> + StatVariant; + + template + explicit Attribute(const char* name, const RTCStatsMember* attribute) + : name_(name), attribute_(attribute) {} + + const char* name() const; + const StatVariant& as_variant() const; + + bool has_value() const; + template + bool holds_alternative() const { + return absl::holds_alternative*>(attribute_); + } + template + absl::optional as_optional() const { + RTC_CHECK(holds_alternative()); + if (!has_value()) { + return absl::nullopt; + } + return absl::optional(get()); + } + template + const T& get() const { + RTC_CHECK(holds_alternative()); + RTC_CHECK(has_value()); + return absl::get*>(attribute_)->value(); + } + + bool is_sequence() const; + bool is_string() const; + std::string ToString() const; + + bool operator==(const Attribute& other) const; + bool operator!=(const Attribute& other) const; + + private: + const char* name_; + StatVariant attribute_; +}; + +struct RTC_EXPORT AttributeInit { + AttributeInit(const char* name, const Attribute::StatVariant& variant); + + const char* name; + Attribute::StatVariant variant; +}; + +} // namespace webrtc + +#endif // API_STATS_ATTRIBUTE_H_ diff --git a/third_party/libwebrtc/api/stats/rtc_stats.h b/third_party/libwebrtc/api/stats/rtc_stats.h index 6cc39a309f..edd293f5c9 100644 --- a/third_party/libwebrtc/api/stats/rtc_stats.h +++ b/third_party/libwebrtc/api/stats/rtc_stats.h @@ -20,7 +20,8 @@ #include #include -#include "absl/types/optional.h" +#include "api/stats/attribute.h" +#include "api/stats/rtc_stats_member.h" #include "api/units/timestamp.h" #include "rtc_base/checks.h" #include "rtc_base/system/rtc_export.h" @@ -28,8 +29,6 @@ namespace webrtc { -class RTCStatsMemberInterface; - // Abstract base class for RTCStats-derived dictionaries, see // https://w3c.github.io/webrtc-stats/. // @@ -40,8 +39,8 @@ class RTCStatsMemberInterface; // Use the `WEBRTC_RTCSTATS_IMPL` macro when implementing subclasses, see macro // for details. // -// Derived classes list their dictionary members, RTCStatsMember, as public -// fields, allowing the following: +// Derived classes list their dictionary attributes (RTCStatsMember to soon +// be replaced by absl::optional) as public fields, allowing the following: // // RTCFooStats foo("fooId", Timestamp::Micros(GetCurrentTime())); // foo.bar = 42; @@ -49,17 +48,18 @@ class RTCStatsMemberInterface; // foo.baz->push_back("hello world"); // uint32_t x = *foo.bar; // -// Pointers to all the members are available with `Members`, allowing iteration: +// Pointers to all the attributes are available with `Attributes()`, allowing +// iteration: // -// for (const RTCStatsMemberInterface* member : foo.Members()) { -// printf("%s = %s\n", member->name(), member->ValueToString().c_str()); +// for (const auto& attribute : foo.Attributes()) { +// printf("%s = %s\n", attribute.name(), attribute.ValueToString().c_str()); // } class RTC_EXPORT RTCStats { public: RTCStats(const std::string& id, Timestamp timestamp) : id_(id), timestamp_(timestamp) {} - - virtual ~RTCStats() {} + RTCStats(const RTCStats& other); + virtual ~RTCStats(); virtual std::unique_ptr copy() const = 0; @@ -69,18 +69,30 @@ class RTC_EXPORT RTCStats { // Returns the static member variable `kType` of the implementing class. virtual const char* type() const = 0; - // Returns a vector of pointers to all the `RTCStatsMemberInterface` members - // of this class. This allows for iteration of members. For a given class, - // `Members` always returns the same members in the same order. - std::vector Members() const; + // Returns all attributes of this stats object, i.e. a list of its individual + // metrics as viewed via the Attribute wrapper. + std::vector Attributes() const; + template + Attribute GetAttribute(const RTCStatsMember& stat) const { + for (const auto& attribute : Attributes()) { + if (!attribute.holds_alternative()) { + continue; + } + if (absl::get*>(attribute.as_variant()) == + &stat) { + return attribute; + } + } + RTC_CHECK_NOTREACHED(); + } // Checks if the two stats objects are of the same type and have the same - // member values. Timestamps are not compared. These operators are exposed for - // testing. + // attribute values. Timestamps are not compared. These operators are exposed + // for testing. bool operator==(const RTCStats& other) const; bool operator!=(const RTCStats& other) const; // Creates a JSON readable string representation of the stats - // object, listing all of its members (names and values). + // object, listing all of its attributes (names and values). std::string ToJson() const; // Downcasts the stats object to an `RTCStats` subclass `T`. DCHECKs that the @@ -92,12 +104,8 @@ class RTC_EXPORT RTCStats { } protected: - // Gets a vector of all members of this `RTCStats` object, including members - // derived from parent classes. `additional_capacity` is how many more members - // shall be reserved in the vector (so that subclasses can allocate a vector - // with room for both parent and child members without it having to resize). - virtual std::vector - MembersOfThisObjectAndAncestors(size_t additional_capacity) const; + virtual std::vector AttributesImpl( + size_t additional_capacity) const; std::string const id_; Timestamp timestamp_; @@ -109,9 +117,8 @@ class RTC_EXPORT RTCStats { // // These macros declare (in _DECL) and define (in _IMPL) the static `kType` and // overrides methods as required by subclasses of `RTCStats`: `copy`, `type` and -// `MembersOfThisObjectAndAncestors`. The |...| argument is a list of addresses -// to each member defined in the implementing class. The list must have at least -// one member. +// `AttributesImpl`. The |...| argument is a list of addresses to each attribute +// defined in the implementing class. The list must have at least one attribute. // // (Since class names need to be known to implement these methods this cannot be // part of the base `RTCStats`. While these methods could be implemented using @@ -144,247 +151,45 @@ class RTC_EXPORT RTCStats { // bar("bar") { // } // -#define WEBRTC_RTCSTATS_DECL() \ - protected: \ - std::vector \ - MembersOfThisObjectAndAncestors(size_t local_var_additional_capacity) \ - const override; \ - \ - public: \ - static const char kType[]; \ - \ - std::unique_ptr copy() const override; \ - const char* type() const override - -#define WEBRTC_RTCSTATS_IMPL(this_class, parent_class, type_str, ...) \ - const char this_class::kType[] = type_str; \ - \ - std::unique_ptr this_class::copy() const { \ - return std::make_unique(*this); \ - } \ - \ - const char* this_class::type() const { \ - return this_class::kType; \ - } \ - \ - std::vector \ - this_class::MembersOfThisObjectAndAncestors( \ - size_t local_var_additional_capacity) const { \ - const webrtc::RTCStatsMemberInterface* local_var_members[] = { \ - __VA_ARGS__}; \ - size_t local_var_members_count = \ - sizeof(local_var_members) / sizeof(local_var_members[0]); \ - std::vector \ - local_var_members_vec = parent_class::MembersOfThisObjectAndAncestors( \ - local_var_members_count + local_var_additional_capacity); \ - RTC_DCHECK_GE( \ - local_var_members_vec.capacity() - local_var_members_vec.size(), \ - local_var_members_count + local_var_additional_capacity); \ - local_var_members_vec.insert(local_var_members_vec.end(), \ - &local_var_members[0], \ - &local_var_members[local_var_members_count]); \ - return local_var_members_vec; \ - } - -// A version of WEBRTC_RTCSTATS_IMPL() where "..." is omitted, used to avoid a -// compile error on windows. This is used if the stats dictionary does not -// declare any members of its own (but perhaps its parent dictionary does). -#define WEBRTC_RTCSTATS_IMPL_NO_MEMBERS(this_class, parent_class, type_str) \ - const char this_class::kType[] = type_str; \ - \ - std::unique_ptr this_class::copy() const { \ - return std::make_unique(*this); \ - } \ +#define WEBRTC_RTCSTATS_DECL() \ + protected: \ + std::vector AttributesImpl(size_t additional_capacity) \ + const override; \ \ - const char* this_class::type() const { \ - return this_class::kType; \ - } \ + public: \ + static const char kType[]; \ \ - std::vector \ - this_class::MembersOfThisObjectAndAncestors( \ - size_t local_var_additional_capacity) const { \ - return parent_class::MembersOfThisObjectAndAncestors(0); \ - } - -// Interface for `RTCStats` members, which have a name and a value of a type -// defined in a subclass. Only the types listed in `Type` are supported, these -// are implemented by `RTCStatsMember`. The value of a member may be -// undefined, the value can only be read if `is_defined`. -class RTCStatsMemberInterface { - public: - // Member value types. - enum Type { - kBool, // bool - kInt32, // int32_t - kUint32, // uint32_t - kInt64, // int64_t - kUint64, // uint64_t - kDouble, // double - kString, // std::string - - kSequenceBool, // std::vector - kSequenceInt32, // std::vector - kSequenceUint32, // std::vector - kSequenceInt64, // std::vector - kSequenceUint64, // std::vector - kSequenceDouble, // std::vector - kSequenceString, // std::vector - - kMapStringUint64, // std::map - kMapStringDouble, // std::map - }; - - virtual ~RTCStatsMemberInterface() {} - - const char* name() const { return name_; } - virtual Type type() const = 0; - virtual bool is_sequence() const = 0; - virtual bool is_string() const = 0; - virtual bool is_defined() const = 0; - // Type and value comparator. The names are not compared. These operators are - // exposed for testing. - bool operator==(const RTCStatsMemberInterface& other) const { - return IsEqual(other); - } - bool operator!=(const RTCStatsMemberInterface& other) const { - return !(*this == other); - } - virtual std::string ValueToString() const = 0; - // This is the same as ValueToString except for kInt64 and kUint64 types, - // where the value is represented as a double instead of as an integer. - // Since JSON stores numbers as floating point numbers, very large integers - // cannot be accurately represented, so we prefer to display them as doubles - // instead. - virtual std::string ValueToJson() const = 0; - - template - const T& cast_to() const { - RTC_DCHECK_EQ(type(), T::StaticType()); - return static_cast(*this); - } - - protected: - explicit RTCStatsMemberInterface(const char* name) : name_(name) {} - - virtual bool IsEqual(const RTCStatsMemberInterface& other) const = 0; - - const char* const name_; -}; - -// Template implementation of `RTCStatsMemberInterface`. -// The supported types are the ones described by -// `RTCStatsMemberInterface::Type`. -template -class RTCStatsMember : public RTCStatsMemberInterface { - public: - explicit RTCStatsMember(const char* name) - : RTCStatsMemberInterface(name), value_() {} - RTCStatsMember(const char* name, const T& value) - : RTCStatsMemberInterface(name), value_(value) {} - RTCStatsMember(const char* name, T&& value) - : RTCStatsMemberInterface(name), value_(std::move(value)) {} - explicit RTCStatsMember(const RTCStatsMember& other) - : RTCStatsMemberInterface(other.name_), value_(other.value_) {} - explicit RTCStatsMember(RTCStatsMember&& other) - : RTCStatsMemberInterface(other.name_), value_(std::move(other.value_)) {} - - static Type StaticType(); - Type type() const override { return StaticType(); } - bool is_sequence() const override; - bool is_string() const override; - bool is_defined() const override { return value_.has_value(); } - std::string ValueToString() const override; - std::string ValueToJson() const override; - - template - inline T ValueOrDefault(U default_value) const { - return value_.value_or(default_value); - } - - // Assignment operators. - T& operator=(const T& value) { - value_ = value; - return value_.value(); - } - T& operator=(const T&& value) { - value_ = std::move(value); - return value_.value(); - } - - // Getter methods that look the same as absl::optional. Please prefer these - // in order to unblock replacing RTCStatsMember with absl::optional in - // the future (https://crbug.com/webrtc/15164). - bool has_value() const { return value_.has_value(); } - const T& value() const { return value_.value(); } - T& value() { return value_.value(); } - T& operator*() { - RTC_DCHECK(value_); - return *value_; - } - const T& operator*() const { - RTC_DCHECK(value_); - return *value_; - } - T* operator->() { - RTC_DCHECK(value_); - return &(*value_); - } - const T* operator->() const { - RTC_DCHECK(value_); - return &(*value_); - } + std::unique_ptr copy() const override; \ + const char* type() const override - protected: - bool IsEqual(const RTCStatsMemberInterface& other) const override { - if (type() != other.type()) - return false; - const RTCStatsMember& other_t = - static_cast&>(other); - return value_ == other_t.value_; +#define WEBRTC_RTCSTATS_IMPL(this_class, parent_class, type_str, ...) \ + const char this_class::kType[] = type_str; \ + \ + std::unique_ptr this_class::copy() const { \ + return std::make_unique(*this); \ + } \ + \ + const char* this_class::type() const { \ + return this_class::kType; \ + } \ + \ + std::vector this_class::AttributesImpl( \ + size_t additional_capacity) const { \ + webrtc::AttributeInit attribute_inits[] = {__VA_ARGS__}; \ + size_t attribute_inits_size = \ + sizeof(attribute_inits) / sizeof(attribute_inits[0]); \ + std::vector attributes = parent_class::AttributesImpl( \ + attribute_inits_size + additional_capacity); \ + for (size_t i = 0; i < attribute_inits_size; ++i) { \ + attributes.push_back(absl::visit( \ + [&](const auto* field) { \ + return Attribute(attribute_inits[i].name, field); \ + }, \ + attribute_inits[i].variant)); \ + } \ + return attributes; \ } - private: - absl::optional value_; -}; - -namespace rtc_stats_internal { - -typedef std::map MapStringUint64; -typedef std::map MapStringDouble; - -} // namespace rtc_stats_internal - -#define WEBRTC_DECLARE_RTCSTATSMEMBER(T) \ - template <> \ - RTC_EXPORT RTCStatsMemberInterface::Type RTCStatsMember::StaticType(); \ - template <> \ - RTC_EXPORT bool RTCStatsMember::is_sequence() const; \ - template <> \ - RTC_EXPORT bool RTCStatsMember::is_string() const; \ - template <> \ - RTC_EXPORT std::string RTCStatsMember::ValueToString() const; \ - template <> \ - RTC_EXPORT std::string RTCStatsMember::ValueToJson() const; \ - extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) \ - RTCStatsMember - -WEBRTC_DECLARE_RTCSTATSMEMBER(bool); -WEBRTC_DECLARE_RTCSTATSMEMBER(int32_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(uint32_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(int64_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(uint64_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(double); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::string); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); -WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64); -WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble); - } // namespace webrtc #endif // API_STATS_RTC_STATS_H_ diff --git a/third_party/libwebrtc/api/stats/rtc_stats_member.h b/third_party/libwebrtc/api/stats/rtc_stats_member.h new file mode 100644 index 0000000000..9039569ede --- /dev/null +++ b/third_party/libwebrtc/api/stats/rtc_stats_member.h @@ -0,0 +1,185 @@ +/* + * Copyright 2023 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_STATS_RTC_STATS_MEMBER_H_ +#define API_STATS_RTC_STATS_MEMBER_H_ + +#include +#include +#include +#include + +#include "absl/types/optional.h" +#include "rtc_base/checks.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/system/rtc_export_template.h" + +namespace webrtc { + +// Interface for `RTCStats` members, which have a name and a value of a type +// defined in a subclass. Only the types listed in `Type` are supported, these +// are implemented by `RTCStatsMember`. The value of a member may be +// undefined, the value can only be read if `is_defined`. +class RTCStatsMemberInterface { + public: + // Member value types. + enum Type { + kBool, // bool + kInt32, // int32_t + kUint32, // uint32_t + kInt64, // int64_t + kUint64, // uint64_t + kDouble, // double + kString, // std::string + + kSequenceBool, // std::vector + kSequenceInt32, // std::vector + kSequenceUint32, // std::vector + kSequenceInt64, // std::vector + kSequenceUint64, // std::vector + kSequenceDouble, // std::vector + kSequenceString, // std::vector + + kMapStringUint64, // std::map + kMapStringDouble, // std::map + }; + + virtual ~RTCStatsMemberInterface() {} + + virtual Type type() const = 0; + virtual bool is_sequence() const = 0; + virtual bool is_string() const = 0; + virtual bool has_value() const = 0; + // Type and value comparator. The names are not compared. These operators are + // exposed for testing. + bool operator==(const RTCStatsMemberInterface& other) const { + return IsEqual(other); + } + bool operator!=(const RTCStatsMemberInterface& other) const { + return !(*this == other); + } + + virtual const RTCStatsMemberInterface* member_ptr() const { return this; } + template + const T& cast_to() const { + RTC_DCHECK_EQ(type(), T::StaticType()); + return static_cast(*member_ptr()); + } + + protected: + virtual bool IsEqual(const RTCStatsMemberInterface& other) const = 0; +}; + +// Template implementation of `RTCStatsMemberInterface`. +// The supported types are the ones described by +// `RTCStatsMemberInterface::Type`. +template +class RTCStatsMember : public RTCStatsMemberInterface { + public: + RTCStatsMember() {} + explicit RTCStatsMember(const T& value) : value_(value) {} + + static Type StaticType(); + Type type() const override { return StaticType(); } + bool is_sequence() const override; + bool is_string() const override; + + template + inline T value_or(U default_value) const { + return value_.value_or(default_value); + } + // TODO(https://crbug.com/webrtc/15164): Migrate to value_or() and delete. + template + inline T ValueOrDefault(U default_value) const { + return value_or(default_value); + } + + // Assignment operators. + T& operator=(const T& value) { + value_ = value; + return value_.value(); + } + T& operator=(const T&& value) { + value_ = std::move(value); + return value_.value(); + } + + // Getter methods that look the same as absl::optional. Please prefer these + // in order to unblock replacing RTCStatsMember with absl::optional in + // the future (https://crbug.com/webrtc/15164). + bool has_value() const override { return value_.has_value(); } + const T& value() const { return value_.value(); } + T& value() { return value_.value(); } + T& operator*() { + RTC_DCHECK(value_); + return *value_; + } + const T& operator*() const { + RTC_DCHECK(value_); + return *value_; + } + T* operator->() { + RTC_DCHECK(value_); + return &(*value_); + } + const T* operator->() const { + RTC_DCHECK(value_); + return &(*value_); + } + + bool IsEqual(const RTCStatsMemberInterface& other) const override { + if (type() != other.type()) + return false; + const RTCStatsMember& other_t = + static_cast&>(other); + return value_ == other_t.value_; + } + + private: + absl::optional value_; +}; + +namespace rtc_stats_internal { + +typedef std::map MapStringUint64; +typedef std::map MapStringDouble; + +} // namespace rtc_stats_internal + +#define WEBRTC_DECLARE_RTCSTATSMEMBER(T) \ + template <> \ + RTC_EXPORT RTCStatsMemberInterface::Type RTCStatsMember::StaticType(); \ + template <> \ + RTC_EXPORT bool RTCStatsMember::is_sequence() const; \ + template <> \ + RTC_EXPORT bool RTCStatsMember::is_string() const; \ + extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) \ + RTCStatsMember + +WEBRTC_DECLARE_RTCSTATSMEMBER(bool); +WEBRTC_DECLARE_RTCSTATSMEMBER(int32_t); +WEBRTC_DECLARE_RTCSTATSMEMBER(uint32_t); +WEBRTC_DECLARE_RTCSTATSMEMBER(int64_t); +WEBRTC_DECLARE_RTCSTATSMEMBER(uint64_t); +WEBRTC_DECLARE_RTCSTATSMEMBER(double); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::string); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); +WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64); +WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble); + +} // namespace webrtc + +#endif // API_STATS_RTC_STATS_MEMBER_H_ diff --git a/third_party/libwebrtc/api/stats/rtcstats_objects.h b/third_party/libwebrtc/api/stats/rtcstats_objects.h index c28b635660..351c2cbefe 100644 --- a/third_party/libwebrtc/api/stats/rtcstats_objects.h +++ b/third_party/libwebrtc/api/stats/rtcstats_objects.h @@ -27,9 +27,7 @@ namespace webrtc { class RTC_EXPORT RTCCertificateStats final : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - RTCCertificateStats(std::string id, Timestamp timestamp); - RTCCertificateStats(const RTCCertificateStats& other); ~RTCCertificateStats() override; RTCStatsMember fingerprint; @@ -42,9 +40,7 @@ class RTC_EXPORT RTCCertificateStats final : public RTCStats { class RTC_EXPORT RTCCodecStats final : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - RTCCodecStats(std::string id, Timestamp timestamp); - RTCCodecStats(const RTCCodecStats& other); ~RTCCodecStats() override; RTCStatsMember transport_id; @@ -59,9 +55,7 @@ class RTC_EXPORT RTCCodecStats final : public RTCStats { class RTC_EXPORT RTCDataChannelStats final : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - RTCDataChannelStats(std::string id, Timestamp timestamp); - RTCDataChannelStats(const RTCDataChannelStats& other); ~RTCDataChannelStats() override; RTCStatsMember label; @@ -78,9 +72,7 @@ class RTC_EXPORT RTCDataChannelStats final : public RTCStats { class RTC_EXPORT RTCIceCandidatePairStats final : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - RTCIceCandidatePairStats(std::string id, Timestamp timestamp); - RTCIceCandidatePairStats(const RTCIceCandidatePairStats& other); ~RTCIceCandidatePairStats() override; RTCStatsMember transport_id; @@ -118,8 +110,6 @@ class RTC_EXPORT RTCIceCandidatePairStats final : public RTCStats { class RTC_EXPORT RTCIceCandidateStats : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - - RTCIceCandidateStats(const RTCIceCandidateStats& other); ~RTCIceCandidateStats() override; RTCStatsMember transport_id; @@ -175,9 +165,7 @@ class RTC_EXPORT RTCRemoteIceCandidateStats final class RTC_EXPORT RTCPeerConnectionStats final : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - RTCPeerConnectionStats(std::string id, Timestamp timestamp); - RTCPeerConnectionStats(const RTCPeerConnectionStats& other); ~RTCPeerConnectionStats() override; RTCStatsMember data_channels_opened; @@ -188,8 +176,6 @@ class RTC_EXPORT RTCPeerConnectionStats final : public RTCStats { class RTC_EXPORT RTCRtpStreamStats : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - - RTCRtpStreamStats(const RTCRtpStreamStats& other); ~RTCRtpStreamStats() override; RTCStatsMember ssrc; @@ -205,8 +191,6 @@ class RTC_EXPORT RTCRtpStreamStats : public RTCStats { class RTC_EXPORT RTCReceivedRtpStreamStats : public RTCRtpStreamStats { public: WEBRTC_RTCSTATS_DECL(); - - RTCReceivedRtpStreamStats(const RTCReceivedRtpStreamStats& other); ~RTCReceivedRtpStreamStats() override; RTCStatsMember jitter; @@ -220,8 +204,6 @@ class RTC_EXPORT RTCReceivedRtpStreamStats : public RTCRtpStreamStats { class RTC_EXPORT RTCSentRtpStreamStats : public RTCRtpStreamStats { public: WEBRTC_RTCSTATS_DECL(); - - RTCSentRtpStreamStats(const RTCSentRtpStreamStats& other); ~RTCSentRtpStreamStats() override; RTCStatsMember packets_sent; @@ -236,9 +218,7 @@ class RTC_EXPORT RTCInboundRtpStreamStats final : public RTCReceivedRtpStreamStats { public: WEBRTC_RTCSTATS_DECL(); - RTCInboundRtpStreamStats(std::string id, Timestamp timestamp); - RTCInboundRtpStreamStats(const RTCInboundRtpStreamStats& other); ~RTCInboundRtpStreamStats() override; RTCStatsMember playout_id; @@ -341,9 +321,7 @@ class RTC_EXPORT RTCOutboundRtpStreamStats final : public RTCSentRtpStreamStats { public: WEBRTC_RTCSTATS_DECL(); - RTCOutboundRtpStreamStats(std::string id, Timestamp timestamp); - RTCOutboundRtpStreamStats(const RTCOutboundRtpStreamStats& other); ~RTCOutboundRtpStreamStats() override; RTCStatsMember media_source_id; @@ -393,9 +371,7 @@ class RTC_EXPORT RTCRemoteInboundRtpStreamStats final : public RTCReceivedRtpStreamStats { public: WEBRTC_RTCSTATS_DECL(); - RTCRemoteInboundRtpStreamStats(std::string id, Timestamp timestamp); - RTCRemoteInboundRtpStreamStats(const RTCRemoteInboundRtpStreamStats& other); ~RTCRemoteInboundRtpStreamStats() override; RTCStatsMember local_id; @@ -410,9 +386,7 @@ class RTC_EXPORT RTCRemoteOutboundRtpStreamStats final : public RTCSentRtpStreamStats { public: WEBRTC_RTCSTATS_DECL(); - RTCRemoteOutboundRtpStreamStats(std::string id, Timestamp timestamp); - RTCRemoteOutboundRtpStreamStats(const RTCRemoteOutboundRtpStreamStats& other); ~RTCRemoteOutboundRtpStreamStats() override; RTCStatsMember local_id; @@ -427,8 +401,6 @@ class RTC_EXPORT RTCRemoteOutboundRtpStreamStats final class RTC_EXPORT RTCMediaSourceStats : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - - RTCMediaSourceStats(const RTCMediaSourceStats& other); ~RTCMediaSourceStats() override; RTCStatsMember track_identifier; @@ -442,9 +414,7 @@ class RTC_EXPORT RTCMediaSourceStats : public RTCStats { class RTC_EXPORT RTCAudioSourceStats final : public RTCMediaSourceStats { public: WEBRTC_RTCSTATS_DECL(); - RTCAudioSourceStats(std::string id, Timestamp timestamp); - RTCAudioSourceStats(const RTCAudioSourceStats& other); ~RTCAudioSourceStats() override; RTCStatsMember audio_level; @@ -458,9 +428,7 @@ class RTC_EXPORT RTCAudioSourceStats final : public RTCMediaSourceStats { class RTC_EXPORT RTCVideoSourceStats final : public RTCMediaSourceStats { public: WEBRTC_RTCSTATS_DECL(); - RTCVideoSourceStats(std::string id, Timestamp timestamp); - RTCVideoSourceStats(const RTCVideoSourceStats& other); ~RTCVideoSourceStats() override; RTCStatsMember width; @@ -473,9 +441,7 @@ class RTC_EXPORT RTCVideoSourceStats final : public RTCMediaSourceStats { class RTC_EXPORT RTCTransportStats final : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - RTCTransportStats(std::string id, Timestamp timestamp); - RTCTransportStats(const RTCTransportStats& other); ~RTCTransportStats() override; RTCStatsMember bytes_sent; @@ -501,9 +467,7 @@ class RTC_EXPORT RTCTransportStats final : public RTCStats { class RTC_EXPORT RTCAudioPlayoutStats final : public RTCStats { public: WEBRTC_RTCSTATS_DECL(); - RTCAudioPlayoutStats(const std::string& id, Timestamp timestamp); - RTCAudioPlayoutStats(const RTCAudioPlayoutStats& other); ~RTCAudioPlayoutStats() override; RTCStatsMember kind; diff --git a/third_party/libwebrtc/api/task_queue/BUILD.gn b/third_party/libwebrtc/api/task_queue/BUILD.gn index 9b2f747e78..c24c22a1f6 100644 --- a/third_party/libwebrtc/api/task_queue/BUILD.gn +++ b/third_party/libwebrtc/api/task_queue/BUILD.gn @@ -88,6 +88,10 @@ rtc_library("task_queue_test") { } rtc_library("default_task_queue_factory") { +# Mozilla - disable this entire target to avoid inclusion of code we want +# to avoid. Better here than trying to wack-a-mole for places that list +# it as a dependency. +if (!build_with_mozilla) { visibility = [ "*" ] if (!is_ios && !is_android) { # Internally webrtc shouldn't rely on any specific TaskQueue implementation @@ -119,13 +123,14 @@ rtc_library("default_task_queue_factory") { } else if (is_mac || is_ios) { sources += [ "default_task_queue_factory_gcd.cc" ] deps += [ "../../rtc_base:rtc_task_queue_gcd" ] - } else if (is_win && current_os != "winuwp") { + } else if (is_win && current_os != "winuwp" && !build_with_chromium) { sources += [ "default_task_queue_factory_win.cc" ] deps += [ "../../rtc_base:rtc_task_queue_win" ] } else { sources += [ "default_task_queue_factory_stdlib.cc" ] deps += [ "../../rtc_base:rtc_task_queue_stdlib" ] } +} # of if (!build_with_mozilla) { } rtc_library("pending_task_safety_flag") { diff --git a/third_party/libwebrtc/api/task_queue/default_task_queue_factory_gn/moz.build b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_gn/moz.build new file mode 100644 index 0000000000..0911b84473 --- /dev/null +++ b/third_party/libwebrtc/api/task_queue/default_task_queue_factory_gn/moz.build @@ -0,0 +1,198 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + + ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ### + ### DO NOT edit it by hand. ### + +COMPILE_FLAGS["OS_INCLUDES"] = [] +AllowCompilerWarnings() + +DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" +DEFINES["WEBRTC_LIBRARY_IMPL"] = True +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" + +FINAL_LIBRARY = "webrtc" + + +LOCAL_INCLUDES += [ + "!/ipc/ipdl/_ipdlheaders", + "!/third_party/libwebrtc/gen", + "/ipc/chromium/src", + "/third_party/libwebrtc/", + "/third_party/libwebrtc/third_party/abseil-cpp/", + "/tools/profiler/public" +] + +if not CONFIG["MOZ_DEBUG"]: + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0" + DEFINES["NDEBUG"] = True + DEFINES["NVALGRIND"] = True + +if CONFIG["MOZ_DEBUG"] == "1": + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1" + +if CONFIG["OS_TARGET"] == "Android": + + DEFINES["ANDROID"] = True + DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1" + DEFINES["HAVE_SYS_UIO_H"] = True + DEFINES["WEBRTC_ANDROID"] = True + DEFINES["WEBRTC_ANDROID_OPENSLES"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_GNU_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["WEBRTC_MAC"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True + DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0" + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_AURA"] = "1" + DEFINES["USE_GLIB"] = "1" + DEFINES["USE_NSS_CERTS"] = "1" + DEFINES["USE_OZONE"] = "1" + DEFINES["USE_UDEV"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + DEFINES["_LARGEFILE64_SOURCE"] = True + DEFINES["_LARGEFILE_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["USE_GLIB"] = "1" + DEFINES["USE_OZONE"] = "1" + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + DEFINES["_LARGEFILE64_SOURCE"] = True + DEFINES["_LARGEFILE_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "WINNT": + + DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True + DEFINES["NOMINMAX"] = True + DEFINES["NTDDI_VERSION"] = "0x0A000000" + DEFINES["PSAPI_VERSION"] = "2" + DEFINES["RTC_ENABLE_WIN_WGC"] = True + DEFINES["UNICODE"] = True + DEFINES["USE_AURA"] = "1" + DEFINES["WEBRTC_WIN"] = True + DEFINES["WIN32"] = True + DEFINES["WIN32_LEAN_AND_MEAN"] = True + DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP" + DEFINES["WINVER"] = "0x0A00" + DEFINES["_ATL_NO_OPENGL"] = True + DEFINES["_CRT_RAND_S"] = True + DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True + DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True + DEFINES["_HAS_EXCEPTIONS"] = "0" + DEFINES["_HAS_NODISCARD"] = True + DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True + DEFINES["_SECURE_ATL"] = True + DEFINES["_UNICODE"] = True + DEFINES["_WIN32_WINNT"] = "0x0A00" + DEFINES["_WINDOWS"] = True + DEFINES["__STD_C"] = True + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT": + + DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" + +if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_X11"] = "1" + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("default_task_queue_factory_gn") diff --git a/third_party/libwebrtc/api/test/create_network_emulation_manager.cc b/third_party/libwebrtc/api/test/create_network_emulation_manager.cc index f5d5a1bc88..14a7a6a171 100644 --- a/third_party/libwebrtc/api/test/create_network_emulation_manager.cc +++ b/third_party/libwebrtc/api/test/create_network_emulation_manager.cc @@ -13,15 +13,17 @@ #include +#include "api/field_trials_view.h" #include "test/network/network_emulation_manager.h" namespace webrtc { std::unique_ptr CreateNetworkEmulationManager( TimeMode time_mode, - EmulatedNetworkStatsGatheringMode stats_gathering_mode) { + EmulatedNetworkStatsGatheringMode stats_gathering_mode, + const FieldTrialsView* field_trials) { return std::make_unique( - time_mode, stats_gathering_mode); + time_mode, stats_gathering_mode, field_trials); } } // namespace webrtc diff --git a/third_party/libwebrtc/api/test/create_network_emulation_manager.h b/third_party/libwebrtc/api/test/create_network_emulation_manager.h index 941b2b1c52..2f2dfeda28 100644 --- a/third_party/libwebrtc/api/test/create_network_emulation_manager.h +++ b/third_party/libwebrtc/api/test/create_network_emulation_manager.h @@ -13,6 +13,7 @@ #include +#include "api/field_trials_view.h" #include "api/test/network_emulation_manager.h" namespace webrtc { @@ -21,7 +22,8 @@ namespace webrtc { std::unique_ptr CreateNetworkEmulationManager( TimeMode time_mode = TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode stats_gathering_mode = - EmulatedNetworkStatsGatheringMode::kDefault); + EmulatedNetworkStatsGatheringMode::kDefault, + const FieldTrialsView* field_trials = nullptr); } // namespace webrtc diff --git a/third_party/libwebrtc/api/test/create_time_controller.cc b/third_party/libwebrtc/api/test/create_time_controller.cc index 7523e05208..cbf1f09aa1 100644 --- a/third_party/libwebrtc/api/test/create_time_controller.cc +++ b/third_party/libwebrtc/api/test/create_time_controller.cc @@ -16,10 +16,10 @@ #include "absl/base/nullability.h" #include "api/enable_media_with_defaults.h" #include "api/environment/environment.h" +#include "api/environment/environment_factory.h" #include "api/peer_connection_interface.h" #include "call/call.h" -#include "call/rtp_transport_config.h" -#include "call/rtp_transport_controller_send_factory_interface.h" +#include "call/call_config.h" #include "pc/media_factory.h" #include "rtc_base/checks.h" #include "system_wrappers/include/clock.h" @@ -49,9 +49,12 @@ void EnableMediaWithDefaultsAndTimeController( : clock_(clock), media_factory_(std::move(media_factory)) {} std::unique_ptr CreateCall(const CallConfig& config) override { - return Call::Create(config, clock_, - config.rtp_transport_controller_send_factory->Create( - config.ExtractTransportConfig(), clock_)); + EnvironmentFactory env_factory(config.env); + env_factory.Set(clock_); + + CallConfig config_with_custom_clock = config; + config_with_custom_clock.env = env_factory.Create(); + return media_factory_->CreateCall(config_with_custom_clock); } std::unique_ptr CreateMediaEngine( diff --git a/third_party/libwebrtc/api/test/pclf/BUILD.gn b/third_party/libwebrtc/api/test/pclf/BUILD.gn index 372ff51f49..4f62984e83 100644 --- a/third_party/libwebrtc/api/test/pclf/BUILD.gn +++ b/third_party/libwebrtc/api/test/pclf/BUILD.gn @@ -20,7 +20,6 @@ rtc_source_set("media_configuration") { "../..:array_view", "../..:audio_options_api", "../..:audio_quality_analyzer_api", - "../..:callfactory_api", "../..:fec_controller_api", "../..:frame_generator_api", "../..:function_view", diff --git a/third_party/libwebrtc/api/test/pclf/media_configuration.h b/third_party/libwebrtc/api/test/pclf/media_configuration.h index 5c3440c293..ad29e17e7d 100644 --- a/third_party/libwebrtc/api/test/pclf/media_configuration.h +++ b/third_party/libwebrtc/api/test/pclf/media_configuration.h @@ -26,7 +26,6 @@ #include "api/array_view.h" #include "api/audio/audio_mixer.h" #include "api/audio_options.h" -#include "api/call/call_factory_interface.h" #include "api/fec_controller.h" #include "api/function_view.h" #include "api/media_stream_interface.h" diff --git a/third_party/libwebrtc/api/test/pclf/media_quality_test_params.h b/third_party/libwebrtc/api/test/pclf/media_quality_test_params.h index aad04c3eb6..8a3a13a33b 100644 --- a/third_party/libwebrtc/api/test/pclf/media_quality_test_params.h +++ b/third_party/libwebrtc/api/test/pclf/media_quality_test_params.h @@ -136,6 +136,7 @@ struct Params { // provided into VideoEncoder::SetRates(...). double video_encoder_bitrate_multiplier = 1.0; + PeerConnectionFactoryInterface::Options peer_connection_factory_options; PeerConnectionInterface::RTCConfiguration rtc_configuration; PeerConnectionInterface::RTCOfferAnswerOptions rtc_offer_answer_options; BitrateSettings bitrate_settings; diff --git a/third_party/libwebrtc/api/test/pclf/peer_configurer.cc b/third_party/libwebrtc/api/test/pclf/peer_configurer.cc index 5e385452b1..ac0d02818f 100644 --- a/third_party/libwebrtc/api/test/pclf/peer_configurer.cc +++ b/third_party/libwebrtc/api/test/pclf/peer_configurer.cc @@ -205,6 +205,11 @@ PeerConfigurer* PeerConfigurer::SetAecDumpPath(absl::string_view path) { params_->aec_dump_path = std::string(path); return this; } +PeerConfigurer* PeerConfigurer::SetPCFOptions( + PeerConnectionFactoryInterface::Options options) { + params_->peer_connection_factory_options = std::move(options); + return this; +} PeerConfigurer* PeerConfigurer::SetRTCConfiguration( PeerConnectionInterface::RTCConfiguration configuration) { params_->rtc_configuration = std::move(configuration); diff --git a/third_party/libwebrtc/api/test/pclf/peer_configurer.h b/third_party/libwebrtc/api/test/pclf/peer_configurer.h index c0faf8573a..1c6fb4c0e6 100644 --- a/third_party/libwebrtc/api/test/pclf/peer_configurer.h +++ b/third_party/libwebrtc/api/test/pclf/peer_configurer.h @@ -158,6 +158,8 @@ class PeerConfigurer { // If is set, an AEC dump will be saved in that location and it will be // available for further analysis. PeerConfigurer* SetAecDumpPath(absl::string_view path); + PeerConfigurer* SetPCFOptions( + PeerConnectionFactoryInterface::Options options); PeerConfigurer* SetRTCConfiguration( PeerConnectionInterface::RTCConfiguration configuration); PeerConfigurer* SetRTCOfferAnswerOptions( diff --git a/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture.h b/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture.h index 034e13ff3b..7e19eb1629 100644 --- a/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture.h +++ b/third_party/libwebrtc/api/test/peerconnection_quality_test_fixture.h @@ -26,7 +26,6 @@ #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/audio_mixer.h" -#include "api/call/call_factory_interface.h" #include "api/fec_controller.h" #include "api/function_view.h" #include "api/media_stream_interface.h" diff --git a/third_party/libwebrtc/api/test/video_quality_test_fixture.h b/third_party/libwebrtc/api/test/video_quality_test_fixture.h index b45faef286..cbe547b60d 100644 --- a/third_party/libwebrtc/api/test/video_quality_test_fixture.h +++ b/third_party/libwebrtc/api/test/video_quality_test_fixture.h @@ -61,7 +61,7 @@ class VideoQualityTestFixtureInterface { bool automatic_scaling = false; std::string clip_path; // "Generator" to generate frames instead. size_t capture_device_index = 0; - SdpVideoFormat::Parameters sdp_params; + CodecParameterMap sdp_params; double encoder_overshoot_factor = 0.0; } video[2]; struct Audio { diff --git a/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.h b/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.h index 0db600918e..f546a0aa3f 100644 --- a/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.h +++ b/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.h @@ -78,6 +78,27 @@ struct FrameDependencyStructure { std::vector templates; }; +class DependencyDescriptorMandatory { + public: + void set_frame_number(int frame_number) { frame_number_ = frame_number; } + int frame_number() const { return frame_number_; } + + void set_template_id(int template_id) { template_id_ = template_id; } + int template_id() const { return template_id_; } + + void set_first_packet_in_frame(bool first) { first_packet_in_frame_ = first; } + bool first_packet_in_frame() const { return first_packet_in_frame_; } + + void set_last_packet_in_frame(bool last) { last_packet_in_frame_ = last; } + bool last_packet_in_frame() const { return last_packet_in_frame_; } + + private: + int frame_number_; + int template_id_; + bool first_packet_in_frame_; + bool last_packet_in_frame_; +}; + struct DependencyDescriptor { static constexpr int kMaxSpatialIds = 4; static constexpr int kMaxTemporalIds = 8; diff --git a/third_party/libwebrtc/api/transport/stun.cc b/third_party/libwebrtc/api/transport/stun.cc index 7ef6852260..ca90515952 100644 --- a/third_party/libwebrtc/api/transport/stun.cc +++ b/third_party/libwebrtc/api/transport/stun.cc @@ -587,7 +587,7 @@ bool StunMessage::AddFingerprint() { bool StunMessage::Read(ByteBufferReader* buf) { // Keep a copy of the buffer data around for later verification. - buffer_.assign(buf->Data(), buf->Length()); + buffer_.assign(reinterpret_cast(buf->Data()), buf->Length()); if (!buf->ReadUInt16(&type_)) { return false; @@ -603,8 +603,8 @@ bool StunMessage::Read(ByteBufferReader* buf) { return false; } - std::string magic_cookie; - if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) { + absl::string_view magic_cookie; + if (!buf->ReadStringView(&magic_cookie, kStunMagicCookieLength)) { return false; } @@ -814,7 +814,7 @@ void StunAttribute::ConsumePadding(ByteBufferReader* buf) const { void StunAttribute::WritePadding(ByteBufferWriter* buf) const { int remainder = length_ % 4; if (remainder > 0) { - char zeroes[4] = {0}; + uint8_t zeroes[4] = {0}; buf->WriteBytes(zeroes, 4 - remainder); } } @@ -949,12 +949,12 @@ bool StunAddressAttribute::Write(ByteBufferWriter* buf) const { switch (address_.family()) { case AF_INET: { in_addr v4addr = address_.ipaddr().ipv4_address(); - buf->WriteBytes(reinterpret_cast(&v4addr), sizeof(v4addr)); + buf->WriteBytes(reinterpret_cast(&v4addr), sizeof(v4addr)); break; } case AF_INET6: { in6_addr v6addr = address_.ipaddr().ipv6_address(); - buf->WriteBytes(reinterpret_cast(&v6addr), sizeof(v6addr)); + buf->WriteBytes(reinterpret_cast(&v6addr), sizeof(v6addr)); break; } } @@ -1039,12 +1039,14 @@ bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const { switch (xored_ip.family()) { case AF_INET: { in_addr v4addr = xored_ip.ipv4_address(); - buf->WriteBytes(reinterpret_cast(&v4addr), sizeof(v4addr)); + buf->WriteBytes(reinterpret_cast(&v4addr), + sizeof(v4addr)); break; } case AF_INET6: { in6_addr v6addr = xored_ip.ipv6_address(); - buf->WriteBytes(reinterpret_cast(&v6addr), sizeof(v6addr)); + buf->WriteBytes(reinterpret_cast(&v6addr), + sizeof(v6addr)); break; } } @@ -1170,7 +1172,7 @@ bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const { if (!LengthValid(type(), length())) { return false; } - buf->WriteBytes(reinterpret_cast(bytes_), length()); + buf->WriteBytes(bytes_, length()); WritePadding(buf); return true; } diff --git a/third_party/libwebrtc/api/video_codecs/BUILD.gn b/third_party/libwebrtc/api/video_codecs/BUILD.gn index 94c9cc8b87..3865f4fee7 100644 --- a/third_party/libwebrtc/api/video_codecs/BUILD.gn +++ b/third_party/libwebrtc/api/video_codecs/BUILD.gn @@ -83,6 +83,7 @@ rtc_library("video_codecs_api") { "..:fec_controller_api", "..:scoped_refptr", "../../api:array_view", + "../../api:rtp_parameters", "../../modules/video_coding:codec_globals_headers", "../../rtc_base:checks", "../../rtc_base:logging", diff --git a/third_party/libwebrtc/api/video_codecs/av1_profile.cc b/third_party/libwebrtc/api/video_codecs/av1_profile.cc index eefe166d80..59d7b13e51 100644 --- a/third_party/libwebrtc/api/video_codecs/av1_profile.cc +++ b/third_party/libwebrtc/api/video_codecs/av1_profile.cc @@ -50,7 +50,7 @@ absl::optional StringToAV1Profile(absl::string_view str) { } absl::optional ParseSdpForAV1Profile( - const SdpVideoFormat::Parameters& params) { + const CodecParameterMap& params) { const auto profile_it = params.find(kAV1FmtpProfile); if (profile_it == params.end()) return AV1Profile::kProfile0; @@ -58,8 +58,8 @@ absl::optional ParseSdpForAV1Profile( return StringToAV1Profile(profile_str); } -bool AV1IsSameProfile(const SdpVideoFormat::Parameters& params1, - const SdpVideoFormat::Parameters& params2) { +bool AV1IsSameProfile(const CodecParameterMap& params1, + const CodecParameterMap& params2) { const absl::optional profile = ParseSdpForAV1Profile(params1); const absl::optional other_profile = ParseSdpForAV1Profile(params2); diff --git a/third_party/libwebrtc/api/video_codecs/av1_profile.h b/third_party/libwebrtc/api/video_codecs/av1_profile.h index 2254d5ecd3..bc9767631c 100644 --- a/third_party/libwebrtc/api/video_codecs/av1_profile.h +++ b/third_party/libwebrtc/api/video_codecs/av1_profile.h @@ -45,12 +45,12 @@ absl::optional StringToAV1Profile(absl::string_view profile); // specified and an empty value if the profile key is present but contains an // invalid value. RTC_EXPORT absl::optional ParseSdpForAV1Profile( - const SdpVideoFormat::Parameters& params); + const CodecParameterMap& params); // Returns true if the parameters have the same AV1 profile or neither contains // an AV1 profile, otherwise false. -bool AV1IsSameProfile(const SdpVideoFormat::Parameters& params1, - const SdpVideoFormat::Parameters& params2); +bool AV1IsSameProfile(const CodecParameterMap& params1, + const CodecParameterMap& params2); } // namespace webrtc diff --git a/third_party/libwebrtc/api/video_codecs/h264_profile_level_id.cc b/third_party/libwebrtc/api/video_codecs/h264_profile_level_id.cc index 5844ca0e32..9bd9c9e4ab 100644 --- a/third_party/libwebrtc/api/video_codecs/h264_profile_level_id.cc +++ b/third_party/libwebrtc/api/video_codecs/h264_profile_level_id.cc @@ -178,7 +178,7 @@ absl::optional H264SupportedLevel(int max_frame_pixel_count, } absl::optional ParseSdpForH264ProfileLevelId( - const SdpVideoFormat::Parameters& params) { + const CodecParameterMap& params) { // TODO(magjed): The default should really be kProfileBaseline and kLevel1 // according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In // order to not break backwards compatibility with older versions of WebRTC @@ -243,8 +243,8 @@ absl::optional H264ProfileLevelIdToString( return {str}; } -bool H264IsSameProfile(const SdpVideoFormat::Parameters& params1, - const SdpVideoFormat::Parameters& params2) { +bool H264IsSameProfile(const CodecParameterMap& params1, + const CodecParameterMap& params2) { const absl::optional profile_level_id = ParseSdpForH264ProfileLevelId(params1); const absl::optional other_profile_level_id = diff --git a/third_party/libwebrtc/api/video_codecs/h264_profile_level_id.h b/third_party/libwebrtc/api/video_codecs/h264_profile_level_id.h index 4b46ad329d..37709fae64 100644 --- a/third_party/libwebrtc/api/video_codecs/h264_profile_level_id.h +++ b/third_party/libwebrtc/api/video_codecs/h264_profile_level_id.h @@ -67,7 +67,7 @@ absl::optional ParseH264ProfileLevelId(const char* str); // returned if the profile-level-id key is missing. Nothing will be returned if // the key is present but the string is invalid. RTC_EXPORT absl::optional ParseSdpForH264ProfileLevelId( - const SdpVideoFormat::Parameters& params); + const CodecParameterMap& params); // Given that a decoder supports up to a given frame size (in pixels) at up to a // given number of frames per second, return the highest H.264 level where it @@ -84,8 +84,8 @@ RTC_EXPORT absl::optional H264ProfileLevelIdToString( // Returns true if the parameters have the same H264 profile (Baseline, High, // etc). -RTC_EXPORT bool H264IsSameProfile(const SdpVideoFormat::Parameters& params1, - const SdpVideoFormat::Parameters& params2); +RTC_EXPORT bool H264IsSameProfile(const CodecParameterMap& params1, + const CodecParameterMap& params2); } // namespace webrtc diff --git a/third_party/libwebrtc/api/video_codecs/h265_profile_tier_level.cc b/third_party/libwebrtc/api/video_codecs/h265_profile_tier_level.cc index f5b376e287..f4dcebb25a 100644 --- a/third_party/libwebrtc/api/video_codecs/h265_profile_tier_level.cc +++ b/third_party/libwebrtc/api/video_codecs/h265_profile_tier_level.cc @@ -1,248 +1,248 @@ -/* - * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "api/video_codecs/h265_profile_tier_level.h" - -#include - -#include "rtc_base/string_to_number.h" - -namespace webrtc { - -namespace { - -const char kH265FmtpProfile[] = "profile-id"; -const char kH265FmtpTier[] = "tier-flag"; -const char kH265FmtpLevel[] = "level-id"; - -} // anonymous namespace - -// Annex A of https://www.itu.int/rec/T-REC-H.265 (08/21), section A.3. -absl::optional StringToH265Profile(const std::string& profile) { - absl::optional i = rtc::StringToNumber(profile); - if (!i.has_value()) { - return absl::nullopt; - } - - switch (i.value()) { - case 1: - return H265Profile::kProfileMain; - case 2: - return H265Profile::kProfileMain10; - case 3: - return H265Profile::kProfileMainStill; - case 4: - return H265Profile::kProfileRangeExtensions; - case 5: - return H265Profile::kProfileHighThroughput; - case 6: - return H265Profile::kProfileMultiviewMain; - case 7: - return H265Profile::kProfileScalableMain; - case 8: - return H265Profile::kProfile3dMain; - case 9: - return H265Profile::kProfileScreenContentCoding; - case 10: - return H265Profile::kProfileScalableRangeExtensions; - case 11: - return H265Profile::kProfileHighThroughputScreenContentCoding; - default: - return absl::nullopt; - } -} - -// Annex A of https://www.itu.int/rec/T-REC-H.265 (08/21), section A.4, -// tiers and levels. -absl::optional StringToH265Tier(const std::string& tier) { - absl::optional i = rtc::StringToNumber(tier); - if (!i.has_value()) { - return absl::nullopt; - } - - switch (i.value()) { - case 0: - return H265Tier::kTier0; - case 1: - return H265Tier::kTier1; - default: - return absl::nullopt; - } -} - -absl::optional StringToH265Level(const std::string& level) { - const absl::optional i = rtc::StringToNumber(level); - if (!i.has_value()) - return absl::nullopt; - - switch (i.value()) { - case 30: - return H265Level::kLevel1; - case 60: - return H265Level::kLevel2; - case 63: - return H265Level::kLevel2_1; - case 90: - return H265Level::kLevel3; - case 93: - return H265Level::kLevel3_1; - case 120: - return H265Level::kLevel4; - case 123: - return H265Level::kLevel4_1; - case 150: - return H265Level::kLevel5; - case 153: - return H265Level::kLevel5_1; - case 156: - return H265Level::kLevel5_2; - case 180: - return H265Level::kLevel6; - case 183: - return H265Level::kLevel6_1; - case 186: - return H265Level::kLevel6_2; - default: - return absl::nullopt; - } -} - -std::string H265ProfileToString(H265Profile profile) { - switch (profile) { - case H265Profile::kProfileMain: - return "1"; - case H265Profile::kProfileMain10: - return "2"; - case H265Profile::kProfileMainStill: - return "3"; - case H265Profile::kProfileRangeExtensions: - return "4"; - case H265Profile::kProfileHighThroughput: - return "5"; - case H265Profile::kProfileMultiviewMain: - return "6"; - case H265Profile::kProfileScalableMain: - return "7"; - case H265Profile::kProfile3dMain: - return "8"; - case H265Profile::kProfileScreenContentCoding: - return "9"; - case H265Profile::kProfileScalableRangeExtensions: - return "10"; - case H265Profile::kProfileHighThroughputScreenContentCoding: - return "11"; - } -} - -std::string H265TierToString(H265Tier tier) { - switch (tier) { - case H265Tier::kTier0: - return "0"; - case H265Tier::kTier1: - return "1"; - } -} - -std::string H265LevelToString(H265Level level) { - switch (level) { - case H265Level::kLevel1: - return "30"; - case H265Level::kLevel2: - return "60"; - case H265Level::kLevel2_1: - return "63"; - case H265Level::kLevel3: - return "90"; - case H265Level::kLevel3_1: - return "93"; - case H265Level::kLevel4: - return "120"; - case H265Level::kLevel4_1: - return "123"; - case H265Level::kLevel5: - return "150"; - case H265Level::kLevel5_1: - return "153"; - case H265Level::kLevel5_2: - return "156"; - case H265Level::kLevel6: - return "180"; - case H265Level::kLevel6_1: - return "183"; - case H265Level::kLevel6_2: - return "186"; - } -} - -absl::optional ParseSdpForH265ProfileTierLevel( - const SdpVideoFormat::Parameters& params) { - static const H265ProfileTierLevel kDefaultProfileTierLevel( - H265Profile::kProfileMain, H265Tier::kTier0, H265Level::kLevel3_1); - bool profile_tier_level_specified = false; - - absl::optional profile; - const auto profile_it = params.find(kH265FmtpProfile); - if (profile_it != params.end()) { - profile_tier_level_specified = true; - const std::string& profile_str = profile_it->second; - profile = StringToH265Profile(profile_str); - if (!profile) { - return absl::nullopt; - } - } else { - profile = H265Profile::kProfileMain; - } - absl::optional tier; - const auto tier_it = params.find(kH265FmtpTier); - if (tier_it != params.end()) { - profile_tier_level_specified = true; - const std::string& tier_str = tier_it->second; - tier = StringToH265Tier(tier_str); - if (!tier) { - return absl::nullopt; - } - } else { - tier = H265Tier::kTier0; - } - absl::optional level; - const auto level_it = params.find(kH265FmtpLevel); - if (level_it != params.end()) { - profile_tier_level_specified = true; - const std::string& level_str = level_it->second; - level = StringToH265Level(level_str); - if (!level) { - return absl::nullopt; - } - } else { - level = H265Level::kLevel3_1; - } - - // Spec Table A.9, level 1 to level 3.1 does not allow high tiers. - if (level <= H265Level::kLevel3_1 && tier == H265Tier::kTier1) { - return absl::nullopt; - } - - return !profile_tier_level_specified - ? kDefaultProfileTierLevel - : H265ProfileTierLevel(profile.value(), tier.value(), - level.value()); -} - -bool H265IsSameProfileTierLevel(const SdpVideoFormat::Parameters& params1, - const SdpVideoFormat::Parameters& params2) { - const absl::optional ptl1 = - ParseSdpForH265ProfileTierLevel(params1); - const absl::optional ptl2 = - ParseSdpForH265ProfileTierLevel(params2); - return ptl1 && ptl2 && ptl1->profile == ptl2->profile && - ptl1->tier == ptl2->tier && ptl1->level == ptl2->level; -} - -} // namespace webrtc +/* + * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/video_codecs/h265_profile_tier_level.h" + +#include + +#include "rtc_base/string_to_number.h" + +namespace webrtc { + +namespace { + +const char kH265FmtpProfile[] = "profile-id"; +const char kH265FmtpTier[] = "tier-flag"; +const char kH265FmtpLevel[] = "level-id"; + +} // anonymous namespace + +// Annex A of https://www.itu.int/rec/T-REC-H.265 (08/21), section A.3. +absl::optional StringToH265Profile(const std::string& profile) { + absl::optional i = rtc::StringToNumber(profile); + if (!i.has_value()) { + return absl::nullopt; + } + + switch (i.value()) { + case 1: + return H265Profile::kProfileMain; + case 2: + return H265Profile::kProfileMain10; + case 3: + return H265Profile::kProfileMainStill; + case 4: + return H265Profile::kProfileRangeExtensions; + case 5: + return H265Profile::kProfileHighThroughput; + case 6: + return H265Profile::kProfileMultiviewMain; + case 7: + return H265Profile::kProfileScalableMain; + case 8: + return H265Profile::kProfile3dMain; + case 9: + return H265Profile::kProfileScreenContentCoding; + case 10: + return H265Profile::kProfileScalableRangeExtensions; + case 11: + return H265Profile::kProfileHighThroughputScreenContentCoding; + default: + return absl::nullopt; + } +} + +// Annex A of https://www.itu.int/rec/T-REC-H.265 (08/21), section A.4, +// tiers and levels. +absl::optional StringToH265Tier(const std::string& tier) { + absl::optional i = rtc::StringToNumber(tier); + if (!i.has_value()) { + return absl::nullopt; + } + + switch (i.value()) { + case 0: + return H265Tier::kTier0; + case 1: + return H265Tier::kTier1; + default: + return absl::nullopt; + } +} + +absl::optional StringToH265Level(const std::string& level) { + const absl::optional i = rtc::StringToNumber(level); + if (!i.has_value()) + return absl::nullopt; + + switch (i.value()) { + case 30: + return H265Level::kLevel1; + case 60: + return H265Level::kLevel2; + case 63: + return H265Level::kLevel2_1; + case 90: + return H265Level::kLevel3; + case 93: + return H265Level::kLevel3_1; + case 120: + return H265Level::kLevel4; + case 123: + return H265Level::kLevel4_1; + case 150: + return H265Level::kLevel5; + case 153: + return H265Level::kLevel5_1; + case 156: + return H265Level::kLevel5_2; + case 180: + return H265Level::kLevel6; + case 183: + return H265Level::kLevel6_1; + case 186: + return H265Level::kLevel6_2; + default: + return absl::nullopt; + } +} + +std::string H265ProfileToString(H265Profile profile) { + switch (profile) { + case H265Profile::kProfileMain: + return "1"; + case H265Profile::kProfileMain10: + return "2"; + case H265Profile::kProfileMainStill: + return "3"; + case H265Profile::kProfileRangeExtensions: + return "4"; + case H265Profile::kProfileHighThroughput: + return "5"; + case H265Profile::kProfileMultiviewMain: + return "6"; + case H265Profile::kProfileScalableMain: + return "7"; + case H265Profile::kProfile3dMain: + return "8"; + case H265Profile::kProfileScreenContentCoding: + return "9"; + case H265Profile::kProfileScalableRangeExtensions: + return "10"; + case H265Profile::kProfileHighThroughputScreenContentCoding: + return "11"; + } +} + +std::string H265TierToString(H265Tier tier) { + switch (tier) { + case H265Tier::kTier0: + return "0"; + case H265Tier::kTier1: + return "1"; + } +} + +std::string H265LevelToString(H265Level level) { + switch (level) { + case H265Level::kLevel1: + return "30"; + case H265Level::kLevel2: + return "60"; + case H265Level::kLevel2_1: + return "63"; + case H265Level::kLevel3: + return "90"; + case H265Level::kLevel3_1: + return "93"; + case H265Level::kLevel4: + return "120"; + case H265Level::kLevel4_1: + return "123"; + case H265Level::kLevel5: + return "150"; + case H265Level::kLevel5_1: + return "153"; + case H265Level::kLevel5_2: + return "156"; + case H265Level::kLevel6: + return "180"; + case H265Level::kLevel6_1: + return "183"; + case H265Level::kLevel6_2: + return "186"; + } +} + +absl::optional ParseSdpForH265ProfileTierLevel( + const CodecParameterMap& params) { + static const H265ProfileTierLevel kDefaultProfileTierLevel( + H265Profile::kProfileMain, H265Tier::kTier0, H265Level::kLevel3_1); + bool profile_tier_level_specified = false; + + absl::optional profile; + const auto profile_it = params.find(kH265FmtpProfile); + if (profile_it != params.end()) { + profile_tier_level_specified = true; + const std::string& profile_str = profile_it->second; + profile = StringToH265Profile(profile_str); + if (!profile) { + return absl::nullopt; + } + } else { + profile = H265Profile::kProfileMain; + } + absl::optional tier; + const auto tier_it = params.find(kH265FmtpTier); + if (tier_it != params.end()) { + profile_tier_level_specified = true; + const std::string& tier_str = tier_it->second; + tier = StringToH265Tier(tier_str); + if (!tier) { + return absl::nullopt; + } + } else { + tier = H265Tier::kTier0; + } + absl::optional level; + const auto level_it = params.find(kH265FmtpLevel); + if (level_it != params.end()) { + profile_tier_level_specified = true; + const std::string& level_str = level_it->second; + level = StringToH265Level(level_str); + if (!level) { + return absl::nullopt; + } + } else { + level = H265Level::kLevel3_1; + } + + // Spec Table A.9, level 1 to level 3.1 does not allow high tiers. + if (level <= H265Level::kLevel3_1 && tier == H265Tier::kTier1) { + return absl::nullopt; + } + + return !profile_tier_level_specified + ? kDefaultProfileTierLevel + : H265ProfileTierLevel(profile.value(), tier.value(), + level.value()); +} + +bool H265IsSameProfileTierLevel(const CodecParameterMap& params1, + const CodecParameterMap& params2) { + const absl::optional ptl1 = + ParseSdpForH265ProfileTierLevel(params1); + const absl::optional ptl2 = + ParseSdpForH265ProfileTierLevel(params2); + return ptl1 && ptl2 && ptl1->profile == ptl2->profile && + ptl1->tier == ptl2->tier && ptl1->level == ptl2->level; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/api/video_codecs/h265_profile_tier_level.h b/third_party/libwebrtc/api/video_codecs/h265_profile_tier_level.h index 3056d2b623..efbdf287ed 100644 --- a/third_party/libwebrtc/api/video_codecs/h265_profile_tier_level.h +++ b/third_party/libwebrtc/api/video_codecs/h265_profile_tier_level.h @@ -1,109 +1,109 @@ -/* - * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef API_VIDEO_CODECS_H265_PROFILE_TIER_LEVEL_H_ -#define API_VIDEO_CODECS_H265_PROFILE_TIER_LEVEL_H_ - -#include - -#include "absl/types/optional.h" -#include "api/video_codecs/sdp_video_format.h" -#include "rtc_base/system/rtc_export.h" - -namespace webrtc { - -// Profiles can be found at: -// https://www.itu.int/rec/T-REC-H.265 -// The enum values match the number specified in the SDP. -enum class H265Profile { - kProfileMain = 1, - kProfileMain10 = 2, - kProfileMainStill = 3, - kProfileRangeExtensions = 4, - kProfileHighThroughput = 5, - kProfileMultiviewMain = 6, - kProfileScalableMain = 7, - kProfile3dMain = 8, - kProfileScreenContentCoding = 9, - kProfileScalableRangeExtensions = 10, - kProfileHighThroughputScreenContentCoding = 11, -}; - -// Tiers can be found at https://www.itu.int/rec/T-REC-H.265 -enum class H265Tier { - kTier0, - kTier1, -}; - -// All values are equal to 30 times the level number. -enum class H265Level { - kLevel1 = 30, - kLevel2 = 60, - kLevel2_1 = 63, - kLevel3 = 90, - kLevel3_1 = 93, - kLevel4 = 120, - kLevel4_1 = 123, - kLevel5 = 150, - kLevel5_1 = 153, - kLevel5_2 = 156, - kLevel6 = 180, - kLevel6_1 = 183, - kLevel6_2 = 186, -}; - -struct H265ProfileTierLevel { - constexpr H265ProfileTierLevel(H265Profile profile, - H265Tier tier, - H265Level level) - : profile(profile), tier(tier), level(level) {} - H265Profile profile; - H265Tier tier; - H265Level level; -}; - -// Helper function to convert H265Profile to std::string. -RTC_EXPORT std::string H265ProfileToString(H265Profile profile); - -// Helper function to convert H265Tier to std::string. -RTC_EXPORT std::string H265TierToString(H265Tier tier); - -// Helper function to convert H265Level to std::string. -RTC_EXPORT std::string H265LevelToString(H265Level level); - -// Helper function to get H265Profile from profile string. -RTC_EXPORT absl::optional StringToH265Profile( - const std::string& profile); - -// Helper function to get H265Tier from tier string. -RTC_EXPORT absl::optional StringToH265Tier(const std::string& tier); - -// Helper function to get H265Level from level string. -RTC_EXPORT absl::optional StringToH265Level( - const std::string& level); - -// Parses an SDP key-value map of format parameters to retrive an H265 -// profile/tier/level. Returns an H265ProfileTierlevel by setting its -// members. profile defaults to `kProfileMain` if no profile-id is specified. -// tier defaults to "kTier0" if no tier-flag is specified. -// level defaults to "kLevel3_1" if no level-id is specified. -// Returns empty value if any of the profile/tier/level key is present but -// contains an invalid value. -RTC_EXPORT absl::optional ParseSdpForH265ProfileTierLevel( - const SdpVideoFormat::Parameters& params); - -// Returns true if the parameters have the same H265 profile or neither contains -// an H265 profile, otherwise false. -bool H265IsSameProfileTierLevel(const SdpVideoFormat::Parameters& params1, - const SdpVideoFormat::Parameters& params2); - -} // namespace webrtc - -#endif // API_VIDEO_CODECS_H265_PROFILE_TIER_LEVEL_H_ +/* + * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_VIDEO_CODECS_H265_PROFILE_TIER_LEVEL_H_ +#define API_VIDEO_CODECS_H265_PROFILE_TIER_LEVEL_H_ + +#include + +#include "absl/types/optional.h" +#include "api/video_codecs/sdp_video_format.h" +#include "rtc_base/system/rtc_export.h" + +namespace webrtc { + +// Profiles can be found at: +// https://www.itu.int/rec/T-REC-H.265 +// The enum values match the number specified in the SDP. +enum class H265Profile { + kProfileMain = 1, + kProfileMain10 = 2, + kProfileMainStill = 3, + kProfileRangeExtensions = 4, + kProfileHighThroughput = 5, + kProfileMultiviewMain = 6, + kProfileScalableMain = 7, + kProfile3dMain = 8, + kProfileScreenContentCoding = 9, + kProfileScalableRangeExtensions = 10, + kProfileHighThroughputScreenContentCoding = 11, +}; + +// Tiers can be found at https://www.itu.int/rec/T-REC-H.265 +enum class H265Tier { + kTier0, + kTier1, +}; + +// All values are equal to 30 times the level number. +enum class H265Level { + kLevel1 = 30, + kLevel2 = 60, + kLevel2_1 = 63, + kLevel3 = 90, + kLevel3_1 = 93, + kLevel4 = 120, + kLevel4_1 = 123, + kLevel5 = 150, + kLevel5_1 = 153, + kLevel5_2 = 156, + kLevel6 = 180, + kLevel6_1 = 183, + kLevel6_2 = 186, +}; + +struct H265ProfileTierLevel { + constexpr H265ProfileTierLevel(H265Profile profile, + H265Tier tier, + H265Level level) + : profile(profile), tier(tier), level(level) {} + H265Profile profile; + H265Tier tier; + H265Level level; +}; + +// Helper function to convert H265Profile to std::string. +RTC_EXPORT std::string H265ProfileToString(H265Profile profile); + +// Helper function to convert H265Tier to std::string. +RTC_EXPORT std::string H265TierToString(H265Tier tier); + +// Helper function to convert H265Level to std::string. +RTC_EXPORT std::string H265LevelToString(H265Level level); + +// Helper function to get H265Profile from profile string. +RTC_EXPORT absl::optional StringToH265Profile( + const std::string& profile); + +// Helper function to get H265Tier from tier string. +RTC_EXPORT absl::optional StringToH265Tier(const std::string& tier); + +// Helper function to get H265Level from level string. +RTC_EXPORT absl::optional StringToH265Level( + const std::string& level); + +// Parses an SDP key-value map of format parameters to retrive an H265 +// profile/tier/level. Returns an H265ProfileTierlevel by setting its +// members. profile defaults to `kProfileMain` if no profile-id is specified. +// tier defaults to "kTier0" if no tier-flag is specified. +// level defaults to "kLevel3_1" if no level-id is specified. +// Returns empty value if any of the profile/tier/level key is present but +// contains an invalid value. +RTC_EXPORT absl::optional ParseSdpForH265ProfileTierLevel( + const CodecParameterMap& params); + +// Returns true if the parameters have the same H265 profile or neither contains +// an H265 profile, otherwise false. +RTC_EXPORT bool H265IsSameProfileTierLevel(const CodecParameterMap& params1, + const CodecParameterMap& params2); + +} // namespace webrtc + +#endif // API_VIDEO_CODECS_H265_PROFILE_TIER_LEVEL_H_ diff --git a/third_party/libwebrtc/api/video_codecs/sdp_video_format.cc b/third_party/libwebrtc/api/video_codecs/sdp_video_format.cc index 51ae18cd78..0f313e84a9 100644 --- a/third_party/libwebrtc/api/video_codecs/sdp_video_format.cc +++ b/third_party/libwebrtc/api/video_codecs/sdp_video_format.cc @@ -28,8 +28,7 @@ namespace webrtc { namespace { -std::string H264GetPacketizationModeOrDefault( - const SdpVideoFormat::Parameters& params) { +std::string H264GetPacketizationModeOrDefault(const CodecParameterMap& params) { constexpr char kH264FmtpPacketizationMode[] = "packetization-mode"; const auto it = params.find(kH264FmtpPacketizationMode); if (it != params.end()) { @@ -40,8 +39,8 @@ std::string H264GetPacketizationModeOrDefault( return "0"; } -bool H264IsSamePacketizationMode(const SdpVideoFormat::Parameters& left, - const SdpVideoFormat::Parameters& right) { +bool H264IsSamePacketizationMode(const CodecParameterMap& left, + const CodecParameterMap& right) { return H264GetPacketizationModeOrDefault(left) == H264GetPacketizationModeOrDefault(right); } @@ -77,12 +76,12 @@ bool IsSameCodecSpecific(const SdpVideoFormat& format1, SdpVideoFormat::SdpVideoFormat(const std::string& name) : name(name) {} SdpVideoFormat::SdpVideoFormat(const std::string& name, - const Parameters& parameters) + const CodecParameterMap& parameters) : name(name), parameters(parameters) {} SdpVideoFormat::SdpVideoFormat( const std::string& name, - const Parameters& parameters, + const CodecParameterMap& parameters, const absl::InlinedVector& scalability_modes) : name(name), diff --git a/third_party/libwebrtc/api/video_codecs/sdp_video_format.h b/third_party/libwebrtc/api/video_codecs/sdp_video_format.h index faaa66c241..af9537b5a3 100644 --- a/third_party/libwebrtc/api/video_codecs/sdp_video_format.h +++ b/third_party/libwebrtc/api/video_codecs/sdp_video_format.h @@ -17,6 +17,7 @@ #include "absl/container/inlined_vector.h" #include "absl/types/optional.h" #include "api/array_view.h" +#include "api/rtp_parameters.h" #include "api/video_codecs/scalability_mode.h" #include "rtc_base/system/rtc_export.h" @@ -25,13 +26,14 @@ namespace webrtc { // SDP specification for a single video codec. // NOTE: This class is still under development and may change without notice. struct RTC_EXPORT SdpVideoFormat { - using Parameters = std::map; + using Parameters [[deprecated(("Use webrtc::CodecParameterMap"))]] = + std::map; explicit SdpVideoFormat(const std::string& name); - SdpVideoFormat(const std::string& name, const Parameters& parameters); + SdpVideoFormat(const std::string& name, const CodecParameterMap& parameters); SdpVideoFormat( const std::string& name, - const Parameters& parameters, + const CodecParameterMap& parameters, const absl::InlinedVector& scalability_modes); SdpVideoFormat(const SdpVideoFormat&); @@ -58,7 +60,7 @@ struct RTC_EXPORT SdpVideoFormat { } std::string name; - Parameters parameters; + CodecParameterMap parameters; absl::InlinedVector scalability_modes; }; diff --git a/third_party/libwebrtc/api/video_codecs/test/h264_profile_level_id_unittest.cc b/third_party/libwebrtc/api/video_codecs/test/h264_profile_level_id_unittest.cc index 47098d2682..404d3e2cb3 100644 --- a/third_party/libwebrtc/api/video_codecs/test/h264_profile_level_id_unittest.cc +++ b/third_party/libwebrtc/api/video_codecs/test/h264_profile_level_id_unittest.cc @@ -145,7 +145,7 @@ TEST(H264ProfileLevelId, TestToStringInvalid) { TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) { const absl::optional profile_level_id = - ParseSdpForH264ProfileLevelId(SdpVideoFormat::Parameters()); + ParseSdpForH264ProfileLevelId(CodecParameterMap()); EXPECT_TRUE(profile_level_id); EXPECT_EQ(H264Profile::kProfileConstrainedBaseline, profile_level_id->profile); @@ -153,7 +153,7 @@ TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) { } TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdConstrainedHigh) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; params["profile-level-id"] = "640c2a"; const absl::optional profile_level_id = ParseSdpForH264ProfileLevelId(params); @@ -163,7 +163,7 @@ TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdConstrainedHigh) { } TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdInvalid) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; params["profile-level-id"] = "foobar"; EXPECT_FALSE(ParseSdpForH264ProfileLevelId(params)); } diff --git a/third_party/libwebrtc/api/video_codecs/test/h265_profile_tier_level_unittest.cc b/third_party/libwebrtc/api/video_codecs/test/h265_profile_tier_level_unittest.cc index a9fdf966a5..85c0f09cd0 100644 --- a/third_party/libwebrtc/api/video_codecs/test/h265_profile_tier_level_unittest.cc +++ b/third_party/libwebrtc/api/video_codecs/test/h265_profile_tier_level_unittest.cc @@ -1,248 +1,248 @@ -/* - * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "api/video_codecs/h265_profile_tier_level.h" - -#include - -#include "absl/types/optional.h" -#include "test/gtest.h" - -namespace webrtc { - -TEST(H265ProfileTierLevel, TestLevelToString) { - EXPECT_EQ(H265LevelToString(H265Level::kLevel1), "30"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel2), "60"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel2_1), "63"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel3), "90"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel3_1), "93"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel4), "120"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel4_1), "123"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel5), "150"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel5_1), "153"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel5_2), "156"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel6), "180"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel6_1), "183"); - EXPECT_EQ(H265LevelToString(H265Level::kLevel6_2), "186"); -} - -TEST(H265ProfileTierLevel, TestProfileToString) { - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMain), "1"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMain10), "2"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMainStill), "3"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileRangeExtensions), "4"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileHighThroughput), "5"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMultiviewMain), "6"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScalableMain), "7"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfile3dMain), "8"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScreenContentCoding), "9"); - EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScalableRangeExtensions), - "10"); - EXPECT_EQ(H265ProfileToString( - H265Profile::kProfileHighThroughputScreenContentCoding), - "11"); -} - -TEST(H265ProfileTierLevel, TestTierToString) { - EXPECT_EQ(H265TierToString(H265Tier::kTier0), "0"); - EXPECT_EQ(H265TierToString(H265Tier::kTier1), "1"); -} - -TEST(H265ProfileTierLevel, TestStringToProfile) { - // Invalid profiles. - EXPECT_FALSE(StringToH265Profile("0")); - EXPECT_FALSE(StringToH265Profile("12")); - - // Malformed profiles - EXPECT_FALSE(StringToH265Profile("")); - EXPECT_FALSE(StringToH265Profile(" 1")); - EXPECT_FALSE(StringToH265Profile("12x")); - EXPECT_FALSE(StringToH265Profile("x12")); - EXPECT_FALSE(StringToH265Profile("gggg")); - - // Valid profiles. - EXPECT_EQ(StringToH265Profile("1"), H265Profile::kProfileMain); - EXPECT_EQ(StringToH265Profile("2"), H265Profile::kProfileMain10); - EXPECT_EQ(StringToH265Profile("4"), H265Profile::kProfileRangeExtensions); -} - -TEST(H265ProfileTierLevel, TestStringToLevel) { - // Invalid levels. - EXPECT_FALSE(StringToH265Level("0")); - EXPECT_FALSE(StringToH265Level("200")); - - // Malformed levels. - EXPECT_FALSE(StringToH265Level("")); - EXPECT_FALSE(StringToH265Level(" 30")); - EXPECT_FALSE(StringToH265Level("30x")); - EXPECT_FALSE(StringToH265Level("x30")); - EXPECT_FALSE(StringToH265Level("ggggg")); - - // Valid levels. - EXPECT_EQ(StringToH265Level("30"), H265Level::kLevel1); - EXPECT_EQ(StringToH265Level("93"), H265Level::kLevel3_1); - EXPECT_EQ(StringToH265Level("183"), H265Level::kLevel6_1); -} - -TEST(H265ProfileTierLevel, TestStringToTier) { - // Invalid tiers. - EXPECT_FALSE(StringToH265Tier("4")); - EXPECT_FALSE(StringToH265Tier("-1")); - - // Malformed tiers. - EXPECT_FALSE(StringToH265Tier("")); - EXPECT_FALSE(StringToH265Tier(" 1")); - EXPECT_FALSE(StringToH265Tier("t1")); - - // Valid tiers. - EXPECT_EQ(StringToH265Tier("0"), H265Tier::kTier0); - EXPECT_EQ(StringToH265Tier("1"), H265Tier::kTier1); -} - -TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelAllEmpty) { - const absl::optional profile_tier_level = - ParseSdpForH265ProfileTierLevel(SdpVideoFormat::Parameters()); - EXPECT_TRUE(profile_tier_level); - EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile); - EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level); - EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier); -} - -TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelPartialEmpty) { - SdpVideoFormat::Parameters params; - params["profile-id"] = "1"; - params["tier-flag"] = "0"; - absl::optional profile_tier_level = - ParseSdpForH265ProfileTierLevel(params); - EXPECT_TRUE(profile_tier_level); - EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile); - EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level); - EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier); - - params.clear(); - params["profile-id"] = "2"; - profile_tier_level = ParseSdpForH265ProfileTierLevel(params); - EXPECT_TRUE(profile_tier_level); - EXPECT_EQ(H265Profile::kProfileMain10, profile_tier_level->profile); - EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level); - EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier); - - params.clear(); - params["level-id"] = "180"; - profile_tier_level = ParseSdpForH265ProfileTierLevel(params); - EXPECT_TRUE(profile_tier_level); - EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile); - EXPECT_EQ(H265Level::kLevel6, profile_tier_level->level); - EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier); -} - -TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelInvalid) { - SdpVideoFormat::Parameters params; - - // Invalid profile-tier-level combination. - params["profile-id"] = "1"; - params["tier-flag"] = "1"; - params["level-id"] = "93"; - absl::optional profile_tier_level = - ParseSdpForH265ProfileTierLevel(params); - EXPECT_FALSE(profile_tier_level); - params.clear(); - params["profile-id"] = "1"; - params["tier-flag"] = "4"; - params["level-id"] = "180"; - profile_tier_level = ParseSdpForH265ProfileTierLevel(params); - EXPECT_FALSE(profile_tier_level); - - // Valid profile-tier-level combination. - params.clear(); - params["profile-id"] = "1"; - params["tier-flag"] = "0"; - params["level-id"] = "153"; - profile_tier_level = ParseSdpForH265ProfileTierLevel(params); - EXPECT_TRUE(profile_tier_level); -} - -TEST(H265ProfileTierLevel, TestToStringRoundTrip) { - SdpVideoFormat::Parameters params; - params["profile-id"] = "1"; - params["tier-flag"] = "0"; - params["level-id"] = "93"; - absl::optional profile_tier_level = - ParseSdpForH265ProfileTierLevel(params); - EXPECT_TRUE(profile_tier_level); - EXPECT_EQ("1", H265ProfileToString(profile_tier_level->profile)); - EXPECT_EQ("0", H265TierToString(profile_tier_level->tier)); - EXPECT_EQ("93", H265LevelToString(profile_tier_level->level)); - - params.clear(); - params["profile-id"] = "2"; - params["tier-flag"] = "1"; - params["level-id"] = "180"; - profile_tier_level = ParseSdpForH265ProfileTierLevel(params); - EXPECT_TRUE(profile_tier_level); - EXPECT_EQ("2", H265ProfileToString(profile_tier_level->profile)); - EXPECT_EQ("1", H265TierToString(profile_tier_level->tier)); - EXPECT_EQ("180", H265LevelToString(profile_tier_level->level)); -} - -TEST(H265ProfileTierLevel, TestProfileTierLevelCompare) { - SdpVideoFormat::Parameters params1; - SdpVideoFormat::Parameters params2; - - // None of profile-id/tier-flag/level-id is specified, - EXPECT_TRUE(H265IsSameProfileTierLevel(params1, params2)); - - // Same non-empty PTL - params1["profile-id"] = "1"; - params1["tier-flag"] = "0"; - params1["level-id"] = "120"; - params2["profile-id"] = "1"; - params2["tier-flag"] = "0"; - params2["level-id"] = "120"; - EXPECT_TRUE(H265IsSameProfileTierLevel(params1, params2)); - - // Different profiles. - params1.clear(); - params2.clear(); - params1["profile-id"] = "1"; - params2["profile-id"] = "2"; - EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2)); - - // Different levels. - params1.clear(); - params2.clear(); - params1["profile-id"] = "1"; - params2["profile-id"] = "1"; - params1["level-id"] = "93"; - params2["level-id"] = "183"; - EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2)); - - // Different tiers. - params1.clear(); - params2.clear(); - params1["profile-id"] = "1"; - params2["profile-id"] = "1"; - params1["level-id"] = "93"; - params2["level-id"] = "93"; - params1["tier-flag"] = "0"; - params2["tier-flag"] = "1"; - EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2)); - - // One of the SdpVideoFormat::Parameters is invalid. - params1.clear(); - params2.clear(); - params1["profile-id"] = "1"; - params2["profile-id"] = "1"; - params1["tier-flag"] = "0"; - params2["tier-flag"] = "4"; - EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2)); -} - -} // namespace webrtc +/* + * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/video_codecs/h265_profile_tier_level.h" + +#include + +#include "absl/types/optional.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(H265ProfileTierLevel, TestLevelToString) { + EXPECT_EQ(H265LevelToString(H265Level::kLevel1), "30"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel2), "60"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel2_1), "63"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel3), "90"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel3_1), "93"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel4), "120"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel4_1), "123"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel5), "150"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel5_1), "153"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel5_2), "156"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel6), "180"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel6_1), "183"); + EXPECT_EQ(H265LevelToString(H265Level::kLevel6_2), "186"); +} + +TEST(H265ProfileTierLevel, TestProfileToString) { + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMain), "1"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMain10), "2"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMainStill), "3"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileRangeExtensions), "4"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileHighThroughput), "5"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMultiviewMain), "6"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScalableMain), "7"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfile3dMain), "8"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScreenContentCoding), "9"); + EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScalableRangeExtensions), + "10"); + EXPECT_EQ(H265ProfileToString( + H265Profile::kProfileHighThroughputScreenContentCoding), + "11"); +} + +TEST(H265ProfileTierLevel, TestTierToString) { + EXPECT_EQ(H265TierToString(H265Tier::kTier0), "0"); + EXPECT_EQ(H265TierToString(H265Tier::kTier1), "1"); +} + +TEST(H265ProfileTierLevel, TestStringToProfile) { + // Invalid profiles. + EXPECT_FALSE(StringToH265Profile("0")); + EXPECT_FALSE(StringToH265Profile("12")); + + // Malformed profiles + EXPECT_FALSE(StringToH265Profile("")); + EXPECT_FALSE(StringToH265Profile(" 1")); + EXPECT_FALSE(StringToH265Profile("12x")); + EXPECT_FALSE(StringToH265Profile("x12")); + EXPECT_FALSE(StringToH265Profile("gggg")); + + // Valid profiles. + EXPECT_EQ(StringToH265Profile("1"), H265Profile::kProfileMain); + EXPECT_EQ(StringToH265Profile("2"), H265Profile::kProfileMain10); + EXPECT_EQ(StringToH265Profile("4"), H265Profile::kProfileRangeExtensions); +} + +TEST(H265ProfileTierLevel, TestStringToLevel) { + // Invalid levels. + EXPECT_FALSE(StringToH265Level("0")); + EXPECT_FALSE(StringToH265Level("200")); + + // Malformed levels. + EXPECT_FALSE(StringToH265Level("")); + EXPECT_FALSE(StringToH265Level(" 30")); + EXPECT_FALSE(StringToH265Level("30x")); + EXPECT_FALSE(StringToH265Level("x30")); + EXPECT_FALSE(StringToH265Level("ggggg")); + + // Valid levels. + EXPECT_EQ(StringToH265Level("30"), H265Level::kLevel1); + EXPECT_EQ(StringToH265Level("93"), H265Level::kLevel3_1); + EXPECT_EQ(StringToH265Level("183"), H265Level::kLevel6_1); +} + +TEST(H265ProfileTierLevel, TestStringToTier) { + // Invalid tiers. + EXPECT_FALSE(StringToH265Tier("4")); + EXPECT_FALSE(StringToH265Tier("-1")); + + // Malformed tiers. + EXPECT_FALSE(StringToH265Tier("")); + EXPECT_FALSE(StringToH265Tier(" 1")); + EXPECT_FALSE(StringToH265Tier("t1")); + + // Valid tiers. + EXPECT_EQ(StringToH265Tier("0"), H265Tier::kTier0); + EXPECT_EQ(StringToH265Tier("1"), H265Tier::kTier1); +} + +TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelAllEmpty) { + const absl::optional profile_tier_level = + ParseSdpForH265ProfileTierLevel(CodecParameterMap()); + EXPECT_TRUE(profile_tier_level); + EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile); + EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level); + EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier); +} + +TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelPartialEmpty) { + CodecParameterMap params; + params["profile-id"] = "1"; + params["tier-flag"] = "0"; + absl::optional profile_tier_level = + ParseSdpForH265ProfileTierLevel(params); + EXPECT_TRUE(profile_tier_level); + EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile); + EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level); + EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier); + + params.clear(); + params["profile-id"] = "2"; + profile_tier_level = ParseSdpForH265ProfileTierLevel(params); + EXPECT_TRUE(profile_tier_level); + EXPECT_EQ(H265Profile::kProfileMain10, profile_tier_level->profile); + EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level); + EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier); + + params.clear(); + params["level-id"] = "180"; + profile_tier_level = ParseSdpForH265ProfileTierLevel(params); + EXPECT_TRUE(profile_tier_level); + EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile); + EXPECT_EQ(H265Level::kLevel6, profile_tier_level->level); + EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier); +} + +TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelInvalid) { + CodecParameterMap params; + + // Invalid profile-tier-level combination. + params["profile-id"] = "1"; + params["tier-flag"] = "1"; + params["level-id"] = "93"; + absl::optional profile_tier_level = + ParseSdpForH265ProfileTierLevel(params); + EXPECT_FALSE(profile_tier_level); + params.clear(); + params["profile-id"] = "1"; + params["tier-flag"] = "4"; + params["level-id"] = "180"; + profile_tier_level = ParseSdpForH265ProfileTierLevel(params); + EXPECT_FALSE(profile_tier_level); + + // Valid profile-tier-level combination. + params.clear(); + params["profile-id"] = "1"; + params["tier-flag"] = "0"; + params["level-id"] = "153"; + profile_tier_level = ParseSdpForH265ProfileTierLevel(params); + EXPECT_TRUE(profile_tier_level); +} + +TEST(H265ProfileTierLevel, TestToStringRoundTrip) { + CodecParameterMap params; + params["profile-id"] = "1"; + params["tier-flag"] = "0"; + params["level-id"] = "93"; + absl::optional profile_tier_level = + ParseSdpForH265ProfileTierLevel(params); + EXPECT_TRUE(profile_tier_level); + EXPECT_EQ("1", H265ProfileToString(profile_tier_level->profile)); + EXPECT_EQ("0", H265TierToString(profile_tier_level->tier)); + EXPECT_EQ("93", H265LevelToString(profile_tier_level->level)); + + params.clear(); + params["profile-id"] = "2"; + params["tier-flag"] = "1"; + params["level-id"] = "180"; + profile_tier_level = ParseSdpForH265ProfileTierLevel(params); + EXPECT_TRUE(profile_tier_level); + EXPECT_EQ("2", H265ProfileToString(profile_tier_level->profile)); + EXPECT_EQ("1", H265TierToString(profile_tier_level->tier)); + EXPECT_EQ("180", H265LevelToString(profile_tier_level->level)); +} + +TEST(H265ProfileTierLevel, TestProfileTierLevelCompare) { + CodecParameterMap params1; + CodecParameterMap params2; + + // None of profile-id/tier-flag/level-id is specified, + EXPECT_TRUE(H265IsSameProfileTierLevel(params1, params2)); + + // Same non-empty PTL + params1["profile-id"] = "1"; + params1["tier-flag"] = "0"; + params1["level-id"] = "120"; + params2["profile-id"] = "1"; + params2["tier-flag"] = "0"; + params2["level-id"] = "120"; + EXPECT_TRUE(H265IsSameProfileTierLevel(params1, params2)); + + // Different profiles. + params1.clear(); + params2.clear(); + params1["profile-id"] = "1"; + params2["profile-id"] = "2"; + EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2)); + + // Different levels. + params1.clear(); + params2.clear(); + params1["profile-id"] = "1"; + params2["profile-id"] = "1"; + params1["level-id"] = "93"; + params2["level-id"] = "183"; + EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2)); + + // Different tiers. + params1.clear(); + params2.clear(); + params1["profile-id"] = "1"; + params2["profile-id"] = "1"; + params1["level-id"] = "93"; + params2["level-id"] = "93"; + params1["tier-flag"] = "0"; + params2["tier-flag"] = "1"; + EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2)); + + // One of the CodecParameterMap is invalid. + params1.clear(); + params2.clear(); + params1["profile-id"] = "1"; + params2["profile-id"] = "1"; + params1["tier-flag"] = "0"; + params2["tier-flag"] = "4"; + EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/api/video_codecs/test/sdp_video_format_unittest.cc b/third_party/libwebrtc/api/video_codecs/test/sdp_video_format_unittest.cc index 797a9a2e72..26e50d6945 100644 --- a/third_party/libwebrtc/api/video_codecs/test/sdp_video_format_unittest.cc +++ b/third_party/libwebrtc/api/video_codecs/test/sdp_video_format_unittest.cc @@ -18,7 +18,7 @@ namespace webrtc { typedef SdpVideoFormat Sdp; -typedef SdpVideoFormat::Parameters Params; +typedef CodecParameterMap Params; TEST(SdpVideoFormatTest, SameCodecNameNoParameters) { EXPECT_TRUE(Sdp("H264").IsSameCodec(Sdp("h264"))); diff --git a/third_party/libwebrtc/api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h b/third_party/libwebrtc/api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h index 417df1e192..0f801ad3c7 100644 --- a/third_party/libwebrtc/api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h +++ b/third_party/libwebrtc/api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h @@ -24,8 +24,7 @@ struct LibaomAv1EncoderTemplateAdapter { static std::vector SupportedFormats() { absl::InlinedVector scalability_modes = LibaomAv1EncoderSupportedScalabilityModes(); - return { - SdpVideoFormat("AV1", SdpVideoFormat::Parameters(), scalability_modes)}; + return {SdpVideoFormat("AV1", CodecParameterMap(), scalability_modes)}; } static std::unique_ptr CreateEncoder( diff --git a/third_party/libwebrtc/api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h b/third_party/libwebrtc/api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h index 0f0a9bacd5..c60aa04795 100644 --- a/third_party/libwebrtc/api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h +++ b/third_party/libwebrtc/api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h @@ -28,8 +28,7 @@ struct LibvpxVp8EncoderTemplateAdapter { scalability_modes.push_back(scalability_mode); } - return { - SdpVideoFormat("VP8", SdpVideoFormat::Parameters(), scalability_modes)}; + return {SdpVideoFormat("VP8", CodecParameterMap(), scalability_modes)}; } static std::unique_ptr CreateEncoder( diff --git a/third_party/libwebrtc/api/video_codecs/vp9_profile.cc b/third_party/libwebrtc/api/video_codecs/vp9_profile.cc index 7e627cc080..ccd3937296 100644 --- a/third_party/libwebrtc/api/video_codecs/vp9_profile.cc +++ b/third_party/libwebrtc/api/video_codecs/vp9_profile.cc @@ -54,7 +54,7 @@ absl::optional StringToVP9Profile(const std::string& str) { } absl::optional ParseSdpForVP9Profile( - const SdpVideoFormat::Parameters& params) { + const CodecParameterMap& params) { const auto profile_it = params.find(kVP9FmtpProfileId); if (profile_it == params.end()) return VP9Profile::kProfile0; @@ -62,8 +62,8 @@ absl::optional ParseSdpForVP9Profile( return StringToVP9Profile(profile_str); } -bool VP9IsSameProfile(const SdpVideoFormat::Parameters& params1, - const SdpVideoFormat::Parameters& params2) { +bool VP9IsSameProfile(const CodecParameterMap& params1, + const CodecParameterMap& params2) { const absl::optional profile = ParseSdpForVP9Profile(params1); const absl::optional other_profile = ParseSdpForVP9Profile(params2); diff --git a/third_party/libwebrtc/api/video_codecs/vp9_profile.h b/third_party/libwebrtc/api/video_codecs/vp9_profile.h index b570bc3bb6..27f84cbecc 100644 --- a/third_party/libwebrtc/api/video_codecs/vp9_profile.h +++ b/third_party/libwebrtc/api/video_codecs/vp9_profile.h @@ -42,12 +42,12 @@ absl::optional StringToVP9Profile(const std::string& str); // profile key is missing. Nothing will be returned if the key is present but // the string is invalid. RTC_EXPORT absl::optional ParseSdpForVP9Profile( - const SdpVideoFormat::Parameters& params); + const CodecParameterMap& params); // Returns true if the parameters have the same VP9 profile, or neither contains // VP9 profile. -bool VP9IsSameProfile(const SdpVideoFormat::Parameters& params1, - const SdpVideoFormat::Parameters& params2); +bool VP9IsSameProfile(const CodecParameterMap& params1, + const CodecParameterMap& params2); } // namespace webrtc diff --git a/third_party/libwebrtc/audio/BUILD.gn b/third_party/libwebrtc/audio/BUILD.gn index 09562b9131..7ece107407 100644 --- a/third_party/libwebrtc/audio/BUILD.gn +++ b/third_party/libwebrtc/audio/BUILD.gn @@ -97,7 +97,6 @@ rtc_library("audio") { "../rtc_base:refcount", "../rtc_base:rtc_event", "../rtc_base:rtc_numerics", - "../rtc_base:rtc_task_queue", "../rtc_base:safe_conversions", "../rtc_base:safe_minmax", "../rtc_base:stringutils", @@ -175,7 +174,8 @@ if (rtc_include_tests) { "../api/audio_codecs/opus:audio_decoder_opus", "../api/audio_codecs/opus:audio_encoder_opus", "../api/crypto:frame_decryptor_interface", - "../api/rtc_event_log", + "../api/environment", + "../api/environment:environment_factory", "../api/task_queue:default_task_queue_factory", "../api/task_queue/test:mock_task_queue_base", "../api/units:time_delta", @@ -223,7 +223,10 @@ if (rtc_include_tests) { "utility:utility_tests", "//testing/gtest", ] - absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/types:optional", + ] } rtc_library("channel_receive_unittest") { @@ -247,6 +250,9 @@ if (rtc_include_tests) { "../test:test_support", "../test/time_controller", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] } } diff --git a/third_party/libwebrtc/audio/audio_receive_stream.cc b/third_party/libwebrtc/audio/audio_receive_stream.cc index c49b83f95f..32a8e1c172 100644 --- a/third_party/libwebrtc/audio/audio_receive_stream.cc +++ b/third_party/libwebrtc/audio/audio_receive_stream.cc @@ -186,6 +186,7 @@ void AudioReceiveStreamImpl::Start() { if (playing_) { return; } + RTC_LOG(LS_INFO) << "AudioReceiveStreamImpl::Start: " << remote_ssrc(); channel_receive_->StartPlayout(); playing_ = true; audio_state()->AddReceivingStream(this); @@ -196,6 +197,7 @@ void AudioReceiveStreamImpl::Stop() { if (!playing_) { return; } + RTC_LOG(LS_INFO) << "AudioReceiveStreamImpl::Stop: " << remote_ssrc(); channel_receive_->StopPlayout(); playing_ = false; audio_state()->RemoveReceivingStream(this); diff --git a/third_party/libwebrtc/audio/audio_send_stream.cc b/third_party/libwebrtc/audio/audio_send_stream.cc index e7ebb2bf4e..8dc78b18fa 100644 --- a/third_party/libwebrtc/audio/audio_send_stream.cc +++ b/third_party/libwebrtc/audio/audio_send_stream.cc @@ -355,6 +355,7 @@ void AudioSendStream::Start() { if (sending_) { return; } + RTC_LOG(LS_INFO) << "AudioSendStream::Start: " << config_.rtp.ssrc; if (!config_.has_dscp && config_.min_bitrate_bps != -1 && config_.max_bitrate_bps != -1 && (allocate_audio_without_feedback_ || TransportSeqNumId(config_) != 0)) { @@ -376,7 +377,7 @@ void AudioSendStream::Stop() { if (!sending_) { return; } - + RTC_LOG(LS_INFO) << "AudioSendStream::Stop: " << config_.rtp.ssrc; RemoveBitrateObserver(); channel_send_->StopSend(); sending_ = false; diff --git a/third_party/libwebrtc/audio/audio_send_stream.h b/third_party/libwebrtc/audio/audio_send_stream.h index 62ccd524cb..09fd712d40 100644 --- a/third_party/libwebrtc/audio/audio_send_stream.h +++ b/third_party/libwebrtc/audio/audio_send_stream.h @@ -28,7 +28,6 @@ #include "rtc_base/experiments/struct_parameters_parser.h" #include "rtc_base/race_checker.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" namespace webrtc { class RtcEventLog; diff --git a/third_party/libwebrtc/audio/channel_receive_frame_transformer_delegate.h b/third_party/libwebrtc/audio/channel_receive_frame_transformer_delegate.h index 37ff75c2e9..d572ffe8d1 100644 --- a/third_party/libwebrtc/audio/channel_receive_frame_transformer_delegate.h +++ b/third_party/libwebrtc/audio/channel_receive_frame_transformer_delegate.h @@ -16,8 +16,8 @@ #include "api/frame_transformer_interface.h" #include "api/sequence_checker.h" +#include "api/task_queue/task_queue_base.h" #include "rtc_base/system/no_unique_address.h" -#include "rtc_base/task_queue.h" #include "rtc_base/thread.h" namespace webrtc { diff --git a/third_party/libwebrtc/audio/channel_send.cc b/third_party/libwebrtc/audio/channel_send.cc index 3c59be52b4..ae264a4c77 100644 --- a/third_party/libwebrtc/audio/channel_send.cc +++ b/third_party/libwebrtc/audio/channel_send.cc @@ -39,7 +39,7 @@ #include "rtc_base/rate_limiter.h" #include "rtc_base/strings/string_builder.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" +#include "rtc_base/system/no_unique_address.h" #include "rtc_base/time_utils.h" #include "rtc_base/trace_event.h" #include "system_wrappers/include/clock.h" @@ -196,7 +196,7 @@ class ChannelSend : public ChannelSendInterface, rtc::ArrayView payload, int64_t absolute_capture_timestamp_ms, rtc::ArrayView csrcs) - RTC_RUN_ON(encoder_queue_); + RTC_RUN_ON(encoder_queue_checker_); void OnReceivedRtt(int64_t rtt_ms); @@ -207,7 +207,7 @@ class ChannelSend : public ChannelSendInterface, // specific threads we know about. The goal is to eventually split up // voe::Channel into parts with single-threaded semantics, and thereby reduce // the need for locks. - SequenceChecker worker_thread_checker_; + RTC_NO_UNIQUE_ADDRESS SequenceChecker worker_thread_checker_; // Methods accessed from audio and video threads are checked for sequential- // only access. We don't necessarily own and control these threads, so thread // checkers cannot be used. E.g. Chromium may transfer "ownership" from one @@ -231,9 +231,9 @@ class ChannelSend : public ChannelSendInterface, absl::optional last_capture_timestamp_ms_ RTC_GUARDED_BY(audio_thread_race_checker_); - RmsLevel rms_level_ RTC_GUARDED_BY(encoder_queue_); + RmsLevel rms_level_ RTC_GUARDED_BY(encoder_queue_checker_); bool input_mute_ RTC_GUARDED_BY(volume_settings_mutex_) = false; - bool previous_frame_muted_ RTC_GUARDED_BY(encoder_queue_) = false; + bool previous_frame_muted_ RTC_GUARDED_BY(encoder_queue_checker_) = false; const std::unique_ptr rtcp_counter_observer_; @@ -242,7 +242,7 @@ class ChannelSend : public ChannelSendInterface, const std::unique_ptr rtp_packet_pacer_proxy_; const std::unique_ptr retransmission_rate_limiter_; - SequenceChecker construction_thread_; + RTC_NO_UNIQUE_ADDRESS SequenceChecker construction_thread_; std::atomic include_audio_level_indication_ = false; std::atomic encoder_queue_is_active_ = false; @@ -250,7 +250,7 @@ class ChannelSend : public ChannelSendInterface, // E2EE Audio Frame Encryption rtc::scoped_refptr frame_encryptor_ - RTC_GUARDED_BY(encoder_queue_); + RTC_GUARDED_BY(encoder_queue_checker_); // E2EE Frame Encryption Options const webrtc::CryptoOptions crypto_options_; @@ -258,15 +258,14 @@ class ChannelSend : public ChannelSendInterface, // receives callbacks with the transformed frames; delegates calls to // ChannelSend::SendRtpAudio to send the transformed audio. rtc::scoped_refptr - frame_transformer_delegate_ RTC_GUARDED_BY(encoder_queue_); + frame_transformer_delegate_ RTC_GUARDED_BY(encoder_queue_checker_); mutable Mutex rtcp_counter_mutex_; RtcpPacketTypeCounter rtcp_packet_type_counter_ RTC_GUARDED_BY(rtcp_counter_mutex_); - // Defined last to ensure that there are no running tasks when the other - // members are destroyed. - rtc::TaskQueue encoder_queue_; + std::unique_ptr encoder_queue_; + RTC_NO_UNIQUE_ADDRESS SequenceChecker encoder_queue_checker_; SdpAudioFormat encoder_format_; }; @@ -299,7 +298,7 @@ class RtpPacketSenderProxy : public RtpPacketSender { } private: - SequenceChecker thread_checker_; + RTC_NO_UNIQUE_ADDRESS SequenceChecker thread_checker_; Mutex mutex_; RtpPacketSender* rtp_packet_pacer_ RTC_GUARDED_BY(&mutex_); }; @@ -310,7 +309,7 @@ int32_t ChannelSend::SendData(AudioFrameType frameType, const uint8_t* payloadData, size_t payloadSize, int64_t absolute_capture_timestamp_ms) { - RTC_DCHECK_RUN_ON(&encoder_queue_); + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); rtc::ArrayView payload(payloadData, payloadSize); if (frame_transformer_delegate_) { // Asynchronously transform the payload before sending it. After the payload @@ -438,6 +437,7 @@ ChannelSend::ChannelSend( encoder_queue_(task_queue_factory->CreateTaskQueue( "AudioEncoder", TaskQueueFactory::Priority::NORMAL)), + encoder_queue_checker_(encoder_queue_.get()), encoder_format_("x-unknown", 0, 0) { audio_coding_ = AudioCodingModule::Create(); @@ -490,6 +490,10 @@ ChannelSend::~ChannelSend() { StopSend(); int error = audio_coding_->RegisterTransportCallback(NULL); RTC_DCHECK_EQ(0, error); + + // Delete the encoder task queue first to ensure that there are no running + // tasks when the other members are destroyed. + encoder_queue_ = nullptr; } void ChannelSend::StartSend() { @@ -519,8 +523,8 @@ void ChannelSend::StopSend() { // Wait until all pending encode tasks are executed and clear any remaining // buffers in the encoder. rtc::Event flush; - encoder_queue_.PostTask([this, &flush]() { - RTC_DCHECK_RUN_ON(&encoder_queue_); + encoder_queue_->PostTask([this, &flush]() { + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); CallEncoder([](AudioEncoder* encoder) { encoder->Reset(); }); flush.Set(); }); @@ -794,9 +798,9 @@ void ChannelSend::ProcessAndEncodeAudio( // Profile time between when the audio frame is added to the task queue and // when the task is actually executed. audio_frame->UpdateProfileTimeStamp(); - encoder_queue_.PostTask( + encoder_queue_->PostTask( [this, audio_frame = std::move(audio_frame)]() mutable { - RTC_DCHECK_RUN_ON(&encoder_queue_); + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); if (!encoder_queue_is_active_.load()) { return; } @@ -858,8 +862,8 @@ int64_t ChannelSend::GetRTT() const { void ChannelSend::SetFrameEncryptor( rtc::scoped_refptr frame_encryptor) { RTC_DCHECK_RUN_ON(&worker_thread_checker_); - encoder_queue_.PostTask([this, frame_encryptor]() mutable { - RTC_DCHECK_RUN_ON(&encoder_queue_); + encoder_queue_->PostTask([this, frame_encryptor]() mutable { + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); frame_encryptor_ = std::move(frame_encryptor); }); } @@ -870,9 +874,9 @@ void ChannelSend::SetEncoderToPacketizerFrameTransformer( if (!frame_transformer) return; - encoder_queue_.PostTask( + encoder_queue_->PostTask( [this, frame_transformer = std::move(frame_transformer)]() mutable { - RTC_DCHECK_RUN_ON(&encoder_queue_); + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); InitFrameTransformerDelegate(std::move(frame_transformer)); }); } @@ -885,7 +889,7 @@ void ChannelSend::OnReceivedRtt(int64_t rtt_ms) { void ChannelSend::InitFrameTransformerDelegate( rtc::scoped_refptr frame_transformer) { - RTC_DCHECK_RUN_ON(&encoder_queue_); + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); RTC_DCHECK(frame_transformer); RTC_DCHECK(!frame_transformer_delegate_); @@ -897,7 +901,7 @@ void ChannelSend::InitFrameTransformerDelegate( rtc::ArrayView payload, int64_t absolute_capture_timestamp_ms, rtc::ArrayView csrcs) { - RTC_DCHECK_RUN_ON(&encoder_queue_); + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); return SendRtpAudio( frameType, payloadType, rtp_timestamp_with_offset - rtp_rtcp_->StartTimestamp(), payload, @@ -906,7 +910,7 @@ void ChannelSend::InitFrameTransformerDelegate( frame_transformer_delegate_ = rtc::make_ref_counted( std::move(send_audio_callback), std::move(frame_transformer), - &encoder_queue_); + encoder_queue_.get()); frame_transformer_delegate_->Init(); } diff --git a/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate.cc b/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate.cc index 2eea0d2387..ac32410aed 100644 --- a/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate.cc +++ b/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate.cc @@ -114,7 +114,7 @@ class TransformableOutgoingAudioFrame ChannelSendFrameTransformerDelegate::ChannelSendFrameTransformerDelegate( SendFrameCallback send_frame_callback, rtc::scoped_refptr frame_transformer, - rtc::TaskQueue* encoder_queue) + TaskQueueBase* encoder_queue) : send_frame_callback_(send_frame_callback), frame_transformer_(std::move(frame_transformer)), encoder_queue_(encoder_queue) {} diff --git a/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate.h b/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate.h index 97fc14f737..30e63ff98b 100644 --- a/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate.h +++ b/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate.h @@ -16,10 +16,10 @@ #include "api/frame_transformer_interface.h" #include "api/sequence_checker.h" +#include "api/task_queue/task_queue_base.h" #include "modules/audio_coding/include/audio_coding_module_typedefs.h" #include "rtc_base/buffer.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" namespace webrtc { @@ -40,7 +40,7 @@ class ChannelSendFrameTransformerDelegate : public TransformedFrameCallback { ChannelSendFrameTransformerDelegate( SendFrameCallback send_frame_callback, rtc::scoped_refptr frame_transformer, - rtc::TaskQueue* encoder_queue); + TaskQueueBase* encoder_queue); // Registers `this` as callback for `frame_transformer_`, to get the // transformed frames. @@ -79,7 +79,7 @@ class ChannelSendFrameTransformerDelegate : public TransformedFrameCallback { mutable Mutex send_lock_; SendFrameCallback send_frame_callback_ RTC_GUARDED_BY(send_lock_); rtc::scoped_refptr frame_transformer_; - rtc::TaskQueue* encoder_queue_ RTC_GUARDED_BY(send_lock_); + TaskQueueBase* const encoder_queue_; bool short_circuit_ RTC_GUARDED_BY(send_lock_) = false; }; diff --git a/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate_unittest.cc b/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate_unittest.cc index 4dcd15cd95..483a2cce78 100644 --- a/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate_unittest.cc +++ b/third_party/libwebrtc/audio/channel_send_frame_transformer_delegate_unittest.cc @@ -78,7 +78,7 @@ std::unique_ptr CreateFrame() { MockChannelSend mock_channel; rtc::scoped_refptr delegate = rtc::make_ref_counted( - mock_channel.callback(), mock_frame_transformer, &channel_queue); + mock_channel.callback(), mock_frame_transformer, channel_queue.Get()); std::unique_ptr frame; ON_CALL(*mock_frame_transformer, Transform) @@ -131,7 +131,7 @@ TEST(ChannelSendFrameTransformerDelegateTest, MockChannelSend mock_channel; rtc::scoped_refptr delegate = rtc::make_ref_counted( - mock_channel.callback(), mock_frame_transformer, &channel_queue); + mock_channel.callback(), mock_frame_transformer, channel_queue.Get()); rtc::scoped_refptr callback; EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback) .WillOnce(SaveArg<0>(&callback)); @@ -160,7 +160,7 @@ TEST(ChannelSendFrameTransformerDelegateTest, MockChannelSend mock_channel; rtc::scoped_refptr delegate = rtc::make_ref_counted( - mock_channel.callback(), mock_frame_transformer, &channel_queue); + mock_channel.callback(), mock_frame_transformer, channel_queue.Get()); rtc::scoped_refptr callback; EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback) .WillOnce(SaveArg<0>(&callback)); @@ -192,7 +192,7 @@ TEST(ChannelSendFrameTransformerDelegateTest, MockChannelSend mock_channel; rtc::scoped_refptr delegate = rtc::make_ref_counted( - mock_channel.callback(), mock_frame_transformer, &channel_queue); + mock_channel.callback(), mock_frame_transformer, channel_queue.Get()); delegate->Reset(); EXPECT_CALL(mock_channel, SendFrame).Times(0); @@ -207,7 +207,7 @@ TEST(ChannelSendFrameTransformerDelegateTest, ShortCircuitingSkipsTransform) { MockChannelSend mock_channel; rtc::scoped_refptr delegate = rtc::make_ref_counted( - mock_channel.callback(), mock_frame_transformer, &channel_queue); + mock_channel.callback(), mock_frame_transformer, channel_queue.Get()); delegate->StartShortCircuiting(); diff --git a/third_party/libwebrtc/audio/channel_send_unittest.cc b/third_party/libwebrtc/audio/channel_send_unittest.cc index 58d7c93c1e..c86dcefadc 100644 --- a/third_party/libwebrtc/audio/channel_send_unittest.cc +++ b/third_party/libwebrtc/audio/channel_send_unittest.cc @@ -14,7 +14,8 @@ #include "api/audio/audio_frame.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" -#include "api/rtc_event_log/rtc_event_log.h" +#include "api/environment/environment.h" +#include "api/environment/environment_factory.h" #include "api/scoped_refptr.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" @@ -53,18 +54,17 @@ class ChannelSendTest : public ::testing::Test { protected: ChannelSendTest() : time_controller_(Timestamp::Seconds(1)), + env_(CreateEnvironment(&field_trials_, + time_controller_.GetClock(), + time_controller_.CreateTaskQueueFactory())), transport_controller_( - time_controller_.GetClock(), - RtpTransportConfig{ - .bitrate_config = GetBitrateConfig(), - .event_log = &event_log_, - .task_queue_factory = time_controller_.GetTaskQueueFactory(), - .trials = &field_trials_, - }) { + RtpTransportConfig{.env = env_, + .bitrate_config = GetBitrateConfig()}) { channel_ = voe::CreateChannelSend( time_controller_.GetClock(), time_controller_.GetTaskQueueFactory(), - &transport_, nullptr, &event_log_, nullptr, crypto_options_, false, - kRtcpIntervalMs, kSsrc, nullptr, &transport_controller_, field_trials_); + &transport_, nullptr, &env_.event_log(), nullptr, crypto_options_, + false, kRtcpIntervalMs, kSsrc, nullptr, &transport_controller_, + env_.field_trials()); encoder_factory_ = CreateBuiltinAudioEncoderFactory(); SdpAudioFormat opus = SdpAudioFormat("opus", kRtpRateHz, 2); std::unique_ptr encoder = @@ -94,7 +94,7 @@ class ChannelSendTest : public ::testing::Test { GlobalSimulatedTimeController time_controller_; webrtc::test::ScopedKeyValueConfig field_trials_; - RtcEventLogNull event_log_; + Environment env_; NiceMock transport_; CryptoOptions crypto_options_; RtpTransportControllerSend transport_controller_; diff --git a/third_party/libwebrtc/audio/voip/BUILD.gn b/third_party/libwebrtc/audio/voip/BUILD.gn index e807e2276b..75f20a6ed2 100644 --- a/third_party/libwebrtc/audio/voip/BUILD.gn +++ b/third_party/libwebrtc/audio/voip/BUILD.gn @@ -94,7 +94,6 @@ rtc_library("audio_egress") { "../../modules/rtp_rtcp", "../../modules/rtp_rtcp:rtp_rtcp_format", "../../rtc_base:logging", - "../../rtc_base:rtc_task_queue", "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:no_unique_address", diff --git a/third_party/libwebrtc/audio/voip/audio_egress.cc b/third_party/libwebrtc/audio/voip/audio_egress.cc index 95a1a3351e..09396cd28d 100644 --- a/third_party/libwebrtc/audio/voip/audio_egress.cc +++ b/third_party/libwebrtc/audio/voip/audio_egress.cc @@ -13,6 +13,7 @@ #include #include +#include "api/sequence_checker.h" #include "rtc_base/logging.h" namespace webrtc { @@ -25,12 +26,17 @@ AudioEgress::AudioEgress(RtpRtcpInterface* rtp_rtcp, audio_coding_(AudioCodingModule::Create()), encoder_queue_(task_queue_factory->CreateTaskQueue( "AudioEncoder", - TaskQueueFactory::Priority::NORMAL)) { + TaskQueueFactory::Priority::NORMAL)), + encoder_queue_checker_(encoder_queue_.get()) { audio_coding_->RegisterTransportCallback(this); } AudioEgress::~AudioEgress() { audio_coding_->RegisterTransportCallback(nullptr); + + // Delete first to ensure that there are no running tasks when the other + // members are destroyed. + encoder_queue_ = nullptr; } bool AudioEgress::IsSending() const { @@ -73,9 +79,9 @@ void AudioEgress::SendAudioData(std::unique_ptr audio_frame) { RTC_DCHECK_GT(audio_frame->samples_per_channel_, 0); RTC_DCHECK_LE(audio_frame->num_channels_, 8); - encoder_queue_.PostTask( + encoder_queue_->PostTask( [this, audio_frame = std::move(audio_frame)]() mutable { - RTC_DCHECK_RUN_ON(&encoder_queue_); + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); if (!rtp_rtcp_->SendingMedia()) { return; } @@ -112,7 +118,7 @@ int32_t AudioEgress::SendData(AudioFrameType frame_type, uint32_t timestamp, const uint8_t* payload_data, size_t payload_size) { - RTC_DCHECK_RUN_ON(&encoder_queue_); + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); rtc::ArrayView payload(payload_data, payload_size); @@ -175,8 +181,8 @@ bool AudioEgress::SendTelephoneEvent(int dtmf_event, int duration_ms) { } void AudioEgress::SetMute(bool mute) { - encoder_queue_.PostTask([this, mute] { - RTC_DCHECK_RUN_ON(&encoder_queue_); + encoder_queue_->PostTask([this, mute] { + RTC_DCHECK_RUN_ON(&encoder_queue_checker_); encoder_context_.mute_ = mute; }); } diff --git a/third_party/libwebrtc/audio/voip/audio_egress.h b/third_party/libwebrtc/audio/voip/audio_egress.h index 989e5bda59..6d1489db34 100644 --- a/third_party/libwebrtc/audio/voip/audio_egress.h +++ b/third_party/libwebrtc/audio/voip/audio_egress.h @@ -16,6 +16,7 @@ #include "api/audio_codecs/audio_format.h" #include "api/sequence_checker.h" +#include "api/task_queue/task_queue_base.h" #include "api/task_queue/task_queue_factory.h" #include "audio/audio_level.h" #include "audio/utility/audio_frame_operations.h" @@ -25,7 +26,7 @@ #include "modules/rtp_rtcp/source/rtp_rtcp_interface.h" #include "modules/rtp_rtcp/source/rtp_sender_audio.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" +#include "rtc_base/system/no_unique_address.h" #include "rtc_base/time_utils.h" namespace webrtc { @@ -146,11 +147,10 @@ class AudioEgress : public AudioSender, public AudioPacketizationCallback { bool previously_muted_ = false; }; - EncoderContext encoder_context_ RTC_GUARDED_BY(encoder_queue_); + EncoderContext encoder_context_ RTC_GUARDED_BY(encoder_queue_checker_); - // Defined last to ensure that there are no running tasks when the other - // members are destroyed. - rtc::TaskQueue encoder_queue_; + std::unique_ptr encoder_queue_; + RTC_NO_UNIQUE_ADDRESS SequenceChecker encoder_queue_checker_; }; } // namespace webrtc diff --git a/third_party/libwebrtc/call/BUILD.gn b/third_party/libwebrtc/call/BUILD.gn index 626ed95066..50a8257631 100644 --- a/third_party/libwebrtc/call/BUILD.gn +++ b/third_party/libwebrtc/call/BUILD.gn @@ -46,10 +46,8 @@ rtc_library("call_interfaces") { ":rtp_interfaces", ":video_stream_api", "../api:fec_controller_api", - "../api:field_trials_view", "../api:frame_transformer_interface", "../api:network_state_predictor_api", - "../api:rtc_error", "../api:rtp_headers", "../api:rtp_parameters", "../api:rtp_sender_setparameters_callback", @@ -116,20 +114,20 @@ rtc_library("rtp_interfaces") { deps = [ "../api:array_view", "../api:fec_controller_api", - "../api:field_trials_view", "../api:frame_transformer_interface", "../api:network_state_predictor_api", "../api:rtp_headers", "../api:rtp_parameters", "../api/crypto:options", + "../api/environment", "../api/rtc_event_log", "../api/transport:bitrate_settings", "../api/transport:network_control", + "../api/units:time_delta", "../api/units:timestamp", "../common_video:frame_counts", "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base:checks", - "../rtc_base:rtc_task_queue", "../rtc_base:stringutils", ] absl_deps = [ @@ -191,6 +189,7 @@ rtc_library("rtp_sender") { "../api:rtp_parameters", "../api:sequence_checker", "../api:transport_api", + "../api/environment", "../api/rtc_event_log", "../api/task_queue:pending_task_safety_flag", "../api/task_queue:task_queue", @@ -280,8 +279,8 @@ rtc_library("bitrate_allocator") { rtc_library("call") { sources = [ "call.cc", - "call_factory.cc", - "call_factory.h", + "create_call.cc", + "create_call.h", "degraded_call.cc", "degraded_call.h", "flexfec_receive_stream_impl.cc", @@ -301,7 +300,6 @@ rtc_library("call") { ":version", ":video_stream_api", "../api:array_view", - "../api:callfactory_api", "../api:fec_controller_api", "../api:field_trials_view", "../api:rtp_headers", @@ -355,7 +353,7 @@ rtc_library("call") { ] if (build_with_mozilla) { # See Bug 1820869. sources -= [ - "call_factory.cc", + "create_call.cc", "degraded_call.cc", ] deps -= [ diff --git a/third_party/libwebrtc/call/call.cc b/third_party/libwebrtc/call/call.cc index 63dc370f1a..71511b2559 100644 --- a/third_party/libwebrtc/call/call.cc +++ b/third_party/libwebrtc/call/call.cc @@ -70,7 +70,7 @@ #include "video/send_delay_stats.h" #include "video/stats_counter.h" #include "video/video_receive_stream2.h" -#include "video/video_send_stream.h" +#include "video/video_send_stream_impl.h" namespace webrtc { @@ -183,10 +183,8 @@ class Call final : public webrtc::Call, public TargetTransferRateObserver, public BitrateAllocator::LimitObserver { public: - Call(Clock* clock, - const CallConfig& config, - std::unique_ptr transport_send, - TaskQueueFactory* task_queue_factory); + Call(const CallConfig& config, + std::unique_ptr transport_send); ~Call() override; Call(const Call&) = delete; @@ -345,8 +343,7 @@ class Call final : public webrtc::Call, // callbacks have been registered. void EnsureStarted() RTC_RUN_ON(worker_thread_); - Clock* const clock_; - TaskQueueFactory* const task_queue_factory_; + const Environment env_; TaskQueueBase* const worker_thread_; TaskQueueBase* const network_thread_; const std::unique_ptr decode_sync_; @@ -356,8 +353,6 @@ class Call final : public webrtc::Call, const std::unique_ptr call_stats_; const std::unique_ptr bitrate_allocator_; const CallConfig config_ RTC_GUARDED_BY(worker_thread_); - // Maps to config_.trials, can be used from any thread via `trials()`. - const FieldTrialsView& trials_; NetworkState audio_network_state_ RTC_GUARDED_BY(worker_thread_); NetworkState video_network_state_ RTC_GUARDED_BY(worker_thread_); @@ -393,9 +388,10 @@ class Call final : public webrtc::Call, // should be accessed on the network thread. std::map audio_send_ssrcs_ RTC_GUARDED_BY(worker_thread_); - std::map video_send_ssrcs_ + std::map video_send_ssrcs_ + RTC_GUARDED_BY(worker_thread_); + std::set video_send_streams_ RTC_GUARDED_BY(worker_thread_); - std::set video_send_streams_ RTC_GUARDED_BY(worker_thread_); // True if `video_send_streams_` is empty, false if not. The atomic variable // is used to decide UMA send statistics behavior and enables avoiding a // PostTask(). @@ -413,8 +409,6 @@ class Call final : public webrtc::Call, RtpPayloadStateMap suspended_video_payload_states_ RTC_GUARDED_BY(worker_thread_); - webrtc::RtcEventLog* const event_log_; - // TODO(bugs.webrtc.org/11993) ready to move stats access to the network // thread. ReceiveStats receive_stats_ RTC_GUARDED_BY(worker_thread_); @@ -460,25 +454,17 @@ class Call final : public webrtc::Call, }; } // namespace internal -/* Mozilla: Avoid this since it could use GetRealTimeClock(). std::unique_ptr Call::Create(const CallConfig& config) { - Clock* clock = - config.env.has_value() ? &config.env->clock() : Clock::GetRealTimeClock(); - return Create(config, clock, - RtpTransportControllerSendFactory().Create( - config.ExtractTransportConfig(), clock)); -} - */ + std::unique_ptr transport_send; + if (config.rtp_transport_controller_send_factory != nullptr) { + transport_send = config.rtp_transport_controller_send_factory->Create( + config.ExtractTransportConfig()); + } else { + transport_send = RtpTransportControllerSendFactory().Create( + config.ExtractTransportConfig()); + } -std::unique_ptr Call::Create( - const CallConfig& config, - Clock* clock, - std::unique_ptr - transportControllerSend) { - RTC_DCHECK(config.task_queue_factory); - return std::make_unique(clock, config, - std::move(transportControllerSend), - config.task_queue_factory); + return std::make_unique(config, std::move(transport_send)); } // This method here to avoid subclasses has to implement this method. @@ -644,47 +630,41 @@ void Call::SendStats::SetMinAllocatableRate(BitrateAllocationLimits limits) { min_allocated_send_bitrate_bps_ = limits.min_allocatable_rate.bps(); } -Call::Call(Clock* clock, - const CallConfig& config, - std::unique_ptr transport_send, - TaskQueueFactory* task_queue_factory) - : clock_(clock), - task_queue_factory_(task_queue_factory), +Call::Call(const CallConfig& config, + std::unique_ptr transport_send) + : env_(config.env), worker_thread_(GetCurrentTaskQueueOrThread()), // If `network_task_queue_` was set to nullptr, network related calls // must be made on `worker_thread_` (i.e. they're one and the same). network_thread_(config.network_task_queue_ ? config.network_task_queue_ : worker_thread_), - decode_sync_(config.metronome - ? std::make_unique(clock_, - config.metronome, - worker_thread_) - : nullptr), + decode_sync_( + config.decode_metronome + ? std::make_unique(&env_.clock(), + config.decode_metronome, + worker_thread_) + : nullptr), num_cpu_cores_(CpuInfo::DetectNumberOfCores()), - call_stats_(new CallStats(clock_, worker_thread_)), + call_stats_(new CallStats(&env_.clock(), worker_thread_)), bitrate_allocator_(new BitrateAllocator(this)), config_(config), - trials_(*config.trials), audio_network_state_(kNetworkDown), video_network_state_(kNetworkDown), aggregate_network_up_(false), - event_log_(config.event_log), - receive_stats_(clock_), - send_stats_(clock_), - receive_side_cc_(clock, + receive_stats_(&env_.clock()), + send_stats_(&env_.clock()), + receive_side_cc_(&env_.clock(), absl::bind_front(&PacketRouter::SendCombinedRtcpPacket, transport_send->packet_router()), absl::bind_front(&PacketRouter::SendRemb, transport_send->packet_router()), /*network_state_estimator=*/nullptr), receive_time_calculator_( - ReceiveTimeCalculator::CreateFromFieldTrial(*config.trials)), - video_send_delay_stats_(new SendDelayStats(clock_)), - start_of_call_(clock_->CurrentTime()), + ReceiveTimeCalculator::CreateFromFieldTrial(env_.field_trials())), + video_send_delay_stats_(new SendDelayStats(&env_.clock())), + start_of_call_(env_.clock().CurrentTime()), transport_send_ptr_(transport_send.get()), transport_send_(std::move(transport_send)) { - RTC_DCHECK(config.event_log != nullptr); - RTC_DCHECK(config.trials != nullptr); RTC_DCHECK(network_thread_); RTC_DCHECK(worker_thread_->IsCurrent()); @@ -702,7 +682,7 @@ Call::Call(Clock* clock, receive_side_cc_periodic_task_ = RepeatingTaskHandle::Start( worker_thread_, [receive_side_cc] { return receive_side_cc->MaybeProcess(); }, - TaskQueueBase::DelayPrecision::kLow, clock_); + TaskQueueBase::DelayPrecision::kLow, &env_.clock()); } Call::~Call() { @@ -720,7 +700,7 @@ Call::~Call() { RTC_HISTOGRAM_COUNTS_100000( "WebRTC.Call.LifetimeInSeconds", - (clock_->CurrentTime() - start_of_call_).seconds()); + (env_.clock().CurrentTime() - start_of_call_).seconds()); } void Call::EnsureStarted() { @@ -765,8 +745,8 @@ webrtc::AudioSendStream* Call::CreateAudioSendStream( } AudioSendStream* send_stream = new AudioSendStream( - clock_, config, config_.audio_state, task_queue_factory_, - transport_send_.get(), bitrate_allocator_.get(), event_log_, + &env_.clock(), config, config_.audio_state, &env_.task_queue_factory(), + transport_send_.get(), bitrate_allocator_.get(), &env_.event_log(), call_stats_->AsRtcpRttStats(), suspended_rtp_state, trials()); RTC_DCHECK(audio_send_ssrcs_.find(config.rtp.ssrc) == audio_send_ssrcs_.end()); @@ -818,12 +798,12 @@ webrtc::AudioReceiveStreamInterface* Call::CreateAudioReceiveStream( TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream"); RTC_DCHECK_RUN_ON(worker_thread_); EnsureStarted(); - event_log_->Log(std::make_unique( + env_.event_log().Log(std::make_unique( CreateRtcLogStreamConfig(config))); AudioReceiveStreamImpl* receive_stream = new AudioReceiveStreamImpl( - clock_, transport_send_->packet_router(), config_.neteq_factory, config, - config_.audio_state, event_log_); + &env_.clock(), transport_send_->packet_router(), config_.neteq_factory, + config, config_.audio_state, &env_.event_log()); audio_receive_streams_.insert(receive_stream); // TODO(bugs.webrtc.org/11993): Make the registration on the network thread @@ -885,7 +865,7 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream( video_send_delay_stats_->AddSsrcs(config); for (size_t ssrc_index = 0; ssrc_index < config.rtp.ssrcs.size(); ++ssrc_index) { - event_log_->Log(std::make_unique( + env_.event_log().Log(std::make_unique( CreateRtcLogStreamConfig(config, ssrc_index))); } @@ -894,13 +874,14 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream( // Copy ssrcs from `config` since `config` is moved. std::vector ssrcs = config.rtp.ssrcs; - VideoSendStream* send_stream = new VideoSendStream( - clock_, num_cpu_cores_, task_queue_factory_, network_thread_, + VideoSendStreamImpl* send_stream = new VideoSendStreamImpl( + &env_.clock(), num_cpu_cores_, &env_.task_queue_factory(), call_stats_->AsRtcpRttStats(), transport_send_.get(), - bitrate_allocator_.get(), video_send_delay_stats_.get(), event_log_, - std::move(config), std::move(encoder_config), suspended_video_send_ssrcs_, + config_.encode_metronome, bitrate_allocator_.get(), + video_send_delay_stats_.get(), &env_.event_log(), std::move(config), + std::move(encoder_config), suspended_video_send_ssrcs_, suspended_video_payload_states_, std::move(fec_controller), - *config_.trials); + env_.field_trials()); for (uint32_t ssrc : ssrcs) { RTC_DCHECK(video_send_ssrcs_.find(ssrc) == video_send_ssrcs_.end()); @@ -928,8 +909,8 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream( } std::unique_ptr fec_controller = config_.fec_controller_factory - ? config_.fec_controller_factory->CreateFecController() - : std::make_unique(clock_); + ? config_.fec_controller_factory->CreateFecController(env_) + : std::make_unique(env_); return CreateVideoSendStream(std::move(config), std::move(encoder_config), std::move(fec_controller)); } @@ -939,12 +920,12 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) { RTC_DCHECK(send_stream != nullptr); RTC_DCHECK_RUN_ON(worker_thread_); - VideoSendStream* send_stream_impl = - static_cast(send_stream); + VideoSendStreamImpl* send_stream_impl = + static_cast(send_stream); auto it = video_send_ssrcs_.begin(); while (it != video_send_ssrcs_.end()) { - if (it->second == static_cast(send_stream)) { + if (it->second == static_cast(send_stream)) { send_stream_impl = it->second; video_send_ssrcs_.erase(it++); } else { @@ -960,8 +941,8 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) { if (video_send_streams_.empty()) video_send_streams_empty_.store(true, std::memory_order_relaxed); - VideoSendStream::RtpStateMap rtp_states; - VideoSendStream::RtpPayloadStateMap rtp_payload_states; + VideoSendStreamImpl::RtpStateMap rtp_states; + VideoSendStreamImpl::RtpPayloadStateMap rtp_payload_states; send_stream_impl->StopPermanentlyAndGetRtpStates(&rtp_states, &rtp_payload_states); for (const auto& kv : rtp_states) { @@ -984,7 +965,7 @@ webrtc::VideoReceiveStreamInterface* Call::CreateVideoReceiveStream( EnsureStarted(); - event_log_->Log(std::make_unique( + env_.event_log().Log(std::make_unique( CreateRtcLogStreamConfig(configuration))); // TODO(bugs.webrtc.org/11993): Move the registration between `receive_stream` @@ -994,10 +975,10 @@ webrtc::VideoReceiveStreamInterface* Call::CreateVideoReceiveStream( // TODO(crbug.com/1381982): Re-enable decode synchronizer once the Chromium // API has adapted to the new Metronome interface. VideoReceiveStream2* receive_stream = new VideoReceiveStream2( - task_queue_factory_, this, num_cpu_cores_, - transport_send_->packet_router(), std::move(configuration), - call_stats_.get(), clock_, std::make_unique(clock_, trials()), - &nack_periodic_processor_, decode_sync_.get(), event_log_); + env_, this, num_cpu_cores_, transport_send_->packet_router(), + std::move(configuration), call_stats_.get(), + std::make_unique(&env_.clock(), trials()), + &nack_periodic_processor_, decode_sync_.get()); // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network // thread. receive_stream->RegisterWithTransport(&video_receiver_controller_); @@ -1040,7 +1021,7 @@ FlexfecReceiveStream* Call::CreateFlexfecReceiveStream( // OnRtpPacket until the constructor is finished and the object is // in a valid state, since OnRtpPacket runs on the same thread. FlexfecReceiveStreamImpl* receive_stream = new FlexfecReceiveStreamImpl( - clock_, std::move(config), &video_receiver_controller_, + &env_.clock(), std::move(config), &video_receiver_controller_, call_stats_->AsRtcpRttStats()); // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network @@ -1104,7 +1085,7 @@ Call::Stats Call::GetStats() const { } const FieldTrialsView& Call::trials() const { - return trials_; + return env_.field_trials(); } TaskQueueBase* Call::network_thread() const { @@ -1244,7 +1225,7 @@ void Call::OnSentPacket(const rtc::SentPacket& sent_packet) { // on a ProcessThread. This is alright as is since we forward the call to // implementations that either just do a PostTask or use locking. video_send_delay_stats_->OnSentPacket(sent_packet.packet_id, - clock_->CurrentTime()); + env_.clock().CurrentTime()); transport_send_->OnSentPacket(sent_packet); } @@ -1341,7 +1322,7 @@ void Call::DeliverRtcpPacket(rtc::CopyOnWriteBuffer packet) { rtcp_delivered = true; } - for (VideoSendStream* stream : video_send_streams_) { + for (VideoSendStreamImpl* stream : video_send_streams_) { stream->DeliverRtcp(packet.cdata(), packet.size()); rtcp_delivered = true; } @@ -1352,7 +1333,7 @@ void Call::DeliverRtcpPacket(rtc::CopyOnWriteBuffer packet) { } if (rtcp_delivered) { - event_log_->Log(std::make_unique(packet)); + env_.event_log().Log(std::make_unique(packet)); } } @@ -1368,13 +1349,14 @@ void Call::DeliverRtpPacket( // Repair packet_time_us for clock resets by comparing a new read of // the same clock (TimeUTCMicros) to a monotonic clock reading. packet_time_us = receive_time_calculator_->ReconcileReceiveTimes( - packet_time_us, rtc::TimeUTCMicros(), clock_->TimeInMicroseconds()); + packet_time_us, rtc::TimeUTCMicros(), + env_.clock().TimeInMicroseconds()); packet.set_arrival_time(Timestamp::Micros(packet_time_us)); } NotifyBweOfReceivedPacket(packet, media_type); - event_log_->Log(std::make_unique(packet)); + env_.event_log().Log(std::make_unique(packet)); if (media_type != MediaType::AUDIO && media_type != MediaType::VIDEO) { return; } diff --git a/third_party/libwebrtc/call/call.h b/third_party/libwebrtc/call/call.h index b36872f5b5..e7d37c0abd 100644 --- a/third_party/libwebrtc/call/call.h +++ b/third_party/libwebrtc/call/call.h @@ -25,7 +25,6 @@ #include "call/call_config.h" #include "call/flexfec_receive_stream.h" #include "call/packet_receiver.h" -#include "call/rtp_transport_controller_send_interface.h" #include "call/video_receive_stream.h" #include "call/video_send_stream.h" #include "rtc_base/copy_on_write_buffer.h" @@ -49,11 +48,6 @@ class Call { using Stats = CallBasicStats; static std::unique_ptr Create(const CallConfig& config); - static std::unique_ptr Create( - const CallConfig& config, - Clock* clock, - std::unique_ptr - transportControllerSend); virtual AudioSendStream* CreateAudioSendStream( const AudioSendStream::Config& config) = 0; diff --git a/third_party/libwebrtc/call/call_config.cc b/third_party/libwebrtc/call/call_config.cc index 5832969b9c..0a6ad2c2ec 100644 --- a/third_party/libwebrtc/call/call_config.cc +++ b/third_party/libwebrtc/call/call_config.cc @@ -10,37 +10,27 @@ #include "call/call_config.h" -#include "rtc_base/checks.h" +#include "api/environment/environment.h" +#include "api/task_queue/task_queue_base.h" namespace webrtc { CallConfig::CallConfig(const Environment& env, TaskQueueBase* network_task_queue) : env(env), - event_log(&env.event_log()), - task_queue_factory(&env.task_queue_factory()), - trials(&env.field_trials()), network_task_queue_(network_task_queue) {} -CallConfig::CallConfig(RtcEventLog* event_log, - TaskQueueBase* network_task_queue /* = nullptr*/) - : event_log(event_log), network_task_queue_(network_task_queue) { - RTC_DCHECK(event_log); -} - CallConfig::CallConfig(const CallConfig& config) = default; RtpTransportConfig CallConfig::ExtractTransportConfig() const { - RtpTransportConfig transportConfig; - transportConfig.bitrate_config = bitrate_config; - transportConfig.event_log = event_log; - transportConfig.network_controller_factory = network_controller_factory; - transportConfig.network_state_predictor_factory = + RtpTransportConfig transport_config = {.env = env}; + transport_config.bitrate_config = bitrate_config; + transport_config.network_controller_factory = network_controller_factory; + transport_config.network_state_predictor_factory = network_state_predictor_factory; - transportConfig.task_queue_factory = task_queue_factory; - transportConfig.trials = trials; + transport_config.pacer_burst_interval = pacer_burst_interval; - return transportConfig; + return transport_config; } CallConfig::~CallConfig() = default; diff --git a/third_party/libwebrtc/call/call_config.h b/third_party/libwebrtc/call/call_config.h index 1b1f696fee..6fd9179a43 100644 --- a/third_party/libwebrtc/call/call_config.h +++ b/third_party/libwebrtc/call/call_config.h @@ -10,15 +10,11 @@ #ifndef CALL_CALL_CONFIG_H_ #define CALL_CALL_CONFIG_H_ -#include "absl/types/optional.h" #include "api/environment/environment.h" #include "api/fec_controller.h" -#include "api/field_trials_view.h" #include "api/metronome/metronome.h" #include "api/neteq/neteq_factory.h" #include "api/network_state_predictor.h" -#include "api/rtc_error.h" -#include "api/task_queue/task_queue_factory.h" #include "api/transport/bitrate_settings.h" #include "api/transport/network_control.h" #include "call/audio_state.h" @@ -28,7 +24,6 @@ namespace webrtc { class AudioProcessing; -class RtcEventLog; struct CallConfig { // If `network_task_queue` is set to nullptr, Call will assume that network @@ -37,19 +32,13 @@ struct CallConfig { explicit CallConfig(const Environment& env, TaskQueueBase* network_task_queue = nullptr); - // TODO(bugs.webrtc.org/15656): Deprecate and delete constructor below. - explicit CallConfig(RtcEventLog* event_log, - TaskQueueBase* network_task_queue = nullptr); - CallConfig(const CallConfig&); ~CallConfig(); RtpTransportConfig ExtractTransportConfig() const; - // TODO(bugs.webrtc.org/15656): Make non-optional when constructor that - // doesn't pass Environment is removed. - absl::optional env; + Environment env; // Bitrate config used until valid bitrate estimates are calculated. Also // used to cap total bitrate used. This comes from the remote connection. @@ -61,16 +50,9 @@ struct CallConfig { // Audio Processing Module to be used in this call. AudioProcessing* audio_processing = nullptr; - // RtcEventLog to use for this call. Required. - // Use webrtc::RtcEventLog::CreateNull() for a null implementation. - RtcEventLog* const event_log = nullptr; - // FecController to use for this call. FecControllerFactoryInterface* fec_controller_factory = nullptr; - // Task Queue Factory to be used in this call. Required. - TaskQueueFactory* task_queue_factory = nullptr; - // NetworkStatePredictor to use for this call. NetworkStatePredictorFactoryInterface* network_state_predictor_factory = nullptr; @@ -81,16 +63,16 @@ struct CallConfig { // NetEq factory to use for this call. NetEqFactory* neteq_factory = nullptr; - // Key-value mapping of internal configurations to apply, - // e.g. field trials. - const FieldTrialsView* trials = nullptr; - TaskQueueBase* const network_task_queue_ = nullptr; // RtpTransportControllerSend to use for this call. RtpTransportControllerSendFactoryInterface* rtp_transport_controller_send_factory = nullptr; - Metronome* metronome = nullptr; + Metronome* decode_metronome = nullptr; + Metronome* encode_metronome = nullptr; + + // The burst interval of the pacer, see TaskQueuePacedSender constructor. + absl::optional pacer_burst_interval; // Enables send packet batching from the egress RTP sender. bool enable_send_packet_batching = false; diff --git a/third_party/libwebrtc/call/call_factory.cc b/third_party/libwebrtc/call/call_factory.cc deleted file mode 100644 index 78a4f1635f..0000000000 --- a/third_party/libwebrtc/call/call_factory.cc +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "call/call_factory.h" - -#include - -#include -#include -#include -#include - -#include "absl/types/optional.h" -#include "api/test/simulated_network.h" -#include "api/units/time_delta.h" -#include "call/call.h" -#include "call/degraded_call.h" -#include "call/rtp_transport_config.h" -#include "rtc_base/checks.h" -#include "rtc_base/experiments/field_trial_list.h" -#include "rtc_base/experiments/field_trial_parser.h" - -namespace webrtc { -namespace { -using TimeScopedNetworkConfig = DegradedCall::TimeScopedNetworkConfig; - -std::vector GetNetworkConfigs( - const FieldTrialsView& trials, - bool send) { - FieldTrialStructList trials_list( - {FieldTrialStructMember("queue_length_packets", - [](TimeScopedNetworkConfig* p) { - // FieldTrialParser does not natively support - // size_t type, so use this ugly cast as - // workaround. - return reinterpret_cast( - &p->queue_length_packets); - }), - FieldTrialStructMember( - "queue_delay_ms", - [](TimeScopedNetworkConfig* p) { return &p->queue_delay_ms; }), - FieldTrialStructMember("delay_standard_deviation_ms", - [](TimeScopedNetworkConfig* p) { - return &p->delay_standard_deviation_ms; - }), - FieldTrialStructMember( - "link_capacity_kbps", - [](TimeScopedNetworkConfig* p) { return &p->link_capacity_kbps; }), - FieldTrialStructMember( - "loss_percent", - [](TimeScopedNetworkConfig* p) { return &p->loss_percent; }), - FieldTrialStructMember( - "allow_reordering", - [](TimeScopedNetworkConfig* p) { return &p->allow_reordering; }), - FieldTrialStructMember("avg_burst_loss_length", - [](TimeScopedNetworkConfig* p) { - return &p->avg_burst_loss_length; - }), - FieldTrialStructMember( - "packet_overhead", - [](TimeScopedNetworkConfig* p) { return &p->packet_overhead; }), - FieldTrialStructMember( - "duration", - [](TimeScopedNetworkConfig* p) { return &p->duration; })}, - {}); - ParseFieldTrial({&trials_list}, - trials.Lookup(send ? "WebRTC-FakeNetworkSendConfig" - : "WebRTC-FakeNetworkReceiveConfig")); - return trials_list.Get(); -} - -} // namespace - -CallFactory::CallFactory() { - call_thread_.Detach(); -} - -std::unique_ptr CallFactory::CreateCall(const CallConfig& config) { - RTC_DCHECK_RUN_ON(&call_thread_); - RTC_DCHECK(config.trials); - - std::vector send_degradation_configs = - GetNetworkConfigs(*config.trials, /*send=*/true); - std::vector - receive_degradation_configs = - GetNetworkConfigs(*config.trials, /*send=*/false); - - RtpTransportConfig transportConfig = config.ExtractTransportConfig(); - - RTC_CHECK(false); - return nullptr; - /* Mozilla: Avoid this since it could use GetRealTimeClock(). - std::unique_ptr call = - Call::Create(config, Clock::GetRealTimeClock(), - config.rtp_transport_controller_send_factory->Create( - transportConfig, Clock::GetRealTimeClock())); - - if (!send_degradation_configs.empty() || - !receive_degradation_configs.empty()) { - return std::make_unique( - std::move(call), send_degradation_configs, receive_degradation_configs); - } - - return call; - */ -} - -std::unique_ptr CreateCallFactory() { - return std::make_unique(); -} - -} // namespace webrtc diff --git a/third_party/libwebrtc/call/call_factory.h b/third_party/libwebrtc/call/call_factory.h deleted file mode 100644 index f75b1bd71b..0000000000 --- a/third_party/libwebrtc/call/call_factory.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef CALL_CALL_FACTORY_H_ -#define CALL_CALL_FACTORY_H_ - -#include - -#include "api/call/call_factory_interface.h" -#include "api/sequence_checker.h" -#include "call/call.h" -#include "call/call_config.h" -#include "rtc_base/system/no_unique_address.h" - -namespace webrtc { - -class CallFactory : public CallFactoryInterface { - public: - CallFactory(); - ~CallFactory() override = default; - - private: - std::unique_ptr CreateCall(const CallConfig& config) override; - - RTC_NO_UNIQUE_ADDRESS SequenceChecker call_thread_; -}; - -} // namespace webrtc - -#endif // CALL_CALL_FACTORY_H_ diff --git a/third_party/libwebrtc/call/create_call.cc b/third_party/libwebrtc/call/create_call.cc new file mode 100644 index 0000000000..8b565745a8 --- /dev/null +++ b/third_party/libwebrtc/call/create_call.cc @@ -0,0 +1,98 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "call/create_call.h" + +#include + +#include +#include +#include +#include + +#include "absl/types/optional.h" +#include "api/test/simulated_network.h" +#include "api/units/time_delta.h" +#include "call/call.h" +#include "call/degraded_call.h" +#include "rtc_base/checks.h" +#include "rtc_base/experiments/field_trial_list.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { +namespace { +using TimeScopedNetworkConfig = DegradedCall::TimeScopedNetworkConfig; + +std::vector GetNetworkConfigs( + const FieldTrialsView& trials, + bool send) { + FieldTrialStructList trials_list( + {FieldTrialStructMember("queue_length_packets", + [](TimeScopedNetworkConfig* p) { + // FieldTrialParser does not natively support + // size_t type, so use this ugly cast as + // workaround. + return reinterpret_cast( + &p->queue_length_packets); + }), + FieldTrialStructMember( + "queue_delay_ms", + [](TimeScopedNetworkConfig* p) { return &p->queue_delay_ms; }), + FieldTrialStructMember("delay_standard_deviation_ms", + [](TimeScopedNetworkConfig* p) { + return &p->delay_standard_deviation_ms; + }), + FieldTrialStructMember( + "link_capacity_kbps", + [](TimeScopedNetworkConfig* p) { return &p->link_capacity_kbps; }), + FieldTrialStructMember( + "loss_percent", + [](TimeScopedNetworkConfig* p) { return &p->loss_percent; }), + FieldTrialStructMember( + "allow_reordering", + [](TimeScopedNetworkConfig* p) { return &p->allow_reordering; }), + FieldTrialStructMember("avg_burst_loss_length", + [](TimeScopedNetworkConfig* p) { + return &p->avg_burst_loss_length; + }), + FieldTrialStructMember( + "packet_overhead", + [](TimeScopedNetworkConfig* p) { return &p->packet_overhead; }), + FieldTrialStructMember( + "duration", + [](TimeScopedNetworkConfig* p) { return &p->duration; })}, + {}); + ParseFieldTrial({&trials_list}, + trials.Lookup(send ? "WebRTC-FakeNetworkSendConfig" + : "WebRTC-FakeNetworkReceiveConfig")); + return trials_list.Get(); +} + +} // namespace + +std::unique_ptr CreateCall(const CallConfig& config) { + std::vector send_degradation_configs = + GetNetworkConfigs(config.env.field_trials(), /*send=*/true); + std::vector + receive_degradation_configs = + GetNetworkConfigs(config.env.field_trials(), /*send=*/false); + + std::unique_ptr call = Call::Create(config); + + if (!send_degradation_configs.empty() || + !receive_degradation_configs.empty()) { + return std::make_unique( + std::move(call), send_degradation_configs, receive_degradation_configs); + } + + return call; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/call/create_call.h b/third_party/libwebrtc/call/create_call.h new file mode 100644 index 0000000000..afba08800e --- /dev/null +++ b/third_party/libwebrtc/call/create_call.h @@ -0,0 +1,25 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef CALL_CREATE_CALL_H_ +#define CALL_CREATE_CALL_H_ + +#include + +#include "call/call.h" +#include "call/call_config.h" + +namespace webrtc { + +std::unique_ptr CreateCall(const CallConfig& config); + +} // namespace webrtc + +#endif // CALL_CREATE_CALL_H_ diff --git a/third_party/libwebrtc/call/rtp_transport_config.h b/third_party/libwebrtc/call/rtp_transport_config.h index f2030b3672..cce5214fc8 100644 --- a/third_party/libwebrtc/call/rtp_transport_config.h +++ b/third_party/libwebrtc/call/rtp_transport_config.h @@ -13,27 +13,22 @@ #include -#include "api/field_trials_view.h" +#include "absl/types/optional.h" +#include "api/environment/environment.h" #include "api/network_state_predictor.h" -#include "api/rtc_event_log/rtc_event_log.h" #include "api/transport/bitrate_settings.h" #include "api/transport/network_control.h" -#include "rtc_base/task_queue.h" +#include "api/units/time_delta.h" namespace webrtc { struct RtpTransportConfig { + Environment env; + // Bitrate config used until valid bitrate estimates are calculated. Also // used to cap total bitrate used. This comes from the remote connection. BitrateConstraints bitrate_config; - // RtcEventLog to use for this call. Required. - // Use webrtc::RtcEventLog::CreateNull() for a null implementation. - RtcEventLog* event_log = nullptr; - - // Task Queue Factory to be used in this call. Required. - TaskQueueFactory* task_queue_factory = nullptr; - // NetworkStatePredictor to use for this call. NetworkStatePredictorFactoryInterface* network_state_predictor_factory = nullptr; @@ -41,9 +36,8 @@ struct RtpTransportConfig { // Network controller factory to use for this call. NetworkControllerFactoryInterface* network_controller_factory = nullptr; - // Key-value mapping of internal configurations to apply, - // e.g. field trials. - const FieldTrialsView* trials = nullptr; + // The burst interval of the pacer, see TaskQueuePacedSender constructor. + absl::optional pacer_burst_interval; }; } // namespace webrtc diff --git a/third_party/libwebrtc/call/rtp_transport_controller_send.cc b/third_party/libwebrtc/call/rtp_transport_controller_send.cc index 8d24f7551e..600d4e2620 100644 --- a/third_party/libwebrtc/call/rtp_transport_controller_send.cc +++ b/third_party/libwebrtc/call/rtp_transport_controller_send.cc @@ -62,55 +62,56 @@ TargetRateConstraints ConvertConstraints(const BitrateConstraints& contraints, contraints.start_bitrate_bps, clock); } -bool IsEnabled(const FieldTrialsView& trials, absl::string_view key) { - return absl::StartsWith(trials.Lookup(key), "Enabled"); -} - bool IsRelayed(const rtc::NetworkRoute& route) { return route.local.uses_turn() || route.remote.uses_turn(); } } // namespace RtpTransportControllerSend::RtpTransportControllerSend( - Clock* clock, const RtpTransportConfig& config) - : clock_(clock), - event_log_(config.event_log), - task_queue_factory_(config.task_queue_factory), + : env_(config.env), task_queue_(TaskQueueBase::Current()), bitrate_configurator_(config.bitrate_config), pacer_started_(false), - pacer_(clock, &packet_router_, *config.trials, TimeDelta::Millis(5), 3), + pacer_(&env_.clock(), + &packet_router_, + env_.field_trials(), + TimeDelta::Millis(5), + 3), observer_(nullptr), controller_factory_override_(config.network_controller_factory), controller_factory_fallback_( std::make_unique( config.network_state_predictor_factory)), process_interval_(controller_factory_fallback_->GetProcessInterval()), - last_report_block_time_(Timestamp::Millis(clock_->TimeInMilliseconds())), + last_report_block_time_( + Timestamp::Millis(env_.clock().TimeInMilliseconds())), reset_feedback_on_route_change_( - !IsEnabled(*config.trials, "WebRTC-Bwe-NoFeedbackReset")), - add_pacing_to_cwin_( - IsEnabled(*config.trials, - "WebRTC-AddPacingToCongestionWindowPushback")), + !env_.field_trials().IsEnabled("WebRTC-Bwe-NoFeedbackReset")), + add_pacing_to_cwin_(env_.field_trials().IsEnabled( + "WebRTC-AddPacingToCongestionWindowPushback")), relay_bandwidth_cap_("relay_cap", DataRate::PlusInfinity()), transport_overhead_bytes_per_packet_(0), network_available_(false), congestion_window_size_(DataSize::PlusInfinity()), is_congested_(false), - retransmission_rate_limiter_(clock, kRetransmitWindowSizeMs), - field_trials_(*config.trials) { - ParseFieldTrial({&relay_bandwidth_cap_}, - config.trials->Lookup("WebRTC-Bwe-NetworkRouteConstraints")); + retransmission_rate_limiter_(&env_.clock(), kRetransmitWindowSizeMs) { + ParseFieldTrial( + {&relay_bandwidth_cap_}, + env_.field_trials().Lookup("WebRTC-Bwe-NetworkRouteConstraints")); initial_config_.constraints = - ConvertConstraints(config.bitrate_config, clock_); - initial_config_.event_log = config.event_log; - initial_config_.key_value_config = config.trials; + ConvertConstraints(config.bitrate_config, &env_.clock()); + initial_config_.event_log = &env_.event_log(); + initial_config_.key_value_config = &env_.field_trials(); RTC_DCHECK(config.bitrate_config.start_bitrate_bps > 0); pacer_.SetPacingRates( DataRate::BitsPerSec(config.bitrate_config.start_bitrate_bps), DataRate::Zero()); + if (config.pacer_burst_interval) { + // Default burst interval overriden by config. + pacer_.SetSendBurstInterval(*config.pacer_burst_interval); + } } RtpTransportControllerSend::~RtpTransportControllerSend() { @@ -133,14 +134,14 @@ RtpVideoSenderInterface* RtpTransportControllerSend::CreateRtpVideoSender( rtc::scoped_refptr frame_transformer) { RTC_DCHECK_RUN_ON(&sequence_checker_); video_rtp_senders_.push_back(std::make_unique( - clock_, suspended_ssrcs, states, rtp_config, rtcp_report_interval_ms, - send_transport, observers, + &env_.clock(), suspended_ssrcs, states, rtp_config, + rtcp_report_interval_ms, send_transport, observers, // TODO(holmer): Remove this circular dependency by injecting // the parts of RtpTransportControllerSendInterface that are really used. this, event_log, &retransmission_rate_limiter_, std::move(fec_controller), frame_encryption_config.frame_encryptor, frame_encryption_config.crypto_options, std::move(frame_transformer), - field_trials_, task_queue_factory_)); + env_.field_trials(), &env_.task_queue_factory())); return video_rtp_senders_.back().get(); } @@ -302,13 +303,11 @@ void RtpTransportControllerSend::OnNetworkRouteChanged( << " bps."; RTC_DCHECK_GT(bitrate_config.start_bitrate_bps, 0); - if (event_log_) { - event_log_->Log(std::make_unique( - network_route.connected, network_route.packet_overhead)); - } + env_.event_log().Log(std::make_unique( + network_route.connected, network_route.packet_overhead)); NetworkRouteChange msg; - msg.at_time = Timestamp::Millis(clock_->TimeInMilliseconds()); - msg.constraints = ConvertConstraints(bitrate_config, clock_); + msg.at_time = Timestamp::Millis(env_.clock().TimeInMilliseconds()); + msg.constraints = ConvertConstraints(bitrate_config, &env_.clock()); transport_overhead_bytes_per_packet_ = network_route.packet_overhead; if (reset_feedback_on_route_change_) { transport_feedback_adapter_.SetNetworkRoute(network_route); @@ -327,7 +326,7 @@ void RtpTransportControllerSend::OnNetworkAvailability(bool network_available) { RTC_LOG(LS_VERBOSE) << "SignalNetworkState " << (network_available ? "Up" : "Down"); NetworkAvailability msg; - msg.at_time = Timestamp::Millis(clock_->TimeInMilliseconds()); + msg.at_time = Timestamp::Millis(env_.clock().TimeInMilliseconds()); msg.network_available = network_available; network_available_ = network_available; if (network_available) { @@ -425,7 +424,7 @@ void RtpTransportControllerSend::OnReceivedPacket( void RtpTransportControllerSend::UpdateBitrateConstraints( const BitrateConstraints& updated) { RTC_DCHECK_RUN_ON(&sequence_checker_); - TargetRateConstraints msg = ConvertConstraints(updated, clock_); + TargetRateConstraints msg = ConvertConstraints(updated, &env_.clock()); if (controller_) { PostUpdates(controller_->OnTargetRateConstraints(msg)); } else { @@ -528,7 +527,8 @@ void RtpTransportControllerSend::OnRttUpdate(Timestamp receive_time, void RtpTransportControllerSend::OnAddPacket( const RtpPacketSendInfo& packet_info) { RTC_DCHECK_RUN_ON(&sequence_checker_); - Timestamp creation_time = Timestamp::Millis(clock_->TimeInMilliseconds()); + Timestamp creation_time = + Timestamp::Millis(env_.clock().TimeInMilliseconds()); feedback_demuxer_.AddPacket(packet_info); transport_feedback_adapter_.AddPacket( packet_info, transport_overhead_bytes_per_packet_, creation_time); @@ -554,11 +554,9 @@ void RtpTransportControllerSend::OnTransportFeedback( void RtpTransportControllerSend::OnRemoteNetworkEstimate( NetworkStateEstimate estimate) { RTC_DCHECK_RUN_ON(&sequence_checker_); - if (event_log_) { - event_log_->Log(std::make_unique( - estimate.link_capacity_lower, estimate.link_capacity_upper)); - } - estimate.update_time = Timestamp::Millis(clock_->TimeInMilliseconds()); + env_.event_log().Log(std::make_unique( + estimate.link_capacity_lower, estimate.link_capacity_upper)); + estimate.update_time = Timestamp::Millis(env_.clock().TimeInMilliseconds()); if (controller_) PostUpdates(controller_->OnNetworkStateEstimate(estimate)); } @@ -572,7 +570,7 @@ void RtpTransportControllerSend::MaybeCreateControllers() { control_handler_ = std::make_unique(); initial_config_.constraints.at_time = - Timestamp::Millis(clock_->TimeInMilliseconds()); + Timestamp::Millis(env_.clock().TimeInMilliseconds()); initial_config_.stream_based_config = streams_config_; // TODO(srte): Use fallback controller if no feedback is available. @@ -623,14 +621,15 @@ void RtpTransportControllerSend::StartProcessPeriodicTasks() { void RtpTransportControllerSend::UpdateControllerWithTimeInterval() { RTC_DCHECK(controller_); ProcessInterval msg; - msg.at_time = Timestamp::Millis(clock_->TimeInMilliseconds()); + msg.at_time = Timestamp::Millis(env_.clock().TimeInMilliseconds()); if (add_pacing_to_cwin_) msg.pacer_queue = pacer_.QueueSizeData(); PostUpdates(controller_->OnProcessInterval(msg)); } void RtpTransportControllerSend::UpdateStreamsConfig() { - streams_config_.at_time = Timestamp::Millis(clock_->TimeInMilliseconds()); + streams_config_.at_time = + Timestamp::Millis(env_.clock().TimeInMilliseconds()); if (controller_) PostUpdates(controller_->OnStreamsConfig(streams_config_)); } diff --git a/third_party/libwebrtc/call/rtp_transport_controller_send.h b/third_party/libwebrtc/call/rtp_transport_controller_send.h index 1aace1ce65..c0bca41a2b 100644 --- a/third_party/libwebrtc/call/rtp_transport_controller_send.h +++ b/third_party/libwebrtc/call/rtp_transport_controller_send.h @@ -18,6 +18,7 @@ #include #include "absl/strings/string_view.h" +#include "api/environment/environment.h" #include "api/network_state_predictor.h" #include "api/sequence_checker.h" #include "api/task_queue/task_queue_base.h" @@ -41,7 +42,6 @@ #include "rtc_base/task_utils/repeating_task.h" namespace webrtc { -class Clock; class FrameEncryptorInterface; class RtcEventLog; @@ -51,7 +51,7 @@ class RtpTransportControllerSend final public TransportFeedbackObserver, public NetworkStateEstimateObserver { public: - RtpTransportControllerSend(Clock* clock, const RtpTransportConfig& config); + explicit RtpTransportControllerSend(const RtpTransportConfig& config); ~RtpTransportControllerSend() override; RtpTransportControllerSend(const RtpTransportControllerSend&) = delete; @@ -146,9 +146,7 @@ class RtpTransportControllerSend final void ProcessSentPacketUpdates(NetworkControlUpdate updates) RTC_RUN_ON(sequence_checker_); - Clock* const clock_; - RtcEventLog* const event_log_; - TaskQueueFactory* const task_queue_factory_; + const Environment env_; SequenceChecker sequence_checker_; TaskQueueBase* task_queue_; PacketRouter packet_router_; @@ -207,8 +205,6 @@ class RtpTransportControllerSend final RateLimiter retransmission_rate_limiter_; ScopedTaskSafety safety_; - - const FieldTrialsView& field_trials_; }; } // namespace webrtc diff --git a/third_party/libwebrtc/call/rtp_transport_controller_send_factory.h b/third_party/libwebrtc/call/rtp_transport_controller_send_factory.h index 6349302e45..cd5a3c58ae 100644 --- a/third_party/libwebrtc/call/rtp_transport_controller_send_factory.h +++ b/third_party/libwebrtc/call/rtp_transport_controller_send_factory.h @@ -22,10 +22,8 @@ class RtpTransportControllerSendFactory : public RtpTransportControllerSendFactoryInterface { public: std::unique_ptr Create( - const RtpTransportConfig& config, - Clock* clock) override { - RTC_CHECK(config.trials); - return std::make_unique(clock, config); + const RtpTransportConfig& config) override { + return std::make_unique(config); } virtual ~RtpTransportControllerSendFactory() {} diff --git a/third_party/libwebrtc/call/rtp_transport_controller_send_factory_interface.h b/third_party/libwebrtc/call/rtp_transport_controller_send_factory_interface.h index 0f4c36c221..8683a34c9e 100644 --- a/third_party/libwebrtc/call/rtp_transport_controller_send_factory_interface.h +++ b/third_party/libwebrtc/call/rtp_transport_controller_send_factory_interface.h @@ -20,11 +20,10 @@ namespace webrtc { // controller. class RtpTransportControllerSendFactoryInterface { public: - virtual std::unique_ptr Create( - const RtpTransportConfig& config, - Clock* clock) = 0; + virtual ~RtpTransportControllerSendFactoryInterface() = default; - virtual ~RtpTransportControllerSendFactoryInterface() {} + virtual std::unique_ptr Create( + const RtpTransportConfig& config) = 0; }; } // namespace webrtc #endif // CALL_RTP_TRANSPORT_CONTROLLER_SEND_FACTORY_INTERFACE_H_ diff --git a/third_party/libwebrtc/call/rtp_video_sender_unittest.cc b/third_party/libwebrtc/call/rtp_video_sender_unittest.cc index 9646a81cfd..cf099afaa3 100644 --- a/third_party/libwebrtc/call/rtp_video_sender_unittest.cc +++ b/third_party/libwebrtc/call/rtp_video_sender_unittest.cc @@ -16,6 +16,8 @@ #include #include "absl/functional/any_invocable.h" +#include "api/environment/environment.h" +#include "api/environment/environment_factory.h" #include "call/rtp_transport_controller_send.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/source/byte_io.h" @@ -118,23 +120,21 @@ class RtpVideoSenderTestFixture { rtc::scoped_refptr frame_transformer, const FieldTrialsView* field_trials = nullptr) : time_controller_(Timestamp::Millis(1000000)), + env_(CreateEnvironment(&field_trials_, + field_trials, + time_controller_.GetClock(), + time_controller_.CreateTaskQueueFactory())), config_(CreateVideoSendStreamConfig(&transport_, ssrcs, rtx_ssrcs, payload_type)), bitrate_config_(GetBitrateConfig()), transport_controller_( - time_controller_.GetClock(), - RtpTransportConfig{ - .bitrate_config = bitrate_config_, - .event_log = &event_log_, - .task_queue_factory = time_controller_.GetTaskQueueFactory(), - .trials = field_trials ? field_trials : &field_trials_, - }), + RtpTransportConfig{.env = env_, .bitrate_config = bitrate_config_}), stats_proxy_(time_controller_.GetClock(), config_, VideoEncoderConfig::ContentType::kRealtimeVideo, - field_trials ? *field_trials : field_trials_), + env_.field_trials()), retransmission_rate_limiter_(time_controller_.GetClock(), kRetransmitWindowSizeMs) { transport_controller_.EnsureStarted(); @@ -144,10 +144,10 @@ class RtpVideoSenderTestFixture { config_.rtp, config_.rtcp_report_interval_ms, &transport_, CreateObservers(&encoder_feedback_, &stats_proxy_, &stats_proxy_, &stats_proxy_, frame_count_observer, &stats_proxy_), - &transport_controller_, &event_log_, &retransmission_rate_limiter_, - std::make_unique(time_controller_.GetClock()), - nullptr, CryptoOptions{}, frame_transformer, - field_trials ? *field_trials : field_trials_, + &transport_controller_, &env_.event_log(), + &retransmission_rate_limiter_, + std::make_unique(env_), nullptr, CryptoOptions{}, + frame_transformer, env_.field_trials(), time_controller_.GetTaskQueueFactory()); } @@ -197,7 +197,7 @@ class RtpVideoSenderTestFixture { NiceMock transport_; NiceMock encoder_feedback_; GlobalSimulatedTimeController time_controller_; - RtcEventLogNull event_log_; + Environment env_; VideoSendStream::Config config_; BitrateConstraints bitrate_config_; RtpTransportControllerSend transport_controller_; diff --git a/third_party/libwebrtc/call/version.cc b/third_party/libwebrtc/call/version.cc index 5770253625..85fdf004ea 100644 --- a/third_party/libwebrtc/call/version.cc +++ b/third_party/libwebrtc/call/version.cc @@ -13,7 +13,7 @@ namespace webrtc { // The timestamp is always in UTC. -const char* const kSourceTimestamp = "WebRTC source stamp 2023-12-03T04:02:06"; +const char* const kSourceTimestamp = "WebRTC source stamp 2024-01-21T04:12:31"; void LoadWebRTCVersionInRegister() { // Using volatile to instruct the compiler to not optimize `p` away even diff --git a/third_party/libwebrtc/common_video/h264/h264_common.h b/third_party/libwebrtc/common_video/h264/h264_common.h index 0b1843ee38..1bc9867d3f 100644 --- a/third_party/libwebrtc/common_video/h264/h264_common.h +++ b/third_party/libwebrtc/common_video/h264/h264_common.h @@ -17,6 +17,7 @@ #include #include "rtc_base/buffer.h" +#include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -59,11 +60,11 @@ struct NaluIndex { }; // Returns a vector of the NALU indices in the given buffer. -std::vector FindNaluIndices(const uint8_t* buffer, - size_t buffer_size); +RTC_EXPORT std::vector FindNaluIndices(const uint8_t* buffer, + size_t buffer_size); // Get the NAL type from the header byte immediately following start sequence. -NaluType ParseNaluType(uint8_t data); +RTC_EXPORT NaluType ParseNaluType(uint8_t data); // Methods for parsing and writing RBSP. See section 7.4.1 of the H264 spec. // diff --git a/third_party/libwebrtc/common_video/h264/sps_parser.h b/third_party/libwebrtc/common_video/h264/sps_parser.h index da328b48b0..a69bd19690 100644 --- a/third_party/libwebrtc/common_video/h264/sps_parser.h +++ b/third_party/libwebrtc/common_video/h264/sps_parser.h @@ -13,15 +13,16 @@ #include "absl/types/optional.h" #include "rtc_base/bitstream_reader.h" +#include "rtc_base/system/rtc_export.h" namespace webrtc { // A class for parsing out sequence parameter set (SPS) data from an H264 NALU. -class SpsParser { +class RTC_EXPORT SpsParser { public: // The parsed state of the SPS. Only some select values are stored. // Add more as they are actually needed. - struct SpsState { + struct RTC_EXPORT SpsState { SpsState(); SpsState(const SpsState&); ~SpsState(); diff --git a/third_party/libwebrtc/common_video/h265/h265_bitstream_parser.cc b/third_party/libwebrtc/common_video/h265/h265_bitstream_parser.cc index f8dc242c7d..f270f228c1 100644 --- a/third_party/libwebrtc/common_video/h265/h265_bitstream_parser.cc +++ b/third_party/libwebrtc/common_video/h265/h265_bitstream_parser.cc @@ -12,6 +12,7 @@ #include #include +#include #include #include "common_video/h265/h265_common.h" @@ -129,6 +130,8 @@ H265BitstreamParser::Result H265BitstreamParser::ParseNonParameterSetNalu( uint32_t slice_segment_address_bits = H265::Log2Ceiling(pic_height_in_ctbs_y * pic_width_in_ctbs_y); + TRUE_OR_RETURN(slice_segment_address_bits != + std::numeric_limits::max()); slice_reader.ConsumeBits(slice_segment_address_bits); } diff --git a/third_party/libwebrtc/docs/native-code/development/README.md b/third_party/libwebrtc/docs/native-code/development/README.md index 8a2678e6cf..02d148c7d7 100644 --- a/third_party/libwebrtc/docs/native-code/development/README.md +++ b/third_party/libwebrtc/docs/native-code/development/README.md @@ -98,11 +98,7 @@ configuration untouched (stored in the args.gn file), do: $ gn clean out/Default ``` -To build the fuzzers residing in the [test/fuzzers][fuzzers] directory, use -``` -$ gn gen out/fuzzers --args='use_libfuzzer=true optimize_for_fuzzing=true' -``` -Depending on the fuzzer additional arguments like `is_asan`, `is_msan` or `is_ubsan_security` might be required. +To build the fuzzers residing in the [test/fuzzers][fuzzers-dir] directory, read the instructions at the [fuzzers][fuzzers] page. See the [GN][gn-doc] documentation for all available options. There are also more platform specific tips on the [Android][webrtc-android-development] and @@ -129,6 +125,11 @@ $ autoninja all -C out/Default See [Ninja build rules][ninja-build-rules] to read more about difference between `ninja` and `ninja all`. +To build a particular target (like a fuzzer which is not included in the main target) use + +``` +autoninja -C out/Default h264_depacketizer_fuzzer +``` ## Using Another Build System @@ -288,4 +289,5 @@ Target name `turnserver`. Used for unit tests. [rfc-5766]: https://tools.ietf.org/html/rfc5766 [m80-log]: https://webrtc.googlesource.com/src/+log/branch-heads/3987 [m80]: https://webrtc.googlesource.com/src/+/branch-heads/3987 -[fuzzers]: https://webrtc.googlesource.com/src/+/main/test/fuzzers/ +[fuzzers-dir]: https://webrtc.googlesource.com/src/+/main/test/fuzzers/ +[fuzzers]: https://webrtc.googlesource.com/src/+/main/docs/native-code/development/fuzzers/ diff --git a/third_party/libwebrtc/docs/native-code/development/fuzzers/README.md b/third_party/libwebrtc/docs/native-code/development/fuzzers/README.md new file mode 100644 index 0000000000..cac77cdc07 --- /dev/null +++ b/third_party/libwebrtc/docs/native-code/development/fuzzers/README.md @@ -0,0 +1,70 @@ +# Fuzzing in WebRTC + +## Intro +WebRTC currently uses libfuzzer for fuzz testing however FuzzTest is a new approach which we have not yet looked into but we will in the future. + +Before continuing, read the [libfuzzer][libfuzzer-getting-started] and [FuzzTest][fuzztest-getting-started] getting started docs to get familar. + +## Compiling locally +To build the fuzzers residing in the [test/fuzzers][fuzzers] directory, use +``` +$ gn gen out/fuzzers --args='use_libfuzzer=true optimize_for_fuzzing=true' +``` +Depending on the fuzzer additional arguments like `is_asan`, `is_msan` or `is_ubsan_security` might be required. + +See the [GN][gn-doc] documentation for all available options. There are also more +platform specific tips on the [Android][webrtc-android-development] and +[iOS][webrtc-ios-development] instructions. + +## Add new fuzzers +Create a new `.cc` file in the [test/fuzzers][fuzzers] directory, use existing files as a guide. + +Add a new `webrtc_fuzzers_test` build rule in the [test/fuzzers/BUILD.gn][BUILD.gn], use existing rules as a guide. + +Ensure it compiles and executes locally then add it to a gerrit CL and upload it for review, e.g. + +``` +$ autoninja -C out/fuzzers test/fuzzers:h264_depacketizer_fuzzer +``` + +It can then be executed like so: +``` +$ out/fuzzers/bin/run_h264_depacketizer_fuzzer +``` + +## Running fuzzers automatically +All fuzzer tests in the [test/fuzzers/BUILD.gn][BUILD.gn] file are compiled per CL on the [libfuzzer bot][libfuzzer-bot]. +This is only to verify that it compiles, this bot does not do any fuzz testing. + +When WebRTC is [rolled][webrtc-autoroller] into to Chromium, the libfuzz bots in the [chromium.fuzz][chromium-fuzz] will compile it, zip it and then upload to https://clusterfuzz.com for execution. + +You can verify that the fuzz test is being executed by: + - Navigate to a bot in the [chromium.fuzz][chromium-fuzz] libfuzzer waterfall, e.g. [ Libfuzzer Upload Linux ASan bot/linux bot][linux-bot]. + - Click on the latest `build#` link. + - Search for `//third_party/webrtc/test/fuzzers` in the `raw_io.output_text_refs_` file in the `calculate_all_fuzzers` step. + - Verify that the new fuzzer (as it's named in the `webrtc_fuzzers_test` build rule) is present. + - Also verify that it's _NOT_ in the `no_clusterfuzz` file in the `calculate_no_clusterfuzz` step. If it is, file a bug at https://bugs.webrtc.org. + +Bugs are filed automatically in https://crbug.com in the blink > WebRTC component and assigned based on [test/fuzzers/OWNERS][OWNERS] file or the commit history. + +If you are a non-googler, you can only view data from https://clusterfuzz.com if your account is CC'ed on the reported bug. + +## Additional reading + +[Libfuzzer in Chromium][libfuzzer-chromium] + + +[libfuzzer-chromium]: https://chromium.googlesource.com/chromium/src/+/HEAD/testing/libfuzzer/README.md +[libfuzzer-bot]: https://ci.chromium.org/ui/p/webrtc/builders/luci.webrtc.ci/Linux64%20Release%20%28Libfuzzer%29 +[fuzzers]: https://webrtc.googlesource.com/src/+/main/test/fuzzers/ +[OWNERS]: https://webrtc.googlesource.com/src/+/main/test/fuzzers/OWNERS +[BUILD.gn]: https://webrtc.googlesource.com/src/+/main/test/fuzzers/BUILD.gn +[gn]: https://gn.googlesource.com/gn/+/main/README.md +[gn-doc]: https://gn.googlesource.com/gn/+/main/docs/reference.md#IDE-options +[webrtc-android-development]: https://webrtc.googlesource.com/src/+/main/docs/native-code/android/ +[webrtc-ios-development]: https://webrtc.googlesource.com/src/+/main/docs/native-code/ios/ +[chromium-fuzz]: https://ci.chromium.org/p/chromium/g/chromium.fuzz/console +[linux-bot]: https://ci.chromium.org/ui/p/chromium/builders/ci/Libfuzzer%20Upload%20Linux%20ASan/ +[libfuzzer-getting-started]: https://chromium.googlesource.com/chromium/src/+/main/testing/libfuzzer/getting_started_with_libfuzzer.md +[fuzztest-getting-started]: https://chromium.googlesource.com/chromium/src/+/main/testing/libfuzzer/getting_started.md +[webrtc-autoroller]: https://autoroll.skia.org/r/webrtc-chromium-autoroll diff --git a/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.cc b/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.cc index 40af78cdac..0e895c520b 100644 --- a/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.cc +++ b/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.cc @@ -154,8 +154,7 @@ void AndroidCallClient::CreatePeerConnectionFactory() { pcf_deps.worker_thread = worker_thread_.get(); pcf_deps.signaling_thread = signaling_thread_.get(); pcf_deps.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory(); - pcf_deps.event_log_factory = std::make_unique( - pcf_deps.task_queue_factory.get()); + pcf_deps.event_log_factory = std::make_unique(); pcf_deps.video_encoder_factory = std::make_unique(); diff --git a/third_party/libwebrtc/examples/androidvoip/BUILD.gn b/third_party/libwebrtc/examples/androidvoip/BUILD.gn index cea05ea128..d390815406 100644 --- a/third_party/libwebrtc/examples/androidvoip/BUILD.gn +++ b/third_party/libwebrtc/examples/androidvoip/BUILD.gn @@ -71,7 +71,7 @@ if (is_android) { "//api/task_queue:default_task_queue_factory", "//api/voip:voip_api", "//api/voip:voip_engine_factory", - "//rtc_base/third_party/sigslot:sigslot", + "//rtc_base/network:received_packet", "//sdk/android:native_api_audio_device_module", "//sdk/android:native_api_base", "//sdk/android:native_api_jni", diff --git a/third_party/libwebrtc/examples/androidvoip/jni/android_voip_client.cc b/third_party/libwebrtc/examples/androidvoip/jni/android_voip_client.cc index 8a0a3badb9..69327990e0 100644 --- a/third_party/libwebrtc/examples/androidvoip/jni/android_voip_client.cc +++ b/third_party/libwebrtc/examples/androidvoip/jni/android_voip_client.cc @@ -313,8 +313,10 @@ void AndroidVoipClient::StartSession(JNIEnv* env) { /*isSuccessful=*/false); return; } - rtp_socket_->SignalReadPacket.connect( - this, &AndroidVoipClient::OnSignalReadRTPPacket); + rtp_socket_->RegisterReceivedPacketCallback( + [&](rtc::AsyncPacketSocket* socket, const rtc::ReceivedPacket& packet) { + OnSignalReadRTPPacket(socket, packet); + }); rtcp_socket_.reset(rtc::AsyncUDPSocket::Create(voip_thread_->socketserver(), rtcp_local_address_)); @@ -324,8 +326,10 @@ void AndroidVoipClient::StartSession(JNIEnv* env) { /*isSuccessful=*/false); return; } - rtcp_socket_->SignalReadPacket.connect( - this, &AndroidVoipClient::OnSignalReadRTCPPacket); + rtcp_socket_->RegisterReceivedPacketCallback( + [&](rtc::AsyncPacketSocket* socket, const rtc::ReceivedPacket& packet) { + OnSignalReadRTCPPacket(socket, packet); + }); Java_VoipClient_onStartSessionCompleted(env_, j_voip_client_, /*isSuccessful=*/true); } @@ -467,12 +471,11 @@ void AndroidVoipClient::ReadRTPPacket(const std::vector& packet_copy) { RTC_CHECK(result == webrtc::VoipResult::kOk); } -void AndroidVoipClient::OnSignalReadRTPPacket(rtc::AsyncPacketSocket* socket, - const char* rtp_packet, - size_t size, - const rtc::SocketAddress& addr, - const int64_t& timestamp) { - std::vector packet_copy(rtp_packet, rtp_packet + size); +void AndroidVoipClient::OnSignalReadRTPPacket( + rtc::AsyncPacketSocket* socket, + const rtc::ReceivedPacket& packet) { + std::vector packet_copy(packet.payload().begin(), + packet.payload().end()); voip_thread_->PostTask([this, packet_copy = std::move(packet_copy)] { ReadRTPPacket(packet_copy); }); @@ -492,12 +495,11 @@ void AndroidVoipClient::ReadRTCPPacket( RTC_CHECK(result == webrtc::VoipResult::kOk); } -void AndroidVoipClient::OnSignalReadRTCPPacket(rtc::AsyncPacketSocket* socket, - const char* rtcp_packet, - size_t size, - const rtc::SocketAddress& addr, - const int64_t& timestamp) { - std::vector packet_copy(rtcp_packet, rtcp_packet + size); +void AndroidVoipClient::OnSignalReadRTCPPacket( + rtc::AsyncPacketSocket* socket, + const rtc::ReceivedPacket& packet) { + std::vector packet_copy(packet.payload().begin(), + packet.payload().end()); voip_thread_->PostTask([this, packet_copy = std::move(packet_copy)] { ReadRTCPPacket(packet_copy); }); diff --git a/third_party/libwebrtc/examples/androidvoip/jni/android_voip_client.h b/third_party/libwebrtc/examples/androidvoip/jni/android_voip_client.h index e2f1c64590..1d9a13b29d 100644 --- a/third_party/libwebrtc/examples/androidvoip/jni/android_voip_client.h +++ b/third_party/libwebrtc/examples/androidvoip/jni/android_voip_client.h @@ -23,8 +23,8 @@ #include "api/voip/voip_engine.h" #include "rtc_base/async_packet_socket.h" #include "rtc_base/async_udp_socket.h" +#include "rtc_base/network/received_packet.h" #include "rtc_base/socket_address.h" -#include "rtc_base/third_party/sigslot/sigslot.h" #include "rtc_base/thread.h" #include "sdk/android/native_api/jni/scoped_java_ref.h" @@ -40,8 +40,7 @@ namespace webrtc_examples { // with consistent thread usage requirement with ProcessThread used // within VoipEngine, as well as providing asynchronicity to the // caller. AndroidVoipClient is meant to be used by Java through JNI. -class AndroidVoipClient : public webrtc::Transport, - public sigslot::has_slots<> { +class AndroidVoipClient : public webrtc::Transport { public: // Returns a pointer to an AndroidVoipClient object. Clients should // use this factory method to create AndroidVoipClient objects. The @@ -122,17 +121,10 @@ class AndroidVoipClient : public webrtc::Transport, const webrtc::PacketOptions& options) override; bool SendRtcp(rtc::ArrayView packet) override; - // Slots for sockets to connect to. void OnSignalReadRTPPacket(rtc::AsyncPacketSocket* socket, - const char* rtp_packet, - size_t size, - const rtc::SocketAddress& addr, - const int64_t& timestamp); + const rtc::ReceivedPacket& packet); void OnSignalReadRTCPPacket(rtc::AsyncPacketSocket* socket, - const char* rtcp_packet, - size_t size, - const rtc::SocketAddress& addr, - const int64_t& timestamp); + const rtc::ReceivedPacket& packet); private: AndroidVoipClient(JNIEnv* env, diff --git a/third_party/libwebrtc/examples/objcnativeapi/objc/objc_call_client.mm b/third_party/libwebrtc/examples/objcnativeapi/objc/objc_call_client.mm index 996c6a9c7f..2601beed71 100644 --- a/third_party/libwebrtc/examples/objcnativeapi/objc/objc_call_client.mm +++ b/third_party/libwebrtc/examples/objcnativeapi/objc/objc_call_client.mm @@ -126,8 +126,7 @@ void ObjCCallClient::CreatePeerConnectionFactory() { [[RTC_OBJC_TYPE(RTCDefaultVideoDecoderFactory) alloc] init]); dependencies.audio_processing = webrtc::AudioProcessingBuilder().Create(); webrtc::EnableMedia(dependencies); - dependencies.event_log_factory = - std::make_unique(dependencies.task_queue_factory.get()); + dependencies.event_log_factory = std::make_unique(); pcf_ = webrtc::CreateModularPeerConnectionFactory(std::move(dependencies)); RTC_LOG(LS_INFO) << "PeerConnectionFactory created: " << pcf_.get(); } diff --git a/third_party/libwebrtc/experiments/field_trials.py b/third_party/libwebrtc/experiments/field_trials.py index 567cafc058..4aa9bcbe4b 100755 --- a/third_party/libwebrtc/experiments/field_trials.py +++ b/third_party/libwebrtc/experiments/field_trials.py @@ -50,6 +50,9 @@ ACTIVE_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([ FieldTrial('WebRTC-Audio-OpusSetSignalVoiceWithDtx', 'webrtc:4559', date(2024, 4, 1)), + FieldTrial('WebRTC-AV1-OverridePriorityBitrate', + 'webrtc:15763', + date(2024, 4, 1)), FieldTrial('WebRTC-Av1-GetEncoderInfoOverride', 'webrtc:14931', date(2024, 4, 1)), @@ -125,6 +128,9 @@ ACTIVE_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([ FieldTrial('WebRTC-VideoEncoderSettings', 'chromium:1406331', date(2024, 4, 1)), + FieldTrial('WebRTC-ZeroHertzQueueOverload', + 'webrtc:332381', + date(2024, 7, 1)), # keep-sorted end ]) # yapf: disable @@ -565,9 +571,6 @@ POLICY_EXEMPT_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([ FieldTrial('WebRTC-DependencyDescriptorAdvertised', 'webrtc:10342', date(2024, 4, 1)), - FieldTrial('WebRTC-DisablePacerEmergencyStop', - '', - date(2024, 4, 1)), FieldTrial('WebRTC-DisableUlpFecExperiment', '', date(2024, 4, 1)), diff --git a/third_party/libwebrtc/infra/OWNERS b/third_party/libwebrtc/infra/OWNERS index eae8171db5..4a9e6f5856 100644 --- a/third_party/libwebrtc/infra/OWNERS +++ b/third_party/libwebrtc/infra/OWNERS @@ -3,4 +3,3 @@ jleconte@webrtc.org titovartem@webrtc.org jansson@webrtc.org terelius@webrtc.org -landrey@webrtc.org diff --git a/third_party/libwebrtc/infra/config/config.star b/third_party/libwebrtc/infra/config/config.star index eecac11c94..94d2d9ccc6 100755 --- a/third_party/libwebrtc/infra/config/config.star +++ b/third_party/libwebrtc/infra/config/config.star @@ -800,6 +800,8 @@ ci_builder("Win64 ASan", "Win Clang|x64|asan") try_builder("win_asan") ci_builder("Win (more configs)", "Win Clang|x86|more") try_builder("win_x86_more_configs") +try_builder("win11_release", cq = None) +try_builder("win11_debug", cq = None) chromium_try_builder("win_chromium_compile") chromium_try_builder("win_chromium_compile_dbg") diff --git a/third_party/libwebrtc/infra/config/cr-buildbucket.cfg b/third_party/libwebrtc/infra/config/cr-buildbucket.cfg index cc36dc359c..039c580a34 100644 --- a/third_party/libwebrtc/infra/config/cr-buildbucket.cfg +++ b/third_party/libwebrtc/infra/config/cr-buildbucket.cfg @@ -4987,6 +4987,100 @@ buckets { } } } + builders { + name: "win11_debug" + swarming_host: "chromium-swarm.appspot.com" + swarming_tags: "vpython:native-python-wrapper" + dimensions: "builderless:1" + dimensions: "cpu:x86-64" + dimensions: "os:Windows" + dimensions: "pool:luci.webrtc.try" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/main" + cmd: "luciexe" + } + properties: + '{' + ' "$build/reclient": {' + ' "instance": "rbe-webrtc-untrusted",' + ' "metrics_project": "chromium-reclient-metrics"' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "tryserver.webrtc",' + ' "recipe": "webrtc/standalone"' + '}' + priority: 30 + execution_timeout_secs: 7200 + build_numbers: YES + service_account: "webrtc-try-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "webrtc-ci" + dataset: "resultdb" + table: "try_test_results" + test_results {} + } + } + } + builders { + name: "win11_release" + swarming_host: "chromium-swarm.appspot.com" + swarming_tags: "vpython:native-python-wrapper" + dimensions: "builderless:1" + dimensions: "cpu:x86-64" + dimensions: "os:Windows" + dimensions: "pool:luci.webrtc.try" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/main" + cmd: "luciexe" + } + properties: + '{' + ' "$build/reclient": {' + ' "instance": "rbe-webrtc-untrusted",' + ' "metrics_project": "chromium-reclient-metrics"' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "tryserver.webrtc",' + ' "recipe": "webrtc/standalone"' + '}' + priority: 30 + execution_timeout_secs: 7200 + build_numbers: YES + service_account: "webrtc-try-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "webrtc-ci" + dataset: "resultdb" + table: "try_test_results" + test_results {} + } + } + } builders { name: "win_asan" swarming_host: "chromium-swarm.appspot.com" diff --git a/third_party/libwebrtc/infra/config/luci-milo.cfg b/third_party/libwebrtc/infra/config/luci-milo.cfg index cca46cd157..3f3a18832a 100644 --- a/third_party/libwebrtc/infra/config/luci-milo.cfg +++ b/third_party/libwebrtc/infra/config/luci-milo.cfg @@ -593,6 +593,12 @@ consoles { builders { name: "buildbucket/luci.webrtc.try/win_x86_more_configs" } + builders { + name: "buildbucket/luci.webrtc.try/win11_release" + } + builders { + name: "buildbucket/luci.webrtc.try/win11_debug" + } builders { name: "buildbucket/luci.webrtc.try/win_chromium_compile" } diff --git a/third_party/libwebrtc/infra/config/luci-notify.cfg b/third_party/libwebrtc/infra/config/luci-notify.cfg index 8cae9b3f93..129d0e4268 100644 --- a/third_party/libwebrtc/infra/config/luci-notify.cfg +++ b/third_party/libwebrtc/infra/config/luci-notify.cfg @@ -2025,6 +2025,32 @@ notifiers { name: "webrtc_linux_chromium" } } +notifiers { + notifications { + on_new_status: INFRA_FAILURE + email { + recipients: "webrtc-troopers-robots@google.com" + } + template: "infra_failure" + } + builders { + bucket: "try" + name: "win11_debug" + } +} +notifiers { + notifications { + on_new_status: INFRA_FAILURE + email { + recipients: "webrtc-troopers-robots@google.com" + } + template: "infra_failure" + } + builders { + bucket: "try" + name: "win11_release" + } +} notifiers { notifications { on_new_status: INFRA_FAILURE diff --git a/third_party/libwebrtc/infra/specs/client.webrtc.json b/third_party/libwebrtc/infra/specs/client.webrtc.json index 6f8bfb5ba5..4d53f6de9d 100644 --- a/third_party/libwebrtc/infra/specs/client.webrtc.json +++ b/third_party/libwebrtc/infra/specs/client.webrtc.json @@ -1864,7 +1864,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -1888,7 +1888,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -1912,7 +1912,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -1936,7 +1936,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -1960,7 +1960,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -1984,7 +1984,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -2008,7 +2008,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2033,7 +2033,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -2057,7 +2057,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2082,7 +2082,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -2106,7 +2106,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -2127,7 +2127,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2149,7 +2149,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -2166,7 +2166,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -2183,7 +2183,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -2200,7 +2200,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -2217,7 +2217,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -2235,7 +2235,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -2253,7 +2253,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2271,7 +2271,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -2288,7 +2288,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -2305,7 +2305,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -2322,7 +2322,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -2340,7 +2340,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -2357,7 +2357,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -2374,7 +2374,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2392,7 +2392,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -2409,7 +2409,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -2426,7 +2426,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -2443,7 +2443,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2461,7 +2461,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -2478,7 +2478,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -2832,7 +2832,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -2849,7 +2849,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -2866,7 +2866,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -2883,7 +2883,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -2900,7 +2900,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -2918,7 +2918,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -2936,7 +2936,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2954,7 +2954,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -2971,7 +2971,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -2988,7 +2988,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -3005,7 +3005,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -3023,7 +3023,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -3040,7 +3040,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3058,7 +3058,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -3075,7 +3075,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -3092,7 +3092,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -3109,7 +3109,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3127,7 +3127,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -3144,7 +3144,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -3165,7 +3165,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -3182,7 +3182,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -3199,7 +3199,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -3216,7 +3216,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -3233,7 +3233,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -3251,7 +3251,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -3269,7 +3269,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3287,7 +3287,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -3304,7 +3304,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -3321,7 +3321,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -3338,7 +3338,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -3356,7 +3356,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -3373,7 +3373,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -3390,7 +3390,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3408,7 +3408,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -3425,7 +3425,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -3442,7 +3442,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -3459,7 +3459,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3477,7 +3477,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -3494,7 +3494,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -3515,7 +3515,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -3532,7 +3532,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -3549,7 +3549,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -3566,7 +3566,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -3583,7 +3583,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -3601,7 +3601,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -3619,7 +3619,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3637,7 +3637,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -3654,7 +3654,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -3671,7 +3671,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -3688,7 +3688,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -3706,7 +3706,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -3723,7 +3723,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -3740,7 +3740,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3758,7 +3758,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -3775,7 +3775,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -3792,7 +3792,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -3809,7 +3809,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3827,7 +3827,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -3844,7 +3844,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -3865,7 +3865,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -3882,7 +3882,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -3899,7 +3899,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -3916,7 +3916,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -3933,7 +3933,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -3951,7 +3951,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -3969,7 +3969,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -3987,7 +3987,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -4004,7 +4004,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -4021,7 +4021,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -4038,7 +4038,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -4056,7 +4056,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -4073,7 +4073,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -4091,7 +4091,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -4108,7 +4108,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -4125,7 +4125,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -4142,7 +4142,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -4160,7 +4160,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -4177,7 +4177,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -4199,7 +4199,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -4216,7 +4216,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -4233,7 +4233,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -4250,7 +4250,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -4267,7 +4267,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -4285,7 +4285,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -4303,7 +4303,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -4321,7 +4321,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -4338,7 +4338,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -4355,7 +4355,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -4372,7 +4372,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -4390,7 +4390,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -4407,7 +4407,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -4425,7 +4425,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -4442,7 +4442,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -4459,7 +4459,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -4476,7 +4476,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -4494,7 +4494,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -4511,7 +4511,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -4534,7 +4534,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -4551,7 +4551,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -4568,7 +4568,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -4585,7 +4585,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -4602,7 +4602,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -4620,7 +4620,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -4638,7 +4638,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -4656,7 +4656,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -4673,7 +4673,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -4690,7 +4690,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -4707,7 +4707,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -4725,7 +4725,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -4742,7 +4742,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -4759,7 +4759,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -4777,7 +4777,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -4794,7 +4794,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -4811,7 +4811,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -4828,7 +4828,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -4846,7 +4846,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -4863,7 +4863,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -4885,7 +4885,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -4902,7 +4902,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -4919,7 +4919,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -4936,7 +4936,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -4953,7 +4953,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -4971,7 +4971,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -4989,7 +4989,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -5007,7 +5007,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -5024,7 +5024,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -5041,7 +5041,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -5058,7 +5058,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -5076,7 +5076,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -5093,7 +5093,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -5110,7 +5110,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -5128,7 +5128,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -5145,7 +5145,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -5162,30 +5162,12 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "result_format": "json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Ubuntu-18.04", - "pool": "WebRTC-baremetal" - } - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, { "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5197,7 +5179,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -5215,7 +5197,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -5232,7 +5214,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -6226,24 +6208,6 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "result_format": "json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Mac-12", - "pool": "WebRTC-baremetal" - } - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, { "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -7934,24 +7898,6 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "result_format": "json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Windows-10-19045", - "pool": "WebRTC-baremetal" - } - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, { "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -8011,20 +7957,20 @@ { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "apprtcmobile_tests iPhone X 14.5", + "name": "apprtcmobile_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8034,29 +7980,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -8067,9 +8012,9 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -8084,17 +8029,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -8113,18 +8057,18 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "apprtcmobile_tests iPhone X 16.2", + "name": "apprtcmobile_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8134,46 +8078,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "audio_decoder_unittests iPhone X 14.5", + "name": "audio_decoder_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8183,29 +8126,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -8217,7 +8159,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -8232,17 +8174,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -8261,17 +8202,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "audio_decoder_unittests iPhone X 16.2", + "name": "audio_decoder_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8281,46 +8222,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "common_audio_unittests iPhone X 14.5", + "name": "common_audio_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8330,29 +8270,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -8364,7 +8303,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -8379,17 +8318,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -8408,17 +8346,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "common_audio_unittests iPhone X 16.2", + "name": "common_audio_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8428,46 +8366,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "common_video_unittests iPhone X 14.5", + "name": "common_video_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8477,29 +8414,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -8511,7 +8447,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -8526,17 +8462,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -8555,17 +8490,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "common_video_unittests iPhone X 16.2", + "name": "common_video_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8575,46 +8510,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "dcsctp_unittests iPhone X 14.5", + "name": "dcsctp_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8624,29 +8558,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -8658,7 +8591,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -8673,17 +8606,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -8702,17 +8634,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "dcsctp_unittests iPhone X 16.2", + "name": "dcsctp_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8722,46 +8654,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "modules_tests iPhone X 14.5", + "name": "modules_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8771,22 +8702,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -8794,7 +8724,7 @@ }, "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -8806,7 +8736,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -8821,17 +8751,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -8851,17 +8780,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "modules_tests iPhone X 16.2", + "name": "modules_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8871,22 +8800,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -8894,24 +8822,24 @@ }, "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "modules_unittests iPhone X 14.5", + "name": "modules_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -8921,23 +8849,22 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -8945,7 +8872,7 @@ }, "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -8957,7 +8884,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -8972,18 +8899,17 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -9003,17 +8929,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "modules_unittests iPhone X 16.2", + "name": "modules_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9023,23 +8949,22 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -9047,24 +8972,24 @@ }, "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_media_unittests iPhone X 14.5", + "name": "rtc_media_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9074,29 +8999,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -9108,7 +9032,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -9123,17 +9047,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -9152,17 +9075,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_media_unittests iPhone X 16.2", + "name": "rtc_media_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9172,46 +9095,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_pc_unittests iPhone X 14.5", + "name": "rtc_pc_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9221,29 +9143,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -9255,7 +9176,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -9270,17 +9191,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -9299,17 +9219,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_pc_unittests iPhone X 16.2", + "name": "rtc_pc_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9319,46 +9239,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_stats_unittests iPhone X 14.5", + "name": "rtc_stats_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9368,29 +9287,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -9402,7 +9320,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -9417,17 +9335,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -9446,17 +9363,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_stats_unittests iPhone X 16.2", + "name": "rtc_stats_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9466,46 +9383,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_unittests iPhone X 14.5", + "name": "rtc_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9515,22 +9431,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -9538,7 +9453,7 @@ }, "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -9550,7 +9465,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -9565,17 +9480,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -9595,17 +9509,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_unittests iPhone X 16.2", + "name": "rtc_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9615,22 +9529,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -9638,25 +9551,25 @@ }, "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "sdk_framework_unittests iPhone X 14.5", + "name": "sdk_framework_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9666,29 +9579,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -9699,9 +9611,9 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -9716,17 +9628,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -9745,18 +9656,18 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "sdk_framework_unittests iPhone X 16.2", + "name": "sdk_framework_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9766,47 +9677,46 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "sdk_unittests iPhone X 14.5", + "name": "sdk_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9816,29 +9726,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -9849,9 +9758,9 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -9866,17 +9775,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -9895,18 +9803,18 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "sdk_unittests iPhone X 16.2", + "name": "sdk_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9916,46 +9824,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "svc_tests iPhone X 14.5", + "name": "svc_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -9965,23 +9872,22 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -9989,7 +9895,7 @@ }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -10001,7 +9907,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -10016,18 +9922,17 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -10047,17 +9952,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "svc_tests iPhone X 16.2", + "name": "svc_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10067,23 +9972,22 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -10091,24 +9995,24 @@ }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "system_wrappers_unittests iPhone X 14.5", + "name": "system_wrappers_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10118,29 +10022,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -10152,7 +10055,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -10167,17 +10070,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -10196,17 +10098,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "system_wrappers_unittests iPhone X 16.2", + "name": "system_wrappers_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10216,46 +10118,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "test_support_unittests iPhone X 14.5", + "name": "test_support_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10265,29 +10166,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -10299,7 +10199,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -10314,17 +10214,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -10343,17 +10242,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "test_support_unittests iPhone X 16.2", + "name": "test_support_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10363,46 +10262,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "tools_unittests iPhone X 14.5", + "name": "tools_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10412,29 +10310,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -10446,7 +10343,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -10461,17 +10358,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -10490,17 +10386,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "tools_unittests iPhone X 16.2", + "name": "tools_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10510,46 +10406,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "video_capture_tests iPhone X 14.5", + "name": "video_engine_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10559,169 +10454,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", - "variant_id": "iPhone X 14.5" - }, - { - "args": [ - "--platform", - "iPhone X", - "--version", - "15.5", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xctest", - "--xcode-build-version", - "14c18" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests iPhone X 15.5", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" - } - ], - "dimensions": { - "caches": "xcode_ios_14c18", - "cpu": "x86-64", - "os": "Mac-12" - }, - "named_caches": [ - { - "name": "xcode_ios_14c18", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_15_5", - "path": "Runtime-ios-15.5" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", - "variant_id": "iPhone X 15.5" - }, - { - "args": [ - "--platform", - "iPhone X", - "--version", - "16.2", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xctest", - "--xcode-build-version", - "14c18" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests iPhone X 16.2", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" - } - ], - "dimensions": { - "caches": "xcode_ios_14c18", - "cpu": "x86-64", - "os": "Mac-12" - }, - "named_caches": [ - { - "name": "xcode_ios_14c18", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", - "variant_id": "iPhone X 16.2" - }, - { - "args": [ - "--platform", - "iPhone X", - "--version", - "14.5", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xctest", - "--xcode-build-version", - "13c100" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_engine_tests iPhone X 14.5", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" - } - ], - "dimensions": { - "caches": "xcode_ios_13c100", - "cpu": "x86-64", - "os": "Mac-12" - }, - "named_caches": [ - { - "name": "xcode_ios_13c100", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -10729,7 +10476,7 @@ }, "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -10741,7 +10488,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -10756,17 +10503,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -10786,17 +10532,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "video_engine_tests iPhone X 16.2", + "name": "video_engine_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10806,22 +10552,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -10829,24 +10574,24 @@ }, "test": "video_engine_tests", "test_id_prefix": "ninja://:video_engine_tests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "voip_unittests iPhone X 14.5", + "name": "voip_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10856,29 +10601,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -10890,7 +10634,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -10905,17 +10649,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -10934,17 +10677,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "voip_unittests iPhone X 16.2", + "name": "voip_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -10954,46 +10697,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "voip_unittests", "test_id_prefix": "ninja://:voip_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "webrtc_nonparallel_tests iPhone X 14.5", + "name": "webrtc_nonparallel_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -11003,29 +10745,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -11037,7 +10778,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -11052,17 +10793,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -11081,17 +10821,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "webrtc_nonparallel_tests iPhone X 16.2", + "name": "webrtc_nonparallel_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -11101,29 +10841,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" } ] }, diff --git a/third_party/libwebrtc/infra/specs/internal.client.webrtc.json b/third_party/libwebrtc/infra/specs/internal.client.webrtc.json index 59547fc132..b6dbd5c2c3 100644 --- a/third_party/libwebrtc/infra/specs/internal.client.webrtc.json +++ b/third_party/libwebrtc/infra/specs/internal.client.webrtc.json @@ -24,7 +24,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -64,7 +64,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -105,7 +105,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -148,7 +148,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -189,7 +189,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -229,7 +229,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -269,7 +269,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -309,7 +309,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -349,7 +349,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -368,46 +368,6 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "args": [ - "--xctest", - "--xcode-build-version", - "15a507", - "--out-dir", - "${ISOLATED_OUTDIR}" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" - } - ], - "dimensions": { - "device_status": "available", - "os": "iOS-16.6", - "pool": "chrome.tests" - }, - "named_caches": [ - { - "name": "xcode_ios_15a507", - "path": "Xcode.app" - } - ], - "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, { "args": [ "--xctest", @@ -429,7 +389,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -480,7 +440,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -529,7 +489,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -569,7 +529,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -610,7 +570,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -653,7 +613,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -694,7 +654,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -734,7 +694,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -774,7 +734,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -814,7 +774,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -854,7 +814,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { @@ -873,46 +833,6 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "args": [ - "--xctest", - "--xcode-build-version", - "15a507", - "--out-dir", - "${ISOLATED_OUTDIR}" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" - } - ], - "dimensions": { - "device_status": "available", - "os": "iOS-16.6", - "pool": "chrome.tests" - }, - "named_caches": [ - { - "name": "xcode_ios_15a507", - "path": "Xcode.app" - } - ], - "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, { "args": [ "--xctest", @@ -934,7 +854,7 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { diff --git a/third_party/libwebrtc/infra/specs/mixins.pyl b/third_party/libwebrtc/infra/specs/mixins.pyl index e436846ef0..8520002df6 100644 --- a/third_party/libwebrtc/infra/specs/mixins.pyl +++ b/third_party/libwebrtc/infra/specs/mixins.pyl @@ -18,20 +18,6 @@ } } }, - 'baremetal-pool': { - 'swarming': { - 'dimensions': { - 'pool': 'WebRTC-baremetal' - } - } - }, - 'baremetal-try-pool': { - 'swarming': { - 'dimensions': { - 'pool': 'WebRTC-baremetal-try' - } - } - }, 'chrome-tester-service-account': { 'swarming': { 'service_account': @@ -92,27 +78,27 @@ } } }, - 'ios_runtime_cache_14_5': { + 'ios_runtime_cache_15_5': { 'swarming': { 'named_caches': [{ - 'name': 'runtime_ios_14_5', - 'path': 'Runtime-ios-14.5' + 'name': 'runtime_ios_15_5', + 'path': 'Runtime-ios-15.5' }] } }, - 'ios_runtime_cache_15_5': { + 'ios_runtime_cache_16_4': { 'swarming': { 'named_caches': [{ - 'name': 'runtime_ios_15_5', - 'path': 'Runtime-ios-15.5' + 'name': 'runtime_ios_16_4', + 'path': 'Runtime-ios-16.4' }] } }, - 'ios_runtime_cache_16_2': { + 'ios_runtime_cache_17_0': { 'swarming': { 'named_caches': [{ - 'name': 'runtime_ios_16_2', - 'path': 'Runtime-ios-16.2' + 'name': 'runtime_ios_17_0', + 'path': 'Runtime-ios-17.0' }] } }, @@ -168,6 +154,14 @@ } } }, + 'mac_13_x64': { + 'swarming': { + 'dimensions': { + 'cpu': 'x86-64', + 'os': 'Mac-13' + } + } + }, 'mac_toolchain': { 'swarming': { 'cipd_packages': [{ @@ -176,7 +170,7 @@ 'location': '.', 'revision': - 'git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce' + 'git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0' }] } }, @@ -299,23 +293,18 @@ } } }, - 'x86-64': { + 'win11': { 'swarming': { 'dimensions': { - 'cpu': 'x86-64' + 'os': 'Windows-11-22000' } } }, - 'xcode_13_main': { - 'args': ['--xcode-build-version', '13c100'], + 'x86-64': { 'swarming': { 'dimensions': { - 'caches': 'xcode_ios_13c100' - }, - 'named_caches': [{ - 'name': 'xcode_ios_13c100', - 'path': 'Xcode.app' - }] + 'cpu': 'x86-64' + } } }, 'xcode_14_main': { @@ -339,7 +328,7 @@ }] } }, - 'xcode_parallelization': { - 'args': ['--xcode-parallelization'] + 'xcodebuild_sim_runner': { + 'args': ['--xcodebuild-sim-runner'] } } diff --git a/third_party/libwebrtc/infra/specs/mixins_webrtc.pyl b/third_party/libwebrtc/infra/specs/mixins_webrtc.pyl index 443a4450eb..cd83ad2d9b 100644 --- a/third_party/libwebrtc/infra/specs/mixins_webrtc.pyl +++ b/third_party/libwebrtc/infra/specs/mixins_webrtc.pyl @@ -14,20 +14,6 @@ }, }, }, - 'baremetal-pool': { - 'swarming': { - 'dimensions': { - 'pool': 'WebRTC-baremetal', - }, - }, - }, - 'baremetal-try-pool': { - 'swarming': { - 'dimensions': { - 'pool': 'WebRTC-baremetal-try', - }, - }, - }, 'cores-12': { 'swarming': { 'dimensions': { @@ -72,22 +58,6 @@ }, }, }, - 'ios_runtime_cache_14_5': { - 'swarming': { - 'named_caches': [{ - 'name': 'runtime_ios_14_5', - 'path': 'Runtime-ios-14.5' - }] - } - }, - 'ios_runtime_cache_16_2': { - 'swarming': { - 'named_caches': [{ - 'name': 'runtime_ios_16_2', - 'path': 'Runtime-ios-16.2' - }] - } - }, 'limited-capacity': { # Sometimes there are multiple tests that can be run only on one machine. # We need to increase timeouts so the tests dont expire before the machine is freed. @@ -221,18 +191,6 @@ '--xctest', ], }, - 'xcode_13_main': { - 'args': ['--xcode-build-version', '13c100'], - 'swarming': { - 'dimensions': { - 'caches': 'xcode_ios_13c100', - }, - 'named_caches': [{ - 'name': 'xcode_ios_13c100', - 'path': 'Xcode.app' - }] - } - }, 'xcode_14_main': { 'args': ['--xcode-build-version', '14c18'], 'swarming': { diff --git a/third_party/libwebrtc/infra/specs/test_suites.pyl b/third_party/libwebrtc/infra/specs/test_suites.pyl index 570314c9bd..e6d98748c7 100644 --- a/third_party/libwebrtc/infra/specs/test_suites.pyl +++ b/third_party/libwebrtc/infra/specs/test_suites.pyl @@ -54,6 +54,9 @@ 'webrtc_nonparallel_tests': {}, }, 'android_tests_tryserver_specific': { + 'video_codec_perf_tests': { + 'mixins': ['shards-2', 'quick-perf-tests'], + }, 'webrtc_perf_tests': { 'mixins': ['quick-perf-tests'], } @@ -95,9 +98,6 @@ 'shared_screencast_stream_test': {}, }, 'desktop_tests_try_server_specific': { - 'video_capture_tests': { - 'mixins': ['baremetal-try-pool'], - }, 'video_codec_perf_tests': { 'mixins': ['quick-perf-tests', 'resultdb-gtest-json-format'], }, @@ -155,14 +155,13 @@ 'system_wrappers_unittests': {}, 'test_support_unittests': {}, 'tools_unittests': {}, - 'video_capture_tests': {}, 'video_engine_tests': { 'mixins': ['shards-4'], }, }, 'ios_simulator_tests': { 'apprtcmobile_tests': { - 'mixins': ['xcode_parallelization'] + 'mixins': ['xcodebuild_sim_runner'] }, 'audio_decoder_unittests': {}, 'common_audio_unittests': {}, @@ -181,10 +180,10 @@ 'mixins': ['shards-6'], }, 'sdk_framework_unittests': { - 'mixins': ['xcode_parallelization'] + 'mixins': ['xcodebuild_sim_runner'] }, 'sdk_unittests': { - 'mixins': ['xcode_parallelization'] + 'mixins': ['xcodebuild_sim_runner'] }, 'svc_tests': { 'mixins': ['shards-4', 'cores-12'], @@ -192,7 +191,6 @@ 'system_wrappers_unittests': {}, 'test_support_unittests': {}, 'tools_unittests': {}, - 'video_capture_tests': {}, 'video_engine_tests': { 'mixins': ['shards-4'], }, @@ -231,11 +229,6 @@ ], }, }, - 'video_capture_tests': { - 'video_capture_tests': { - 'mixins': ['baremetal-pool'], - } - }, }, ############################################################################## @@ -250,20 +243,11 @@ 'desktop_tests', 'desktop_tests_try_server_specific', ], - 'desktop_tests_with_video_capture': [ - 'desktop_tests', - 'video_capture_tests', - ], 'linux_desktop_tests_tryserver': [ 'desktop_tests', 'desktop_tests_linux_specific', 'desktop_tests_try_server_specific', ], - 'linux_desktop_tests_with_video_capture': [ - 'desktop_tests', - 'desktop_tests_linux_specific', - 'video_capture_tests', - ], 'linux_tests': [ 'desktop_tests', 'desktop_tests_linux_specific', @@ -277,9 +261,9 @@ 'ios_simulator_tests_matrix': { 'ios_simulator_tests': { 'variants': [ - 'SIM_IPHONE_X_14_5', 'SIM_IPHONE_X_15_5', - 'SIM_IPHONE_X_16_2', + 'SIM_IPHONE_X_16_4', + 'SIM_IPHONE_14_17_0', ], }, }, diff --git a/third_party/libwebrtc/infra/specs/tryserver.webrtc.json b/third_party/libwebrtc/infra/specs/tryserver.webrtc.json index 61e47fd0f8..3ab538b02c 100644 --- a/third_party/libwebrtc/infra/specs/tryserver.webrtc.json +++ b/third_party/libwebrtc/infra/specs/tryserver.webrtc.json @@ -368,6 +368,31 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, + { + "args": [ + "--webrtc_quick_perf_test", + "--nologs" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "video_codec_perf_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "android_devices": "1", + "device_type": "walleye", + "os": "Android" + }, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "video_codec_perf_tests", + "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" + }, { "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -845,6 +870,31 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, + { + "args": [ + "--webrtc_quick_perf_test", + "--nologs" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "video_codec_perf_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "android_devices": "1", + "device_type": "walleye", + "os": "Android" + }, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "video_codec_perf_tests", + "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" + }, { "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -1322,6 +1372,31 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, + { + "args": [ + "--webrtc_quick_perf_test", + "--nologs" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "video_codec_perf_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "android_devices": "1", + "device_type": "walleye", + "os": "Android" + }, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "video_codec_perf_tests", + "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" + }, { "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -1824,6 +1899,31 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, + { + "args": [ + "--webrtc_quick_perf_test", + "--nologs" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "video_codec_perf_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "android_devices": "1", + "device_type": "walleye", + "os": "Android" + }, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "video_codec_perf_tests", + "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" + }, { "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -1962,7 +2062,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -1986,7 +2086,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -2010,7 +2110,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -2034,7 +2134,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -2058,7 +2158,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -2082,7 +2182,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -2106,7 +2206,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2131,7 +2231,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -2155,7 +2255,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -2180,7 +2280,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -2204,7 +2304,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -2219,20 +2319,20 @@ { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "apprtcmobile_tests iPhone X 14.5", + "name": "apprtcmobile_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2242,29 +2342,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -2275,9 +2374,9 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2292,17 +2391,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -2321,18 +2419,18 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "apprtcmobile_tests iPhone X 16.2", + "name": "apprtcmobile_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2342,46 +2440,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "apprtcmobile_tests", "test_id_prefix": "ninja://examples:apprtcmobile_tests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "audio_decoder_unittests iPhone X 14.5", + "name": "audio_decoder_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2391,29 +2488,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -2425,7 +2521,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2440,17 +2536,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -2469,17 +2564,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "audio_decoder_unittests iPhone X 16.2", + "name": "audio_decoder_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2489,46 +2584,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "audio_decoder_unittests", "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "common_audio_unittests iPhone X 14.5", + "name": "common_audio_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2538,29 +2632,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -2572,7 +2665,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2587,17 +2680,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -2616,17 +2708,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "common_audio_unittests iPhone X 16.2", + "name": "common_audio_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2636,46 +2728,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "common_audio_unittests", "test_id_prefix": "ninja://common_audio:common_audio_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "common_video_unittests iPhone X 14.5", + "name": "common_video_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2685,29 +2776,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -2719,7 +2809,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2734,17 +2824,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -2763,17 +2852,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "common_video_unittests iPhone X 16.2", + "name": "common_video_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2783,46 +2872,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "common_video_unittests", "test_id_prefix": "ninja://common_video:common_video_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "dcsctp_unittests iPhone X 14.5", + "name": "dcsctp_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2832,29 +2920,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -2866,7 +2953,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2881,17 +2968,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -2910,17 +2996,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "dcsctp_unittests iPhone X 16.2", + "name": "dcsctp_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2930,46 +3016,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "dcsctp_unittests", "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "modules_tests iPhone X 14.5", + "name": "modules_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -2979,22 +3064,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -3002,7 +3086,7 @@ }, "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -3014,7 +3098,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3029,17 +3113,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -3059,17 +3142,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "modules_tests iPhone X 16.2", + "name": "modules_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3079,22 +3162,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -3102,24 +3184,24 @@ }, "test": "modules_tests", "test_id_prefix": "ninja://modules:modules_tests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "modules_unittests iPhone X 14.5", + "name": "modules_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3129,23 +3211,22 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -3153,7 +3234,7 @@ }, "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -3165,7 +3246,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3180,18 +3261,17 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -3211,17 +3291,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "modules_unittests iPhone X 16.2", + "name": "modules_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3231,23 +3311,22 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -3255,24 +3334,24 @@ }, "test": "modules_unittests", "test_id_prefix": "ninja://modules:modules_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_media_unittests iPhone X 14.5", + "name": "rtc_media_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3282,29 +3361,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -3316,7 +3394,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3331,17 +3409,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -3360,17 +3437,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_media_unittests iPhone X 16.2", + "name": "rtc_media_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3380,46 +3457,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_media_unittests", "test_id_prefix": "ninja://media:rtc_media_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_pc_unittests iPhone X 14.5", + "name": "rtc_pc_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3429,29 +3505,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -3463,7 +3538,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3478,17 +3553,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -3507,17 +3581,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_pc_unittests iPhone X 16.2", + "name": "rtc_pc_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3527,46 +3601,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_pc_unittests", "test_id_prefix": "ninja://pc:rtc_pc_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_stats_unittests iPhone X 14.5", + "name": "rtc_stats_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3576,29 +3649,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -3610,7 +3682,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3625,17 +3697,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -3654,17 +3725,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_stats_unittests iPhone X 16.2", + "name": "rtc_stats_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3674,46 +3745,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "rtc_stats_unittests", "test_id_prefix": "ninja://stats:rtc_stats_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_unittests iPhone X 14.5", + "name": "rtc_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3723,22 +3793,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -3746,7 +3815,7 @@ }, "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -3758,7 +3827,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3773,17 +3842,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -3803,17 +3871,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "rtc_unittests iPhone X 16.2", + "name": "rtc_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3823,22 +3891,21 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -3846,25 +3913,25 @@ }, "test": "rtc_unittests", "test_id_prefix": "ninja://:rtc_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "sdk_framework_unittests iPhone X 14.5", + "name": "sdk_framework_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3874,29 +3941,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -3907,9 +3973,9 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3924,17 +3990,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -3953,18 +4018,18 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "sdk_framework_unittests iPhone X 16.2", + "name": "sdk_framework_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -3974,47 +4039,46 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sdk_framework_unittests", "test_id_prefix": "ninja://sdk:sdk_framework_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "sdk_unittests iPhone X 14.5", + "name": "sdk_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4024,29 +4088,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -4057,9 +4120,9 @@ "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4074,17 +4137,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -4103,18 +4165,18 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", - "--xcode-parallelization", + "--xcodebuild-sim-runner", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "sdk_unittests iPhone X 16.2", + "name": "sdk_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4124,46 +4186,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sdk_unittests", "test_id_prefix": "ninja://sdk:sdk_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "svc_tests iPhone X 14.5", + "name": "svc_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4173,23 +4234,22 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -4197,7 +4257,7 @@ }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -4209,7 +4269,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4224,18 +4284,17 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -4255,17 +4314,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "svc_tests iPhone X 16.2", + "name": "svc_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4275,23 +4334,22 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cores": "12", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -4299,24 +4357,24 @@ }, "test": "svc_tests", "test_id_prefix": "ninja://pc:svc_tests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "system_wrappers_unittests iPhone X 14.5", + "name": "system_wrappers_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4326,29 +4384,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -4360,7 +4417,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4375,17 +4432,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -4404,17 +4460,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "system_wrappers_unittests iPhone X 16.2", + "name": "system_wrappers_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4424,46 +4480,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "system_wrappers_unittests", "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "test_support_unittests iPhone X 14.5", + "name": "test_support_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4473,29 +4528,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -4507,7 +4561,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4522,17 +4576,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -4551,17 +4604,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "test_support_unittests iPhone X 16.2", + "name": "test_support_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4571,46 +4624,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "test_support_unittests", "test_id_prefix": "ninja://test:test_support_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "tools_unittests iPhone X 14.5", + "name": "tools_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4620,29 +4672,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", - "variant_id": "iPhone X 14.5" + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -4654,7 +4705,7 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4669,17 +4720,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -4698,17 +4748,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "tools_unittests iPhone X 16.2", + "name": "tools_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4718,46 +4768,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/", - "variant_id": "iPhone X 16.2" + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "video_capture_tests iPhone X 14.5", + "name": "video_engine_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4767,29 +4816,29 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", - "variant_id": "iPhone X 14.5" + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/", + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -4801,12 +4850,12 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "video_capture_tests iPhone X 15.5", + "name": "video_engine_tests iPhone X 15.5", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4816,17 +4865,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -4834,10 +4882,11 @@ "path": "Runtime-ios-15.5" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/", "variant_id": "iPhone X 15.5" }, { @@ -4845,17 +4894,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "video_capture_tests iPhone X 16.2", + "name": "video_engine_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4865,46 +4914,46 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/", - "variant_id": "iPhone X 16.2" + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/", + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "video_engine_tests iPhone X 14.5", + "name": "voip_unittests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4914,30 +4963,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test": "video_engine_tests", - "test_id_prefix": "ninja://:video_engine_tests/", - "variant_id": "iPhone X 14.5" + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/", + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -4949,12 +4996,12 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "video_engine_tests iPhone X 15.5", + "name": "voip_unittests iPhone X 15.5", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -4964,17 +5011,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -4982,11 +5028,10 @@ "path": "Runtime-ios-15.5" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test": "video_engine_tests", - "test_id_prefix": "ninja://:video_engine_tests/", + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/", "variant_id": "iPhone X 15.5" }, { @@ -4994,17 +5039,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "video_engine_tests iPhone X 16.2", + "name": "voip_unittests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -5014,47 +5059,45 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test": "video_engine_tests", - "test_id_prefix": "ninja://:video_engine_tests/", - "variant_id": "iPhone X 16.2" + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/", + "variant_id": "iPhone X 16.4" }, { "args": [ "--platform", - "iPhone X", + "iPhone 14", "--version", - "14.5", + "17.0", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "13c100" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "voip_unittests iPhone X 14.5", + "name": "webrtc_nonparallel_tests iPhone 14 17.0", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -5064,29 +5107,28 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_13c100", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_13c100", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" + "name": "runtime_ios_17_0", + "path": "Runtime-ios-17.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test": "voip_unittests", - "test_id_prefix": "ninja://:voip_unittests/", - "variant_id": "iPhone X 14.5" + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", + "variant_id": "iPhone 14 17.0" }, { "args": [ @@ -5098,12 +5140,12 @@ "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "voip_unittests iPhone X 15.5", + "name": "webrtc_nonparallel_tests iPhone X 15.5", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -5113,17 +5155,16 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { @@ -5133,8 +5174,8 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test": "voip_unittests", - "test_id_prefix": "ninja://:voip_unittests/", + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", "variant_id": "iPhone X 15.5" }, { @@ -5142,17 +5183,17 @@ "--platform", "iPhone X", "--version", - "16.2", + "16.4", "--out-dir", "${ISOLATED_OUTDIR}", "--xctest", "--xcode-build-version", - "14c18" + "15a507" ], "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "voip_unittests iPhone X 16.2", + "name": "webrtc_nonparallel_tests iPhone X 16.4", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -5162,181 +5203,33 @@ { "cipd_package": "infra/tools/mac_toolchain/${platform}", "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" + "revision": "git_revision:b28cf90d462a7bbd45c28f2d931960c2b9404cb0" } ], "dimensions": { - "caches": "xcode_ios_14c18", "cpu": "x86-64", - "os": "Mac-12" + "os": "Mac-13" }, "named_caches": [ { - "name": "xcode_ios_14c18", + "name": "xcode_ios_15a507", "path": "Xcode.app" }, { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" + "name": "runtime_ios_16_4", + "path": "Runtime-ios-16.4" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test": "voip_unittests", - "test_id_prefix": "ninja://:voip_unittests/", - "variant_id": "iPhone X 16.2" - }, - { - "args": [ - "--platform", - "iPhone X", - "--version", - "14.5", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xctest", - "--xcode-build-version", - "13c100" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "webrtc_nonparallel_tests iPhone X 14.5", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" - } - ], - "dimensions": { - "caches": "xcode_ios_13c100", - "cpu": "x86-64", - "os": "Mac-12" - }, - "named_caches": [ - { - "name": "xcode_ios_13c100", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_14_5", - "path": "Runtime-ios-14.5" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "webrtc_nonparallel_tests", - "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", - "variant_id": "iPhone X 14.5" - }, - { - "args": [ - "--platform", - "iPhone X", - "--version", - "15.5", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xctest", - "--xcode-build-version", - "14c18" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "webrtc_nonparallel_tests iPhone X 15.5", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" - } - ], - "dimensions": { - "caches": "xcode_ios_14c18", - "cpu": "x86-64", - "os": "Mac-12" - }, - "named_caches": [ - { - "name": "xcode_ios_14c18", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_15_5", - "path": "Runtime-ios-15.5" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "webrtc_nonparallel_tests", - "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", - "variant_id": "iPhone X 15.5" - }, - { - "args": [ - "--platform", - "iPhone X", - "--version", - "16.2", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xctest", - "--xcode-build-version", - "14c18" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "webrtc_nonparallel_tests iPhone X 16.2", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:32d81d877ee07af07bf03b7f70ce597e323b80ce" - } - ], - "dimensions": { - "caches": "xcode_ios_14c18", - "cpu": "x86-64", - "os": "Mac-12" - }, - "named_caches": [ - { - "name": "xcode_ios_14c18", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_16_2", - "path": "Runtime-ios-16.2" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "webrtc_nonparallel_tests", - "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", - "variant_id": "iPhone X 16.2" - } - ] - }, - "linux_asan": { - "isolated_scripts": [ + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/", + "variant_id": "iPhone X 16.4" + } + ] + }, + "linux_asan": { + "isolated_scripts": [ { "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5348,7 +5241,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -5365,7 +5258,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -5382,7 +5275,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -5399,7 +5292,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -5416,7 +5309,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -5434,7 +5327,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -5452,7 +5345,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -5470,7 +5363,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -5487,7 +5380,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -5504,7 +5397,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -5521,7 +5414,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -5539,7 +5432,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -5556,7 +5449,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -5573,7 +5466,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -5591,7 +5484,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -5608,7 +5501,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -5625,7 +5518,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -5642,7 +5535,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -5660,7 +5553,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -5677,7 +5570,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -5705,7 +5598,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -5723,7 +5616,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -5741,7 +5634,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -5759,7 +5652,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -5777,7 +5670,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -5796,7 +5689,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -5815,7 +5708,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -5834,7 +5727,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -5852,7 +5745,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -5870,7 +5763,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -5888,7 +5781,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -5907,7 +5800,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -5925,7 +5818,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -5943,7 +5836,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -5962,7 +5855,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -5980,7 +5873,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -5998,31 +5891,12 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "isolate_profile_data": true, - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "result_format": "json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Ubuntu-18.04", - "pool": "WebRTC-baremetal-try" - } - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, { "args": [ "--webrtc_quick_perf_test", @@ -6041,7 +5915,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "video_codec_perf_tests", @@ -6059,7 +5933,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -6078,7 +5952,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -6096,7 +5970,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -6120,7 +5994,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_perf_tests", @@ -6141,7 +6015,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -6158,7 +6032,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -6175,7 +6049,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -6192,7 +6066,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -6209,7 +6083,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -6227,7 +6101,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -6245,7 +6119,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -6263,7 +6137,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -6280,7 +6154,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -6297,7 +6171,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -6314,7 +6188,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -6332,7 +6206,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -6349,7 +6223,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -6366,7 +6240,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -6384,7 +6258,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -6401,7 +6275,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -6418,7 +6292,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -6435,7 +6309,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -6453,7 +6327,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -6470,7 +6344,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -6492,7 +6366,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -6509,7 +6383,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -6526,7 +6400,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -6543,7 +6417,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -6560,7 +6434,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -6578,7 +6452,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -6596,7 +6470,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -6614,7 +6488,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -6631,7 +6505,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -6648,7 +6522,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -6665,7 +6539,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -6683,7 +6557,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -6700,7 +6574,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -6717,7 +6591,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -6735,7 +6609,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -6752,7 +6626,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -6769,7 +6643,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -6786,7 +6660,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -6804,7 +6678,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -6821,7 +6695,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -6842,7 +6716,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -7197,7 +7071,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -7214,7 +7088,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -7231,7 +7105,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -7248,7 +7122,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -7265,7 +7139,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -7283,7 +7157,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -7301,7 +7175,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -7319,7 +7193,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -7336,7 +7210,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -7353,7 +7227,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -7370,7 +7244,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -7388,7 +7262,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -7405,7 +7279,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -7422,7 +7296,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -7440,7 +7314,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -7457,7 +7331,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -7474,30 +7348,12 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "result_format": "json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Ubuntu-18.04", - "pool": "WebRTC-baremetal-try" - } - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, { "args": [ "--webrtc_quick_perf_test", @@ -7515,7 +7371,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "video_codec_perf_tests", @@ -7532,7 +7388,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -7550,7 +7406,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -7567,7 +7423,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -7590,7 +7446,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_perf_tests", @@ -7611,7 +7467,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -7628,7 +7484,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -7645,7 +7501,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -7662,7 +7518,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -7679,7 +7535,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -7697,7 +7553,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -7715,7 +7571,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -7733,7 +7589,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -7750,7 +7606,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -7767,7 +7623,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -7784,7 +7640,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -7802,7 +7658,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -7819,7 +7675,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -7837,7 +7693,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -7854,7 +7710,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -7871,7 +7727,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -7888,7 +7744,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -7906,7 +7762,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -7923,7 +7779,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -7944,7 +7800,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -7961,7 +7817,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -7978,7 +7834,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -7995,7 +7851,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -8012,7 +7868,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -8030,7 +7886,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -8048,7 +7904,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8066,7 +7922,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -8083,7 +7939,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -8100,7 +7956,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -8117,7 +7973,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -8135,7 +7991,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -8152,7 +8008,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -8169,7 +8025,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8187,7 +8043,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -8204,7 +8060,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -8221,7 +8077,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -8238,7 +8094,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8256,7 +8112,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -8273,7 +8129,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -8294,7 +8150,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -8311,7 +8167,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -8328,7 +8184,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -8345,7 +8201,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -8362,7 +8218,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -8380,7 +8236,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -8398,7 +8254,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8416,7 +8272,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -8433,7 +8289,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -8450,7 +8306,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -8467,7 +8323,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -8485,7 +8341,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "shared_screencast_stream_test", @@ -8502,7 +8358,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -8519,7 +8375,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8537,7 +8393,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -8554,7 +8410,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -8571,7 +8427,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -8588,7 +8444,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8606,7 +8462,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -8623,7 +8479,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -8644,7 +8500,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -8661,7 +8517,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -8678,7 +8534,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -8695,7 +8551,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -8712,7 +8568,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -8730,7 +8586,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -8748,7 +8604,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8766,7 +8622,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -8783,7 +8639,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -8800,7 +8656,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -8817,7 +8673,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -8835,7 +8691,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -8852,7 +8708,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8870,7 +8726,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -8887,7 +8743,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -8904,7 +8760,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -8921,7 +8777,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -8939,7 +8795,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -8956,7 +8812,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -8977,7 +8833,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "audio_decoder_unittests", @@ -8994,7 +8850,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_audio_unittests", @@ -9011,7 +8867,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "common_video_unittests", @@ -9028,7 +8884,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "dcsctp_unittests", @@ -9045,7 +8901,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 2 }, @@ -9063,7 +8919,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -9081,7 +8937,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -9099,7 +8955,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_media_unittests", @@ -9116,7 +8972,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_pc_unittests", @@ -9133,7 +8989,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "rtc_stats_unittests", @@ -9150,7 +9006,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 6 }, @@ -9168,7 +9024,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "slow_peer_connection_unittests", @@ -9185,7 +9041,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -9203,7 +9059,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "system_wrappers_unittests", @@ -9220,7 +9076,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "test_support_unittests", @@ -9237,7 +9093,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "tools_unittests", @@ -9254,7 +9110,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" }, "shards": 4 }, @@ -9272,7 +9128,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "voip_unittests", @@ -9289,7 +9145,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Ubuntu-18.04" + "os": "Ubuntu-20.04" } }, "test": "webrtc_nonparallel_tests", @@ -9754,7 +9610,686 @@ }, "swarming": { "dimensions": { - "cores": "12", + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + }, + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + }, + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + }, + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "slow_peer_connection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "slow_peer_connection_unittests", + "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "svc_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + }, + "shards": 4 + }, + "test": "svc_tests", + "test_id_prefix": "ninja://pc:svc_tests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + }, + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cores": "12", + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "mac_dbg_m1": { + "isolated_scripts": [ + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + }, + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + }, + "shards": 6 + }, + "test": "modules_unittests", + "test_id_prefix": "ninja://modules:modules_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "peerconnection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + }, + "shards": 4 + }, + "test": "peerconnection_unittests", + "test_id_prefix": "ninja://pc:peerconnection_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_media_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "rtc_media_unittests", + "test_id_prefix": "ninja://media:rtc_media_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_pc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "rtc_pc_unittests", + "test_id_prefix": "ninja://pc:rtc_pc_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_stats_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "rtc_stats_unittests", + "test_id_prefix": "ninja://stats:rtc_stats_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "rtc_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + }, + "shards": 6 + }, + "test": "rtc_unittests", + "test_id_prefix": "ninja://:rtc_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "slow_peer_connection_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "slow_peer_connection_unittests", + "test_id_prefix": "ninja://pc:slow_peer_connection_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "svc_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + }, + "shards": 4 + }, + "test": "svc_tests", + "test_id_prefix": "ninja://pc:svc_tests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "system_wrappers_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "system_wrappers_unittests", + "test_id_prefix": "ninja://system_wrappers:system_wrappers_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "test_support_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "test_support_unittests", + "test_id_prefix": "ninja://test:test_support_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "tools_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "tools_unittests", + "test_id_prefix": "ninja://rtc_tools:tools_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_engine_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + }, + "shards": 4 + }, + "test": "video_engine_tests", + "test_id_prefix": "ninja://:video_engine_tests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "voip_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "voip_unittests", + "test_id_prefix": "ninja://:voip_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_nonparallel_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "arm64-64-Apple_M1", + "os": "Mac-12" + } + }, + "test": "webrtc_nonparallel_tests", + "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + } + ] + }, + "mac_rel": { + "isolated_scripts": [ + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "audio_decoder_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "audio_decoder_unittests", + "test_id_prefix": "ninja://modules/audio_coding:audio_decoder_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_audio_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "common_audio_unittests", + "test_id_prefix": "ninja://common_audio:common_audio_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "common_video_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "common_video_unittests", + "test_id_prefix": "ninja://common_video:common_video_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "dcsctp_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "dcsctp_unittests", + "test_id_prefix": "ninja://net/dcsctp:dcsctp_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_tests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Mac-12" + }, + "shards": 2 + }, + "test": "modules_tests", + "test_id_prefix": "ninja://modules:modules_tests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "modules_unittests", + "resultdb": { + "result_format": "json" + }, + "swarming": { + "dimensions": { "cpu": "x86-64", "os": "Mac-12" }, @@ -9773,7 +10308,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" }, @@ -9792,7 +10326,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } @@ -9810,7 +10343,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } @@ -9828,7 +10360,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } @@ -9846,7 +10377,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" }, @@ -9865,7 +10395,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } @@ -9883,7 +10412,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" }, @@ -9902,7 +10430,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } @@ -9920,7 +10447,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } @@ -9938,7 +10464,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } @@ -9946,6 +10471,29 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, + { + "args": [ + "--webrtc_quick_perf_test", + "--nologs", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_codec_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "video_codec_perf_tests", + "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" + }, { "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -9956,7 +10504,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" }, @@ -9975,7 +10522,6 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } @@ -9993,17 +10539,39 @@ }, "swarming": { "dimensions": { - "cores": "12", "cpu": "x86-64", "os": "Mac-12" } }, "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--webrtc_quick_perf_test", + "--nologs", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Mac-12" + } + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] }, - "mac_dbg_m1": { + "mac_rel_m1": { "isolated_scripts": [ { "merge": { @@ -10336,7 +10904,7 @@ } ] }, - "mac_rel": { + "win11_debug": { "isolated_scripts": [ { "merge": { @@ -10349,7 +10917,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "audio_decoder_unittests", @@ -10366,7 +10934,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "common_audio_unittests", @@ -10383,7 +10951,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "common_video_unittests", @@ -10400,7 +10968,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "dcsctp_unittests", @@ -10417,7 +10985,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" }, "shards": 2 }, @@ -10435,7 +11003,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" }, "shards": 6 }, @@ -10453,7 +11021,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" }, "shards": 4 }, @@ -10471,7 +11039,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "rtc_media_unittests", @@ -10488,7 +11056,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "rtc_pc_unittests", @@ -10505,7 +11073,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "rtc_stats_unittests", @@ -10522,7 +11090,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" }, "shards": 6 }, @@ -10540,7 +11108,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "slow_peer_connection_unittests", @@ -10557,7 +11125,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" }, "shards": 4 }, @@ -10575,7 +11143,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "system_wrappers_unittests", @@ -10592,7 +11160,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "test_support_unittests", @@ -10609,53 +11177,12 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "result_format": "json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Mac-12", - "pool": "WebRTC-baremetal-try" - } - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, - { - "args": [ - "--webrtc_quick_perf_test", - "--nologs", - "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_codec_perf_tests", - "resultdb": { - "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", - "result_format": "gtest_json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Mac-12" - } - }, - "test": "video_codec_perf_tests", - "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" - }, { "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -10667,7 +11194,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" }, "shards": 4 }, @@ -10685,7 +11212,7 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "voip_unittests", @@ -10702,38 +11229,15 @@ "swarming": { "dimensions": { "cpu": "x86-64", - "os": "Mac-12" + "os": "Windows-11-22000" } }, "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" - }, - { - "args": [ - "--webrtc_quick_perf_test", - "--nologs", - "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "webrtc_perf_tests", - "resultdb": { - "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", - "result_format": "gtest_json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Mac-12" - } - }, - "test": "webrtc_perf_tests", - "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] }, - "mac_rel_m1": { + "win11_release": { "isolated_scripts": [ { "merge": { @@ -10745,8 +11249,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "audio_decoder_unittests", @@ -10762,8 +11266,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "common_audio_unittests", @@ -10779,8 +11283,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "common_video_unittests", @@ -10796,8 +11300,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "dcsctp_unittests", @@ -10813,8 +11317,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" }, "shards": 2 }, @@ -10831,8 +11335,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" }, "shards": 6 }, @@ -10849,8 +11353,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" }, "shards": 4 }, @@ -10867,8 +11371,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "rtc_media_unittests", @@ -10884,8 +11388,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "rtc_pc_unittests", @@ -10901,8 +11405,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "rtc_stats_unittests", @@ -10918,8 +11422,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" }, "shards": 6 }, @@ -10936,8 +11440,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "slow_peer_connection_unittests", @@ -10953,8 +11457,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" }, "shards": 4 }, @@ -10971,8 +11475,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "system_wrappers_unittests", @@ -10988,8 +11492,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "test_support_unittests", @@ -11005,13 +11509,36 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, + { + "args": [ + "--webrtc_quick_perf_test", + "--nologs", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "video_codec_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Windows-11-22000" + } + }, + "test": "video_codec_perf_tests", + "test_id_prefix": "ninja://modules/video_coding:video_codec_perf_tests/" + }, { "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -11022,8 +11549,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" }, "shards": 4 }, @@ -11040,8 +11567,8 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "voip_unittests", @@ -11057,12 +11584,35 @@ }, "swarming": { "dimensions": { - "cpu": "arm64-64-Apple_M1", - "os": "Mac-12" + "cpu": "x86-64", + "os": "Windows-11-22000" } }, "test": "webrtc_nonparallel_tests", "test_id_prefix": "ninja://:webrtc_nonparallel_tests/" + }, + { + "args": [ + "--webrtc_quick_perf_test", + "--nologs", + "--gtest_output=json:${ISOLATED_OUTDIR}/gtest_output.json" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webrtc_perf_tests", + "resultdb": { + "result_file": "${ISOLATED_OUTDIR}/gtest_output.json", + "result_format": "gtest_json" + }, + "swarming": { + "dimensions": { + "cpu": "x86-64", + "os": "Windows-11-22000" + } + }, + "test": "webrtc_perf_tests", + "test_id_prefix": "ninja://:webrtc_perf_tests/" } ] }, @@ -12681,24 +13231,6 @@ "test": "tools_unittests", "test_id_prefix": "ninja://rtc_tools:tools_unittests/" }, - { - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "video_capture_tests", - "resultdb": { - "result_format": "json" - }, - "swarming": { - "dimensions": { - "cpu": "x86-64", - "os": "Windows-10-19045", - "pool": "WebRTC-baremetal-try" - } - }, - "test": "video_capture_tests", - "test_id_prefix": "ninja://modules/video_capture:video_capture_tests/" - }, { "args": [ "--webrtc_quick_perf_test", diff --git a/third_party/libwebrtc/infra/specs/variants.pyl b/third_party/libwebrtc/infra/specs/variants.pyl index e764f698e3..c97bdc5468 100644 --- a/third_party/libwebrtc/infra/specs/variants.pyl +++ b/third_party/libwebrtc/infra/specs/variants.pyl @@ -7,34 +7,34 @@ # be found in the AUTHORS file in the root of the source tree. { - 'SIM_IPHONE_X_14_5': { + 'SIM_IPHONE_X_15_5': { 'args': [ '--platform', 'iPhone X', '--version', - '14.5', + '15.5', ], - 'identifier': 'iPhone X 14.5', - 'mixins': ['xcode_13_main', 'ios_runtime_cache_14_5'], + 'identifier': 'iPhone X 15.5', + 'mixins': ['xcode_15_main', 'ios_runtime_cache_15_5'], }, - 'SIM_IPHONE_X_15_5': { + 'SIM_IPHONE_X_16_4': { 'args': [ '--platform', 'iPhone X', '--version', - '15.5', + '16.4', ], - 'identifier': 'iPhone X 15.5', - 'mixins': ['xcode_14_main', 'ios_runtime_cache_15_5'], + 'identifier': 'iPhone X 16.4', + 'mixins': ['xcode_15_main', 'ios_runtime_cache_16_4'], }, - 'SIM_IPHONE_X_16_2': { + 'SIM_IPHONE_14_17_0': { 'args': [ '--platform', - 'iPhone X', + 'iPhone 14', '--version', - '16.2', + '17.0', ], - 'identifier': 'iPhone X 16.2', - 'mixins': ['xcode_14_main', 'ios_runtime_cache_16_2'], + 'identifier': 'iPhone 14 17.0', + 'mixins': ['xcode_15_main', 'ios_runtime_cache_17_0'], }, } diff --git a/third_party/libwebrtc/infra/specs/waterfalls.pyl b/third_party/libwebrtc/infra/specs/waterfalls.pyl index 76c1760d1d..3521a9fee3 100644 --- a/third_party/libwebrtc/infra/specs/waterfalls.pyl +++ b/third_party/libwebrtc/infra/specs/waterfalls.pyl @@ -70,7 +70,7 @@ 'os_type': 'linux', 'mixins': [ - 'linux-bionic', 'x86-64', 'fuchsia-gtest-output', + 'linux-focal', 'x86-64', 'fuchsia-gtest-output', 'resultdb-gtest-json-format' ], 'test_suites': { @@ -79,14 +79,14 @@ }, 'Linux (more configs)': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'more_configs_tests', }, }, 'Linux Asan': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, @@ -103,7 +103,7 @@ }, 'Linux Tsan v2': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { # TODO(crbug.com/webrtc/14568): Using 'linux_tests' # fails on "ThreadSanitizer: data race on vptr (ctor/dtor vs @@ -113,21 +113,21 @@ }, 'Linux UBSan': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, }, 'Linux UBSan vptr': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, }, 'Linux32 Debug': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'desktop_tests', }, @@ -135,7 +135,7 @@ 'Linux32 Debug (ARM)': {}, 'Linux32 Release': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'desktop_tests', }, @@ -144,7 +144,7 @@ 'Linux64 Builder': {}, 'Linux64 Debug': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, @@ -152,9 +152,9 @@ 'Linux64 Debug (ARM)': {}, 'Linux64 Release': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { - 'isolated_scripts': 'linux_desktop_tests_with_video_capture', + 'isolated_scripts': 'linux_tests', }, }, 'Linux64 Release (ARM)': {}, @@ -178,14 +178,12 @@ 'os_type': 'mac', 'mixins': ['mac_12_x64', 'resultdb-json-format'], 'test_suites': { - 'isolated_scripts': 'desktop_tests_with_video_capture', + 'isolated_scripts': 'desktop_tests', }, }, 'MacARM64 M1 Release': { 'os_type': 'mac', 'mixins': ['mac_12_arm64', 'mac-m1-cpu', 'resultdb-json-format'], - # TODO(b/228171565): Replace desktop_tests by desktop_tests_with_video_capture when - # there is a camera available for the baremetal m1 machines. 'test_suites': { 'isolated_scripts': 'desktop_tests', }, @@ -225,12 +223,12 @@ 'os_type': 'win', 'mixins': ['win10', 'x86-64', 'resultdb-json-format'], 'test_suites': { - 'isolated_scripts': 'desktop_tests_with_video_capture', + 'isolated_scripts': 'desktop_tests', }, }, 'iOS Debug (simulator)': { 'mixins': [ - 'mac_12_x64', 'chromium-tester-service-account', 'mac_toolchain', + 'mac_13_x64', 'chromium-tester-service-account', 'mac_toolchain', 'has_native_resultdb_integration', 'out_dir_arg', 'webrtc-xctest' ], 'test_suites': { @@ -422,7 +420,7 @@ 'os_type': 'linux', 'mixins': [ - 'linux-bionic', 'x86-64', 'fuchsia-gtest-output', + 'linux-focal', 'x86-64', 'fuchsia-gtest-output', 'resultdb-gtest-json-format' ], 'test_suites': { @@ -433,7 +431,7 @@ 'ios_compile_arm64_rel': {}, 'ios_dbg_simulator': { 'mixins': [ - 'mac_12_x64', 'chromium-tester-service-account', 'mac_toolchain', + 'mac_13_x64', 'chromium-tester-service-account', 'mac_toolchain', 'has_native_resultdb_integration', 'out_dir_arg', 'webrtc-xctest' ], 'test_suites': { @@ -442,7 +440,7 @@ }, 'linux_asan': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, @@ -457,7 +455,7 @@ 'os_type': 'linux', 'mixins': [ - 'linux-bionic', 'x86-64', 'resultdb-json-format', + 'linux-focal', 'x86-64', 'resultdb-json-format', 'isolate_profile_data' ], 'test_suites': { @@ -466,7 +464,7 @@ }, 'linux_dbg': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, @@ -474,14 +472,14 @@ 'linux_libfuzzer_rel': {}, 'linux_memcheck': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, }, 'linux_more_configs': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'more_configs_tests', }, @@ -498,14 +496,14 @@ }, 'linux_rel': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_desktop_tests_tryserver', }, }, 'linux_tsan2': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { # TODO(crbug.com/webrtc/14568): Using 'linux_tests' # fails on "ThreadSanitizer: data race on vptr (ctor/dtor vs @@ -515,28 +513,28 @@ }, 'linux_ubsan': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, }, 'linux_ubsan_vptr': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'linux_tests', }, }, 'linux_x86_dbg': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'desktop_tests', }, }, 'linux_x86_rel': { 'os_type': 'linux', - 'mixins': ['linux-bionic', 'x86-64', 'resultdb-json-format'], + 'mixins': ['linux-focal', 'x86-64', 'resultdb-json-format'], 'test_suites': { 'isolated_scripts': 'desktop_tests', }, @@ -574,12 +572,24 @@ 'mac_rel_m1': { 'os_type': 'mac', 'mixins': ['mac_12_arm64', 'mac-m1-cpu', 'resultdb-json-format'], - # TODO(b/228171565): Replace desktop_tests by desktop_tests_tryserver when - # there is a camera available for the baremetal-try m1 machines. 'test_suites': { 'isolated_scripts': 'desktop_tests', }, }, + 'win11_debug': { + 'os_type': 'win', + 'mixins': ['win11', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests', + }, + }, + 'win11_release': { + 'os_type': 'win', + 'mixins': ['win11', 'x86-64', 'resultdb-json-format'], + 'test_suites': { + 'isolated_scripts': 'desktop_tests_tryserver', + }, + }, 'win_asan': { 'os_type': 'win', 'mixins': ['win10', 'x86-64', 'resultdb-json-format'], diff --git a/third_party/libwebrtc/logging/BUILD.gn b/third_party/libwebrtc/logging/BUILD.gn index 92f55edfa0..91890553a3 100644 --- a/third_party/libwebrtc/logging/BUILD.gn +++ b/third_party/libwebrtc/logging/BUILD.gn @@ -82,6 +82,7 @@ rtc_library("rtc_stream_config") { } rtc_library("rtc_event_pacing") { + visibility = [ "*" ] sources = [ "rtc_event_log/events/rtc_event_alr_state.cc", "rtc_event_log/events/rtc_event_alr_state.h", @@ -99,6 +100,7 @@ rtc_library("rtc_event_pacing") { } rtc_library("rtc_event_audio") { + visibility = [ "*" ] sources = [ "rtc_event_log/events/rtc_event_audio_network_adaptation.cc", "rtc_event_log/events/rtc_event_audio_network_adaptation.h", @@ -143,6 +145,7 @@ rtc_library("rtc_event_begin_end") { } rtc_library("rtc_event_bwe") { + visibility = [ "*" ] sources = [ "rtc_event_log/events/rtc_event_bwe_update_delay_based.cc", "rtc_event_log/events/rtc_event_bwe_update_delay_based.h", @@ -174,6 +177,7 @@ rtc_library("rtc_event_bwe") { } rtc_library("rtc_event_frame_events") { + visibility = [ "*" ] sources = [ "rtc_event_log/events/rtc_event_frame_decoded.cc", "rtc_event_log/events/rtc_event_frame_decoded.h", @@ -216,6 +220,7 @@ rtc_library("rtc_event_generic_packet_events") { } rtc_library("rtc_event_rtp_rtcp") { + visibility = [ "*" ] sources = [ "rtc_event_log/events/logged_rtp_rtcp.h", "rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc", @@ -245,6 +250,7 @@ rtc_library("rtc_event_rtp_rtcp") { } rtc_library("rtc_event_video") { + visibility = [ "*" ] sources = [ "rtc_event_log/events/rtc_event_video_receive_stream_config.cc", "rtc_event_log/events/rtc_event_video_receive_stream_config.h", @@ -450,8 +456,10 @@ if (rtc_enable_protobuf) { ":ice_log", ":rtc_event_log_api", ":rtc_event_log_impl_encoder", + "../api:field_trials_view", "../api:libjingle_logging_api", "../api:sequence_checker", + "../api/environment", "../api/rtc_event_log", "../api/task_queue", "../api/units:time_delta", @@ -459,7 +467,6 @@ if (rtc_enable_protobuf) { "../rtc_base:logging", "../rtc_base:macromagic", "../rtc_base:rtc_event", - "../rtc_base:rtc_task_queue", "../rtc_base:safe_conversions", "../rtc_base:safe_minmax", "../rtc_base:timeutils", @@ -666,6 +673,7 @@ if (rtc_enable_protobuf) { } rtc_library("ice_log") { + visibility = [ "*" ] sources = [ "rtc_event_log/events/rtc_event_dtls_transport_state.cc", "rtc_event_log/events/rtc_event_dtls_transport_state.h", diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.cc b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.cc index f2b3f22d6a..419afd330a 100644 --- a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.cc +++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.cc @@ -17,6 +17,8 @@ #include #include "absl/strings/string_view.h" +#include "api/environment/environment.h" +#include "api/field_trials_view.h" #include "api/task_queue/task_queue_base.h" #include "api/units/time_delta.h" #include "logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h" @@ -29,24 +31,23 @@ #include "rtc_base/time_utils.h" namespace webrtc { +namespace { -std::unique_ptr RtcEventLogImpl::CreateEncoder( - RtcEventLog::EncodingType type) { - switch (type) { - case RtcEventLog::EncodingType::Legacy: - RTC_DLOG(LS_INFO) << "Creating legacy encoder for RTC event log."; - return std::make_unique(); - case RtcEventLog::EncodingType::NewFormat: - RTC_DLOG(LS_INFO) << "Creating new format encoder for RTC event log."; - return std::make_unique(); - default: - RTC_LOG(LS_ERROR) << "Unknown RtcEventLog encoder type (" << int(type) - << ")"; - RTC_DCHECK_NOTREACHED(); - return std::unique_ptr(nullptr); +std::unique_ptr CreateEncoder(const Environment& env) { + if (env.field_trials().IsDisabled("WebRTC-RtcEventLogNewFormat")) { + RTC_DLOG(LS_INFO) << "Creating legacy encoder for RTC event log."; + return std::make_unique(); + } else { + RTC_DLOG(LS_INFO) << "Creating new format encoder for RTC event log."; + return std::make_unique(); } } +} // namespace + +RtcEventLogImpl::RtcEventLogImpl(const Environment& env) + : RtcEventLogImpl(CreateEncoder(env), &env.task_queue_factory()) {} + RtcEventLogImpl::RtcEventLogImpl(std::unique_ptr encoder, TaskQueueFactory* task_queue_factory, size_t max_events_in_history, @@ -55,10 +56,9 @@ RtcEventLogImpl::RtcEventLogImpl(std::unique_ptr encoder, max_config_events_in_history_(max_config_events_in_history), event_encoder_(std::move(encoder)), last_output_ms_(rtc::TimeMillis()), - task_queue_( - std::make_unique(task_queue_factory->CreateTaskQueue( - "rtc_event_log", - TaskQueueFactory::Priority::NORMAL))) {} + task_queue_(task_queue_factory->CreateTaskQueue( + "rtc_event_log", + TaskQueueFactory::Priority::NORMAL)) {} RtcEventLogImpl::~RtcEventLogImpl() { // If we're logging to the output, this will stop that. Blocking function. @@ -71,10 +71,12 @@ RtcEventLogImpl::~RtcEventLogImpl() { StopLogging(); } - // We want to block on any executing task by invoking ~TaskQueue() before + // Since we are posting tasks bound to `this`, it is critical that the event + // log and its members outlive `task_queue_`. Destruct `task_queue_` first + // to ensure tasks living on the queue can access other members. + // We want to block on any executing task by deleting TaskQueue before // we set unique_ptr's internal pointer to null. - rtc::TaskQueue* tq = task_queue_.get(); - delete tq; + task_queue_.get_deleter()(task_queue_.get()); task_queue_.release(); } diff --git a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.h b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.h index 3187a7fe87..2c4ef8d7ed 100644 --- a/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.h +++ b/third_party/libwebrtc/logging/rtc_event_log/rtc_event_log_impl.h @@ -18,14 +18,15 @@ #include #include "absl/strings/string_view.h" +#include "api/environment/environment.h" #include "api/rtc_event_log/rtc_event.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/rtc_event_log_output.h" #include "api/sequence_checker.h" +#include "api/task_queue/task_queue_base.h" #include "api/task_queue/task_queue_factory.h" #include "logging/rtc_event_log/encoder/rtc_event_log_encoder.h" #include "rtc_base/system/no_unique_address.h" -#include "rtc_base/task_queue.h" #include "rtc_base/thread_annotations.h" namespace webrtc { @@ -39,6 +40,7 @@ class RtcEventLogImpl final : public RtcEventLog { // bound to prevent an attack via unreasonable memory use. static constexpr size_t kMaxEventsInConfigHistory = 1000; + explicit RtcEventLogImpl(const Environment& env); RtcEventLogImpl( std::unique_ptr encoder, TaskQueueFactory* task_queue_factory, @@ -49,9 +51,6 @@ class RtcEventLogImpl final : public RtcEventLog { ~RtcEventLogImpl() override; - static std::unique_ptr CreateEncoder( - EncodingType encoding_type); - // TODO(eladalon): We should change these name to reflect that what we're // actually starting/stopping is the output of the log, not the log itself. bool StartLogging(std::unique_ptr output, @@ -114,11 +113,7 @@ class RtcEventLogImpl final : public RtcEventLog { bool immediately_output_mode_ RTC_GUARDED_BY(mutex_) = false; bool need_schedule_output_ RTC_GUARDED_BY(mutex_) = false; - // Since we are posting tasks bound to `this`, it is critical that the event - // log and its members outlive `task_queue_`. Keep the `task_queue_` - // last to ensure it destructs first, or else tasks living on the queue might - // access other members after they've been torn down. - std::unique_ptr task_queue_; + std::unique_ptr task_queue_; Mutex mutex_; }; diff --git a/third_party/libwebrtc/media/BUILD.gn b/third_party/libwebrtc/media/BUILD.gn index 055bf75a19..44638d562e 100644 --- a/third_party/libwebrtc/media/BUILD.gn +++ b/third_party/libwebrtc/media/BUILD.gn @@ -549,7 +549,6 @@ rtc_library("rtc_audio_video") { "../rtc_base:macromagic", "../rtc_base:network_route", "../rtc_base:race_checker", - "../rtc_base:rtc_task_queue", "../rtc_base:safe_conversions", "../rtc_base:socket", "../rtc_base:ssl", diff --git a/third_party/libwebrtc/media/base/codec.cc b/third_party/libwebrtc/media/base/codec.cc index c4e1c6f1f3..d18baf7132 100644 --- a/third_party/libwebrtc/media/base/codec.cc +++ b/third_party/libwebrtc/media/base/codec.cc @@ -15,6 +15,9 @@ #include "api/audio_codecs/audio_format.h" #include "api/video_codecs/av1_profile.h" #include "api/video_codecs/h264_profile_level_id.h" +#ifdef RTC_ENABLE_H265 +#include "api/video_codecs/h265_profile_tier_level.h" +#endif #include "api/video_codecs/vp9_profile.h" #include "media/base/media_constants.h" #include "rtc_base/checks.h" @@ -25,7 +28,8 @@ namespace cricket { namespace { -std::string GetH264PacketizationModeOrDefault(const CodecParameterMap& params) { +std::string GetH264PacketizationModeOrDefault( + const webrtc::CodecParameterMap& params) { auto it = params.find(kH264FmtpPacketizationMode); if (it != params.end()) { return it->second; @@ -35,18 +39,36 @@ std::string GetH264PacketizationModeOrDefault(const CodecParameterMap& params) { return "0"; } -bool IsSameH264PacketizationMode(const CodecParameterMap& left, - const CodecParameterMap& right) { +bool IsSameH264PacketizationMode(const webrtc::CodecParameterMap& left, + const webrtc::CodecParameterMap& right) { return GetH264PacketizationModeOrDefault(left) == GetH264PacketizationModeOrDefault(right); } +#ifdef RTC_ENABLE_H265 +std::string GetH265TxModeOrDefault(const webrtc::CodecParameterMap& params) { + auto it = params.find(kH265FmtpTxMode); + if (it != params.end()) { + return it->second; + } + // If TxMode is not present, a value of "SRST" must be inferred. + // https://tools.ietf.org/html/rfc7798@section-7.1 + return "SRST"; +} + +bool IsSameH265TxMode(const webrtc::CodecParameterMap& left, + const webrtc::CodecParameterMap& right) { + return absl::EqualsIgnoreCase(GetH265TxModeOrDefault(left), + GetH265TxModeOrDefault(right)); +} +#endif + // Some (video) codecs are actually families of codecs and rely on parameters // to distinguish different incompatible family members. bool IsSameCodecSpecific(const std::string& name1, - const CodecParameterMap& params1, + const webrtc::CodecParameterMap& params1, const std::string& name2, - const CodecParameterMap& params2) { + const webrtc::CodecParameterMap& params2) { // The names might not necessarily match, so check both. auto either_name_matches = [&](const std::string name) { return absl::EqualsIgnoreCase(name, name1) || @@ -59,6 +81,12 @@ bool IsSameCodecSpecific(const std::string& name1, return webrtc::VP9IsSameProfile(params1, params2); if (either_name_matches(kAv1CodecName)) return webrtc::AV1IsSameProfile(params1, params2); +#ifdef RTC_ENABLE_H265 + if (either_name_matches(kH265CodecName)) { + return webrtc::H265IsSameProfileTierLevel(params1, params2) && + IsSameH265TxMode(params1, params2); + } +#endif return true; } @@ -222,7 +250,7 @@ bool Codec::MatchesRtpCodec(const webrtc::RtpCodec& codec_capability) const { } bool Codec::GetParam(const std::string& name, std::string* out) const { - CodecParameterMap::const_iterator iter = params.find(name); + webrtc::CodecParameterMap::const_iterator iter = params.find(name); if (iter == params.end()) return false; *out = iter->second; @@ -230,7 +258,7 @@ bool Codec::GetParam(const std::string& name, std::string* out) const { } bool Codec::GetParam(const std::string& name, int* out) const { - CodecParameterMap::const_iterator iter = params.find(name); + webrtc::CodecParameterMap::const_iterator iter = params.find(name); if (iter == params.end()) return false; return rtc::FromString(iter->second, out); @@ -283,7 +311,8 @@ webrtc::RtpCodecParameters Codec::ToCodecParameters() const { } bool Codec::IsMediaCodec() const { - return !IsResiliencyCodec(); + return !IsResiliencyCodec() && + !absl::EqualsIgnoreCase(name, kComfortNoiseCodecName); } bool Codec::IsResiliencyCodec() const { diff --git a/third_party/libwebrtc/media/base/codec.h b/third_party/libwebrtc/media/base/codec.h index bd4239b251..f586f78973 100644 --- a/third_party/libwebrtc/media/base/codec.h +++ b/third_party/libwebrtc/media/base/codec.h @@ -27,8 +27,6 @@ namespace cricket { -using CodecParameterMap = std::map; - class FeedbackParam { public: FeedbackParam() = default; @@ -98,9 +96,12 @@ struct RTC_EXPORT Codec { absl::InlinedVector scalability_modes; + // H.265 only + absl::optional tx_mode; + // Non key-value parameters such as the telephone-event "0‐15" are // represented using an empty string as key, i.e. {"": "0-15"}. - CodecParameterMap params; + webrtc::CodecParameterMap params; FeedbackParams feedback_params; Codec(const Codec& c); @@ -110,7 +111,9 @@ struct RTC_EXPORT Codec { // Indicates if this codec is compatible with the specified codec by // checking the assigned id and profile values for the relevant video codecs. - // H264 levels are not compared. + // For H.264, packetization modes will be compared; If H.265 is enabled, + // TxModes will be compared. + // H.264(and H.265, if enabled) levels are not compared. bool Matches(const Codec& codec) const; bool MatchesRtpCodec(const webrtc::RtpCodec& capability) const; diff --git a/third_party/libwebrtc/media/base/codec_unittest.cc b/third_party/libwebrtc/media/base/codec_unittest.cc index eb34530c38..4dc3b18c21 100644 --- a/third_party/libwebrtc/media/base/codec_unittest.cc +++ b/third_party/libwebrtc/media/base/codec_unittest.cc @@ -342,6 +342,67 @@ TEST(CodecTest, TestH264CodecMatches) { } } +#ifdef RTC_ENABLE_H265 +// Matching H.265 codecs should have matching profile/tier/level and tx-mode. +TEST(CodecTest, TestH265CodecMatches) { + constexpr char kProfile1[] = "1"; + constexpr char kTier1[] = "1"; + constexpr char kLevel3_1[] = "93"; + constexpr char kLevel4[] = "120"; + constexpr char kTxMrst[] = "MRST"; + + VideoCodec c_ptl_blank = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + + { + VideoCodec c_profile_1 = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_profile_1.params[cricket::kH265FmtpProfileId] = kProfile1; + + // Matches since profile-id unspecified defaults to "1". + EXPECT_TRUE(c_ptl_blank.Matches(c_profile_1)); + } + + { + VideoCodec c_tier_flag_1 = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_tier_flag_1.params[cricket::kH265FmtpTierFlag] = kTier1; + + // Does not match since profile-space unspecified defaults to "0". + EXPECT_FALSE(c_ptl_blank.Matches(c_tier_flag_1)); + } + + { + VideoCodec c_level_id_3_1 = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_level_id_3_1.params[cricket::kH265FmtpLevelId] = kLevel3_1; + + // Matches since level-id unspecified defautls to "93". + EXPECT_TRUE(c_ptl_blank.Matches(c_level_id_3_1)); + } + + { + VideoCodec c_level_id_4 = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_level_id_4.params[cricket::kH265FmtpLevelId] = kLevel4; + + // Does not match since different level-ids are specified. + EXPECT_FALSE(c_ptl_blank.Matches(c_level_id_4)); + } + + { + VideoCodec c_tx_mode_mrst = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_tx_mode_mrst.params[cricket::kH265FmtpTxMode] = kTxMrst; + + // Does not match since tx-mode implies to "SRST" and must be not specified + // when it is the only mode supported: + // https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-hevc-webrtc + EXPECT_FALSE(c_ptl_blank.Matches(c_tx_mode_mrst)); + } +} +#endif + TEST(CodecTest, TestSetParamGetParamAndRemoveParam) { AudioCodec codec = cricket::CreateAudioCodec(0, "foo", 22222, 2); codec.SetParam("a", "1"); diff --git a/third_party/libwebrtc/media/base/media_channel_impl.cc b/third_party/libwebrtc/media/base/media_channel_impl.cc index 5b41a9ccda..ff69ea62dc 100644 --- a/third_party/libwebrtc/media/base/media_channel_impl.cc +++ b/third_party/libwebrtc/media/base/media_channel_impl.cc @@ -58,18 +58,6 @@ int MediaChannelUtil::GetRtpSendTimeExtnId() const { return -1; } -void MediaChannelUtil::SetFrameEncryptor( - uint32_t ssrc, - rtc::scoped_refptr frame_encryptor) { - // Placeholder should be pure virtual once internal supports it. -} - -void MediaChannelUtil::SetFrameDecryptor( - uint32_t ssrc, - rtc::scoped_refptr frame_decryptor) { - // Placeholder should be pure virtual once internal supports it. -} - bool MediaChannelUtil::SendPacket(rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options) { return transport_.DoSendPacket(packet, false, options); @@ -102,14 +90,6 @@ bool MediaChannelUtil::HasNetworkInterface() const { return transport_.HasNetworkInterface(); } -void MediaChannelUtil::SetEncoderToPacketizerFrameTransformer( - uint32_t ssrc, - rtc::scoped_refptr frame_transformer) {} - -void MediaChannelUtil::SetDepacketizerToDecoderFrameTransformer( - uint32_t ssrc, - rtc::scoped_refptr frame_transformer) {} - bool MediaChannelUtil::DscpEnabled() const { return transport_.DscpEnabled(); } diff --git a/third_party/libwebrtc/media/base/media_channel_impl.h b/third_party/libwebrtc/media/base/media_channel_impl.h index f8c8174efa..eda47af568 100644 --- a/third_party/libwebrtc/media/base/media_channel_impl.h +++ b/third_party/libwebrtc/media/base/media_channel_impl.h @@ -106,20 +106,6 @@ class MediaChannelUtil { // Must be called on the network thread. bool HasNetworkInterface() const; - void SetFrameEncryptor( - uint32_t ssrc, - rtc::scoped_refptr frame_encryptor); - void SetFrameDecryptor( - uint32_t ssrc, - rtc::scoped_refptr frame_decryptor); - - void SetEncoderToPacketizerFrameTransformer( - uint32_t ssrc, - rtc::scoped_refptr frame_transformer); - void SetDepacketizerToDecoderFrameTransformer( - uint32_t ssrc, - rtc::scoped_refptr frame_transformer); - protected: bool DscpEnabled() const; diff --git a/third_party/libwebrtc/media/base/sdp_video_format_utils.cc b/third_party/libwebrtc/media/base/sdp_video_format_utils.cc index a156afdc02..2b756ba734 100644 --- a/third_party/libwebrtc/media/base/sdp_video_format_utils.cc +++ b/third_party/libwebrtc/media/base/sdp_video_format_utils.cc @@ -15,6 +15,9 @@ #include #include "api/video_codecs/h264_profile_level_id.h" +#ifdef RTC_ENABLE_H265 +#include "api/video_codecs/h265_profile_tier_level.h" +#endif #include "rtc_base/checks.h" #include "rtc_base/string_to_number.h" @@ -27,8 +30,13 @@ const char kVPxFmtpMaxFrameRate[] = "max-fr"; // Max frame size for VP8 and VP9 video. const char kVPxFmtpMaxFrameSize[] = "max-fs"; const int kVPxFmtpFrameSizeSubBlockPixels = 256; +#ifdef RTC_ENABLE_H265 +constexpr char kH265ProfileId[] = "profile-id"; +constexpr char kH265TierFlag[] = "tier-flag"; +constexpr char kH265LevelId[] = "level-id"; +#endif -bool IsH264LevelAsymmetryAllowed(const SdpVideoFormat::Parameters& params) { +bool IsH264LevelAsymmetryAllowed(const CodecParameterMap& params) { const auto it = params.find(kH264LevelAsymmetryAllowed); return it != params.end() && strcmp(it->second.c_str(), "1") == 0; } @@ -47,7 +55,7 @@ H264Level H264LevelMin(H264Level a, H264Level b) { } absl::optional ParsePositiveNumberFromParams( - const SdpVideoFormat::Parameters& params, + const CodecParameterMap& params, const char* parameter_name) { const auto max_frame_rate_it = params.find(parameter_name); if (max_frame_rate_it == params.end()) @@ -60,13 +68,64 @@ absl::optional ParsePositiveNumberFromParams( return i; } +#ifdef RTC_ENABLE_H265 +// Compares two H265Level and return the smaller. +H265Level H265LevelMin(H265Level a, H265Level b) { + return a <= b ? a : b; +} + +// Returns true if none of profile-id/tier-flag/level-id is specified +// explicitly in the param. +bool IsDefaultH265PTL(const CodecParameterMap& params) { + return !params.count(kH265ProfileId) && !params.count(kH265TierFlag) && + !params.count(kH265LevelId); +} +#endif + } // namespace +#ifdef RTC_ENABLE_H265 +// Set level according to https://tools.ietf.org/html/rfc7798#section-7.1 +void H265GenerateProfileTierLevelForAnswer( + const CodecParameterMap& local_supported_params, + const CodecParameterMap& remote_offered_params, + CodecParameterMap* answer_params) { + // If local and remote haven't set profile-id/tier-flag/level-id, they + // are both using the default PTL In this case, don't set PTL in answer + // either. + if (IsDefaultH265PTL(local_supported_params) && + IsDefaultH265PTL(remote_offered_params)) { + return; + } + + // Parse profile-tier-level. + const absl::optional local_profile_tier_level = + ParseSdpForH265ProfileTierLevel(local_supported_params); + const absl::optional remote_profile_tier_level = + ParseSdpForH265ProfileTierLevel(remote_offered_params); + // Profile and tier for local and remote codec must be valid and equal. + RTC_DCHECK(local_profile_tier_level); + RTC_DCHECK(remote_profile_tier_level); + RTC_DCHECK_EQ(local_profile_tier_level->profile, + remote_profile_tier_level->profile); + RTC_DCHECK_EQ(local_profile_tier_level->tier, + remote_profile_tier_level->tier); + + const H265Level answer_level = H265LevelMin(local_profile_tier_level->level, + remote_profile_tier_level->level); + + // Level-id in answer is changable as long as the highest level indicated by + // the answer is not higher than that indicated by the offer. See + // https://tools.ietf.org/html/rfc7798#section-7.2.2, sub-clause 2. + (*answer_params)[kH265LevelId] = H265LevelToString(answer_level); +} +#endif + // Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2. void H264GenerateProfileLevelIdForAnswer( - const SdpVideoFormat::Parameters& local_supported_params, - const SdpVideoFormat::Parameters& remote_offered_params, - SdpVideoFormat::Parameters* answer_params) { + const CodecParameterMap& local_supported_params, + const CodecParameterMap& remote_offered_params, + CodecParameterMap* answer_params) { // If both local and remote haven't set profile-level-id, they are both using // the default profile. In this case, don't set profile-level-id in answer // either. @@ -106,12 +165,12 @@ void H264GenerateProfileLevelIdForAnswer( } absl::optional ParseSdpForVPxMaxFrameRate( - const SdpVideoFormat::Parameters& params) { + const CodecParameterMap& params) { return ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameRate); } absl::optional ParseSdpForVPxMaxFrameSize( - const SdpVideoFormat::Parameters& params) { + const CodecParameterMap& params) { const absl::optional i = ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameSize); return i ? absl::make_optional(i.value() * kVPxFmtpFrameSizeSubBlockPixels) diff --git a/third_party/libwebrtc/media/base/sdp_video_format_utils.h b/third_party/libwebrtc/media/base/sdp_video_format_utils.h index 80c1e4d501..931caa8a29 100644 --- a/third_party/libwebrtc/media/base/sdp_video_format_utils.h +++ b/third_party/libwebrtc/media/base/sdp_video_format_utils.h @@ -32,20 +32,30 @@ namespace webrtc { // parameters that are used when negotiating are the level part of // profile-level-id and level-asymmetry-allowed. void H264GenerateProfileLevelIdForAnswer( - const SdpVideoFormat::Parameters& local_supported_params, - const SdpVideoFormat::Parameters& remote_offered_params, - SdpVideoFormat::Parameters* answer_params); + const CodecParameterMap& local_supported_params, + const CodecParameterMap& remote_offered_params, + CodecParameterMap* answer_params); + +#ifdef RTC_ENABLE_H265 +// Works similarly as H264GenerateProfileLevelIdForAnswer, but generates codec +// parameters that will be used as answer for H.265. +// Media configuration parameters, except level-id, must be used symmetrically. +// For level-id, the highest level indicated by the answer must not be higher +// than that indicated by the offer. +void H265GenerateProfileTierLevelForAnswer( + const CodecParameterMap& local_supported_params, + const CodecParameterMap& remote_offered_params, + CodecParameterMap* answer_params); +#endif // Parse max frame rate from SDP FMTP line. absl::nullopt is returned if the // field is missing or not a number. -absl::optional ParseSdpForVPxMaxFrameRate( - const SdpVideoFormat::Parameters& params); +absl::optional ParseSdpForVPxMaxFrameRate(const CodecParameterMap& params); // Parse max frame size from SDP FMTP line. absl::nullopt is returned if the // field is missing or not a number. Please note that the value is stored in sub // blocks but the returned value is in total number of pixels. -absl::optional ParseSdpForVPxMaxFrameSize( - const SdpVideoFormat::Parameters& params); +absl::optional ParseSdpForVPxMaxFrameSize(const CodecParameterMap& params); } // namespace webrtc diff --git a/third_party/libwebrtc/media/base/sdp_video_format_utils_unittest.cc b/third_party/libwebrtc/media/base/sdp_video_format_utils_unittest.cc index d8ef9ab827..9f505c19d7 100644 --- a/third_party/libwebrtc/media/base/sdp_video_format_utils_unittest.cc +++ b/third_party/libwebrtc/media/base/sdp_video_format_utils_unittest.cc @@ -27,29 +27,28 @@ const char kVPxFmtpMaxFrameSize[] = "max-fs"; } // namespace TEST(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerEmpty) { - SdpVideoFormat::Parameters answer_params; - H264GenerateProfileLevelIdForAnswer(SdpVideoFormat::Parameters(), - SdpVideoFormat::Parameters(), + CodecParameterMap answer_params; + H264GenerateProfileLevelIdForAnswer(CodecParameterMap(), CodecParameterMap(), &answer_params); EXPECT_TRUE(answer_params.empty()); } TEST(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerLevelSymmetryCapped) { - SdpVideoFormat::Parameters low_level; + CodecParameterMap low_level; low_level["profile-level-id"] = "42e015"; - SdpVideoFormat::Parameters high_level; + CodecParameterMap high_level; high_level["profile-level-id"] = "42e01f"; // Level asymmetry is not allowed; test that answer level is the lower of the // local and remote levels. - SdpVideoFormat::Parameters answer_params; + CodecParameterMap answer_params; H264GenerateProfileLevelIdForAnswer(low_level /* local_supported */, high_level /* remote_offered */, &answer_params); EXPECT_EQ("42e015", answer_params["profile-level-id"]); - SdpVideoFormat::Parameters answer_params2; + CodecParameterMap answer_params2; H264GenerateProfileLevelIdForAnswer(high_level /* local_supported */, low_level /* remote_offered */, &answer_params2); @@ -58,13 +57,13 @@ TEST(SdpVideoFormatUtilsTest, TEST(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerConstrainedBaselineLevelAsymmetry) { - SdpVideoFormat::Parameters local_params; + CodecParameterMap local_params; local_params["profile-level-id"] = "42e01f"; local_params["level-asymmetry-allowed"] = "1"; - SdpVideoFormat::Parameters remote_params; + CodecParameterMap remote_params; remote_params["profile-level-id"] = "42e015"; remote_params["level-asymmetry-allowed"] = "1"; - SdpVideoFormat::Parameters answer_params; + CodecParameterMap answer_params; H264GenerateProfileLevelIdForAnswer(local_params, remote_params, &answer_params); // When level asymmetry is allowed, we can answer a higher level than what was @@ -72,8 +71,38 @@ TEST(SdpVideoFormatUtilsTest, EXPECT_EQ("42e01f", answer_params["profile-level-id"]); } +#ifdef RTC_ENABLE_H265 +// Answer should not include explicit PTL info if neither local nor remote set +// any of them. +TEST(SdpVideoFormatUtilsTest, H265GenerateProfileTierLevelEmpty) { + CodecParameterMap answer_params; + H265GenerateProfileTierLevelForAnswer(CodecParameterMap(), + CodecParameterMap(), &answer_params); + EXPECT_TRUE(answer_params.empty()); +} + +// Answer must use the minimum level as supported by both local and remote. +TEST(SdpVideoFormatUtilsTest, H265GenerateProfileTierLevelNoEmpty) { + constexpr char kLocallySupportedLevelId[] = "93"; + constexpr char kRemoteOfferedLevelId[] = "120"; + + CodecParameterMap local_params; + local_params["profile-id"] = "1"; + local_params["tier-flag"] = "0"; + local_params["level-id"] = kLocallySupportedLevelId; + CodecParameterMap remote_params; + remote_params["profile-id"] = "1"; + remote_params["tier-flag"] = "0"; + remote_params["level-id"] = kRemoteOfferedLevelId; + CodecParameterMap answer_params; + H265GenerateProfileTierLevelForAnswer(local_params, remote_params, + &answer_params); + EXPECT_EQ(kLocallySupportedLevelId, answer_params["level-id"]); +} +#endif + TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsMissingOrInvalid) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; absl::optional empty = ParseSdpForVPxMaxFrameRate(params); EXPECT_FALSE(empty); params[kVPxFmtpMaxFrameRate] = "-1"; @@ -85,7 +114,7 @@ TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsMissingOrInvalid) { } TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsSpecified) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; params[kVPxFmtpMaxFrameRate] = "30"; EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 30); params[kVPxFmtpMaxFrameRate] = "60"; @@ -93,7 +122,7 @@ TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsSpecified) { } TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsMissingOrInvalid) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; absl::optional empty = ParseSdpForVPxMaxFrameSize(params); EXPECT_FALSE(empty); params[kVPxFmtpMaxFrameSize] = "-1"; @@ -105,7 +134,7 @@ TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsMissingOrInvalid) { } TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsSpecified) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; params[kVPxFmtpMaxFrameSize] = "8100"; // 1920 x 1080 / (16^2) EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 1920 * 1080); params[kVPxFmtpMaxFrameSize] = "32400"; // 3840 x 2160 / (16^2) diff --git a/third_party/libwebrtc/media/engine/internal_decoder_factory_unittest.cc b/third_party/libwebrtc/media/engine/internal_decoder_factory_unittest.cc index bb2e24d5d8..51d6a94dd6 100644 --- a/third_party/libwebrtc/media/engine/internal_decoder_factory_unittest.cc +++ b/third_party/libwebrtc/media/engine/internal_decoder_factory_unittest.cc @@ -43,6 +43,8 @@ constexpr bool kDav1dIsIncluded = true; #else constexpr bool kDav1dIsIncluded = false; #endif +constexpr bool kH265Enabled = false; + constexpr VideoDecoderFactory::CodecSupport kSupported = { /*is_supported=*/true, /*is_power_efficient=*/false}; constexpr VideoDecoderFactory::CodecSupport kUnsupported = { @@ -99,6 +101,14 @@ TEST(InternalDecoderFactoryTest, Av1Profile0) { } } +// At current stage since internal H.265 decoder is not implemented, +TEST(InternalDecoderFactoryTest, H265IsNotEnabled) { + InternalDecoderFactory factory; + std::unique_ptr decoder = + factory.CreateVideoDecoder(SdpVideoFormat(cricket::kH265CodecName)); + EXPECT_EQ(static_cast(decoder), kH265Enabled); +} + #if defined(RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY) TEST(InternalDecoderFactoryTest, Av1) { InternalDecoderFactory factory; diff --git a/third_party/libwebrtc/media/engine/internal_encoder_factory_unittest.cc b/third_party/libwebrtc/media/engine/internal_encoder_factory_unittest.cc index a1c90b8cf4..b9ca6d88c2 100644 --- a/third_party/libwebrtc/media/engine/internal_encoder_factory_unittest.cc +++ b/third_party/libwebrtc/media/engine/internal_encoder_factory_unittest.cc @@ -33,6 +33,8 @@ constexpr bool kH264Enabled = true; #else constexpr bool kH264Enabled = false; #endif +constexpr bool kH265Enabled = false; + constexpr VideoEncoderFactory::CodecSupport kSupported = { /*is_supported=*/true, /*is_power_efficient=*/false}; constexpr VideoEncoderFactory::CodecSupport kUnsupported = { @@ -78,6 +80,17 @@ TEST(InternalEncoderFactoryTest, H264) { } } +// At current stage H.265 is not supported by internal encoder factory. +TEST(InternalEncoderFactoryTest, H265IsNotEnabled) { + InternalEncoderFactory factory; + std::unique_ptr encoder = + factory.CreateVideoEncoder(SdpVideoFormat(cricket::kH265CodecName)); + EXPECT_EQ(static_cast(encoder), kH265Enabled); + EXPECT_THAT( + factory.GetSupportedFormats(), + Not(Contains(Field(&SdpVideoFormat::name, cricket::kH265CodecName)))); +} + TEST(InternalEncoderFactoryTest, QueryCodecSupportWithScalabilityMode) { InternalEncoderFactory factory; // VP8 and VP9 supported for singles spatial layers. diff --git a/third_party/libwebrtc/media/engine/simulcast_encoder_adapter_unittest.cc b/third_party/libwebrtc/media/engine/simulcast_encoder_adapter_unittest.cc index e2ac5ea390..3ee3465e13 100644 --- a/third_party/libwebrtc/media/engine/simulcast_encoder_adapter_unittest.cc +++ b/third_party/libwebrtc/media/engine/simulcast_encoder_adapter_unittest.cc @@ -586,7 +586,7 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, absl::optional last_encoded_image_simulcast_index_; std::unique_ptr rate_allocator_; bool use_fallback_factory_; - SdpVideoFormat::Parameters sdp_video_parameters_; + CodecParameterMap sdp_video_parameters_; test::ScopedKeyValueConfig field_trials_; }; diff --git a/third_party/libwebrtc/media/engine/webrtc_media_engine.cc b/third_party/libwebrtc/media/engine/webrtc_media_engine.cc index 463ed29109..31769e05de 100644 --- a/third_party/libwebrtc/media/engine/webrtc_media_engine.cc +++ b/third_party/libwebrtc/media/engine/webrtc_media_engine.cc @@ -12,53 +12,16 @@ #include #include -#include #include #include #include "absl/algorithm/container.h" #include "absl/strings/match.h" -#include "api/transport/field_trial_based_config.h" #include "media/base/media_constants.h" -#include "media/engine/webrtc_voice_engine.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" -#ifdef HAVE_WEBRTC_VIDEO -#include "media/engine/webrtc_video_engine.h" -#else -#include "media/engine/null_webrtc_video_engine.h" -#endif - namespace cricket { - -std::unique_ptr CreateMediaEngine( - MediaEngineDependencies dependencies) { - // TODO(sprang): Make populating `dependencies.trials` mandatory and remove - // these fallbacks. - std::unique_ptr fallback_trials( - dependencies.trials ? nullptr : new webrtc::FieldTrialBasedConfig()); - const webrtc::FieldTrialsView& trials = - dependencies.trials ? *dependencies.trials : *fallback_trials; - auto audio_engine = std::make_unique( - dependencies.task_queue_factory, dependencies.adm.get(), - std::move(dependencies.audio_encoder_factory), - std::move(dependencies.audio_decoder_factory), - std::move(dependencies.audio_mixer), - std::move(dependencies.audio_processing), - std::move(dependencies.owned_audio_frame_processor), trials); -#ifdef HAVE_WEBRTC_VIDEO - auto video_engine = std::make_unique( - std::move(dependencies.video_encoder_factory), - std::move(dependencies.video_decoder_factory), trials); -#else - auto video_engine = std::make_unique(); -#endif - return std::make_unique(std::move(fallback_trials), - std::move(audio_engine), - std::move(video_engine)); -} - namespace { // Remove mutually exclusive extensions with lower priority. void DiscardRedundantExtensions( diff --git a/third_party/libwebrtc/media/engine/webrtc_media_engine.h b/third_party/libwebrtc/media/engine/webrtc_media_engine.h index 863db9f278..5bd5a8bce5 100644 --- a/third_party/libwebrtc/media/engine/webrtc_media_engine.h +++ b/third_party/libwebrtc/media/engine/webrtc_media_engine.h @@ -11,59 +11,17 @@ #ifndef MEDIA_ENGINE_WEBRTC_MEDIA_ENGINE_H_ #define MEDIA_ENGINE_WEBRTC_MEDIA_ENGINE_H_ -#include #include #include "absl/strings/string_view.h" #include "api/array_view.h" -#include "api/audio/audio_frame_processor.h" -#include "api/audio/audio_mixer.h" -#include "api/audio_codecs/audio_decoder_factory.h" -#include "api/audio_codecs/audio_encoder_factory.h" #include "api/field_trials_view.h" #include "api/rtp_parameters.h" -#include "api/scoped_refptr.h" -#include "api/task_queue/task_queue_factory.h" #include "api/transport/bitrate_settings.h" -#include "api/video_codecs/video_decoder_factory.h" -#include "api/video_codecs/video_encoder_factory.h" #include "media/base/codec.h" -#include "media/base/media_engine.h" -#include "modules/audio_device/include/audio_device.h" -#include "modules/audio_processing/include/audio_processing.h" -#include "rtc_base/system/rtc_export.h" namespace cricket { -struct MediaEngineDependencies { - MediaEngineDependencies() = default; - MediaEngineDependencies(const MediaEngineDependencies&) = delete; - MediaEngineDependencies(MediaEngineDependencies&&) = default; - MediaEngineDependencies& operator=(const MediaEngineDependencies&) = delete; - MediaEngineDependencies& operator=(MediaEngineDependencies&&) = default; - ~MediaEngineDependencies() = default; - - webrtc::TaskQueueFactory* task_queue_factory = nullptr; - rtc::scoped_refptr adm; - rtc::scoped_refptr audio_encoder_factory; - rtc::scoped_refptr audio_decoder_factory; - rtc::scoped_refptr audio_mixer; - rtc::scoped_refptr audio_processing; - std::unique_ptr owned_audio_frame_processor; - - std::unique_ptr video_encoder_factory; - std::unique_ptr video_decoder_factory; - - const webrtc::FieldTrialsView* trials = nullptr; -}; - -// CreateMediaEngine may be called on any thread, though the engine is -// only expected to be used on one thread, internally called the "worker -// thread". This is the thread Init must be called on. -[[deprecated("bugs.webrtc.org/15574")]] // -RTC_EXPORT std::unique_ptr -CreateMediaEngine(MediaEngineDependencies dependencies); - // Verify that extension IDs are within 1-byte extension range and are not // overlapping, and that they form a legal change from previously registerd // extensions (if any). diff --git a/third_party/libwebrtc/media/engine/webrtc_video_engine.cc b/third_party/libwebrtc/media/engine/webrtc_video_engine.cc index 8a9d6ff95c..a5b46d3344 100644 --- a/third_party/libwebrtc/media/engine/webrtc_video_engine.cc +++ b/third_party/libwebrtc/media/engine/webrtc_video_engine.cc @@ -1038,13 +1038,19 @@ bool WebRtcVideoSendChannel::GetChangedSenderParameters( return false; } + std::vector mapped_codecs = MapCodecs(params.codecs); + if (mapped_codecs.empty()) { + // This suggests a failure in MapCodecs, e.g. inconsistent RTX codecs. + return false; + } + std::vector negotiated_codecs = - SelectSendVideoCodecs(MapCodecs(params.codecs)); + SelectSendVideoCodecs(mapped_codecs); - // We should only fail here if send direction is enabled. if (params.is_stream_active && negotiated_codecs.empty()) { - RTC_LOG(LS_ERROR) << "No video codecs supported."; - return false; + // This is not a failure but will lead to the answer being rejected. + RTC_LOG(LS_ERROR) << "No video codecs in common."; + return true; } // Never enable sending FlexFEC, unless we are in the experiment. diff --git a/third_party/libwebrtc/media/engine/webrtc_video_engine_unittest.cc b/third_party/libwebrtc/media/engine/webrtc_video_engine_unittest.cc index f5736679be..148223f497 100644 --- a/third_party/libwebrtc/media/engine/webrtc_video_engine_unittest.cc +++ b/third_party/libwebrtc/media/engine/webrtc_video_engine_unittest.cc @@ -3781,7 +3781,7 @@ class Vp9SettingsTest : public WebRtcVideoChannelTest { TEST_F(Vp9SettingsTest, VerifyVp9SpecificSettings) { encoder_factory_->AddSupportedVideoCodec( - webrtc::SdpVideoFormat("VP9", webrtc::SdpVideoFormat::Parameters(), + webrtc::SdpVideoFormat("VP9", webrtc::CodecParameterMap(), {ScalabilityMode::kL1T1, ScalabilityMode::kL2T1})); cricket::VideoSenderParameters parameters; @@ -8545,7 +8545,7 @@ TEST_F(WebRtcVideoChannelTest, FallbackForUnsetOrUnsupportedScalabilityMode) { ScalabilityMode::kL1T3}; encoder_factory_->AddSupportedVideoCodec(webrtc::SdpVideoFormat( - "VP8", webrtc::SdpVideoFormat::Parameters(), kSupportedModes)); + "VP8", webrtc::CodecParameterMap(), kSupportedModes)); FakeVideoSendStream* stream = SetUpSimulcast(true, /*with_rtx=*/false); @@ -8615,9 +8615,9 @@ TEST_F(WebRtcVideoChannelTest, kVp9SupportedModes = {ScalabilityMode::kL3T3}; encoder_factory_->AddSupportedVideoCodec(webrtc::SdpVideoFormat( - "VP8", webrtc::SdpVideoFormat::Parameters(), {ScalabilityMode::kL1T1})); + "VP8", webrtc::CodecParameterMap(), {ScalabilityMode::kL1T1})); encoder_factory_->AddSupportedVideoCodec(webrtc::SdpVideoFormat( - "VP9", webrtc::SdpVideoFormat::Parameters(), {ScalabilityMode::kL3T3})); + "VP9", webrtc::CodecParameterMap(), {ScalabilityMode::kL3T3})); cricket::VideoSenderParameters send_parameters; send_parameters.codecs.push_back(GetEngineCodec("VP9")); diff --git a/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc b/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc index adf662074d..fcc2703f98 100644 --- a/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc +++ b/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc @@ -377,9 +377,8 @@ void WebRtcVoiceEngine::Init() { // TaskQueue expects to be created/destroyed on the same thread. RTC_DCHECK(!low_priority_worker_queue_); - low_priority_worker_queue_.reset( - new rtc::TaskQueue(task_queue_factory_->CreateTaskQueue( - "rtc-low-prio", webrtc::TaskQueueFactory::Priority::LOW))); + low_priority_worker_queue_ = task_queue_factory_->CreateTaskQueue( + "rtc-low-prio", webrtc::TaskQueueFactory::Priority::LOW); // Load our audio codec lists. RTC_LOG(LS_VERBOSE) << "Supported send codecs in order of preference:"; @@ -761,9 +760,9 @@ std::vector WebRtcVoiceEngine::CollectCodecs( out.push_back(codec); if (codec.name == kOpusCodecName) { - std::string redFmtp = + std::string red_fmtp = rtc::ToString(codec.id) + "/" + rtc::ToString(codec.id); - map_format({kRedCodecName, 48000, 2, {{"", redFmtp}}}, &out); + map_format({kRedCodecName, 48000, 2, {{"", red_fmtp}}}, &out); } } } @@ -1318,7 +1317,7 @@ bool WebRtcVoiceSendChannel::SetSenderParameters( } } - if (!SetMaxSendBitrate(params.max_bandwidth_bps)) { + if (send_codec_spec_ && !SetMaxSendBitrate(params.max_bandwidth_bps)) { return false; } return SetOptions(params.options); @@ -1402,7 +1401,8 @@ bool WebRtcVoiceSendChannel::SetSendCodecs( } if (!send_codec_spec) { - return false; + // No codecs in common, bail out early. + return true; } RTC_DCHECK(voice_codec_info); diff --git a/third_party/libwebrtc/media/engine/webrtc_voice_engine.h b/third_party/libwebrtc/media/engine/webrtc_voice_engine.h index ed71667525..b28b9652bb 100644 --- a/third_party/libwebrtc/media/engine/webrtc_voice_engine.h +++ b/third_party/libwebrtc/media/engine/webrtc_voice_engine.h @@ -66,7 +66,6 @@ #include "rtc_base/network/sent_packet.h" #include "rtc_base/network_route.h" #include "rtc_base/system/file_wrapper.h" -#include "rtc_base/task_queue.h" namespace webrtc { class AudioFrameProcessor; @@ -141,7 +140,8 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface { void ApplyOptions(const AudioOptions& options); webrtc::TaskQueueFactory* const task_queue_factory_; - std::unique_ptr low_priority_worker_queue_; + std::unique_ptr + low_priority_worker_queue_; webrtc::AudioDeviceModule* adm(); webrtc::AudioProcessing* apm() const; diff --git a/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc b/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc index 4d6580631d..8ae441bc69 100644 --- a/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc +++ b/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc @@ -1702,27 +1702,29 @@ TEST_P(WebRtcVoiceEngineTestFake, DontRecreateSendStream) { // TODO(ossu): Revisit if these tests need to be here, now that these kinds of // tests should be available in AudioEncoderOpusTest. -// Test that if clockrate is not 48000 for opus, we fail. +// Test that if clockrate is not 48000 for opus, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBadClockrate) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; parameters.codecs.push_back(kOpusCodec); parameters.codecs[0].bitrate = 0; parameters.codecs[0].clockrate = 50000; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channels=0 for opus, we fail. +// Test that if channels=0 for opus, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad0ChannelsNoStereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; parameters.codecs.push_back(kOpusCodec); parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 0; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channels=0 for opus, we fail. +// Test that if channels=0 for opus, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad0Channels1Stereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; @@ -1730,20 +1732,23 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad0Channels1Stereo) { parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 0; parameters.codecs[0].params["stereo"] = "1"; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channel is 1 for opus and there's no stereo, we fail. +// Test that if channel is 1 for opus and there's no stereo, we do not have a +// send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpus1ChannelNoStereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; parameters.codecs.push_back(kOpusCodec); parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 1; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channel is 1 for opus and stereo=0, we fail. +// Test that if channel is 1 for opus and stereo=0, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel0Stereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; @@ -1751,10 +1756,11 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel0Stereo) { parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 1; parameters.codecs[0].params["stereo"] = "0"; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channel is 1 for opus and stereo=1, we fail. +// Test that if channel is 1 for opus and stereo=1, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel1Stereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; @@ -1762,7 +1768,8 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel1Stereo) { parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 1; parameters.codecs[0].params["stereo"] = "1"; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } // Test that with bitrate=0 and no stereo, bitrate is 32000. @@ -2035,11 +2042,12 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecsBitrate) { } } -// Test that we fail if no codecs are specified. +// Test that we do not fail if no codecs are specified. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecsNoCodecs) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } // Test that we can set send codecs even with telephone-event codec as the first diff --git a/third_party/libwebrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_unittest.cc b/third_party/libwebrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_unittest.cc index bd8d1cc341..998e78e1d3 100644 --- a/third_party/libwebrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_unittest.cc +++ b/third_party/libwebrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_unittest.cc @@ -146,7 +146,7 @@ TEST(AudioDecoderFactoryTest, CreateOpus) { for (int hz : {8000, 16000, 32000, 48000}) { for (int channels : {0, 1, 2, 3}) { for (std::string stereo : {"XX", "0", "1", "2"}) { - SdpAudioFormat::Parameters params; + CodecParameterMap params; if (stereo != "XX") { params["stereo"] = stereo; } diff --git a/third_party/libwebrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/third_party/libwebrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc index a2ebe43bbe..f82ef965db 100644 --- a/third_party/libwebrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc +++ b/third_party/libwebrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc @@ -39,7 +39,7 @@ constexpr int kDefaultOpusPacSize = 960; constexpr int64_t kInitialTimeUs = 12345678; AudioEncoderOpusConfig CreateConfigWithParameters( - const SdpAudioFormat::Parameters& params) { + const CodecParameterMap& params) { const SdpAudioFormat format("opus", 48000, 2, params); return *AudioEncoderOpus::SdpToConfig(format); } diff --git a/third_party/libwebrtc/modules/audio_coding/neteq/test/neteq_opus_quality_test.cc b/third_party/libwebrtc/modules/audio_coding/neteq/test/neteq_opus_quality_test.cc index 5a2df24ef6..eddacd3680 100644 --- a/third_party/libwebrtc/modules/audio_coding/neteq/test/neteq_opus_quality_test.cc +++ b/third_party/libwebrtc/modules/audio_coding/neteq/test/neteq_opus_quality_test.cc @@ -106,8 +106,8 @@ NetEqOpusQualityTest::NetEqOpusQualityTest() // Redefine decoder type if input is stereo. if (channels_ > 1) { - audio_format_ = SdpAudioFormat("opus", 48000, 2, - SdpAudioFormat::Parameters{{"stereo", "1"}}); + audio_format_ = + SdpAudioFormat("opus", 48000, 2, CodecParameterMap{{"stereo", "1"}}); } application_ = absl::GetFlag(FLAGS_application); } diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestStereo.cc b/third_party/libwebrtc/modules/audio_coding/test/TestStereo.cc index 94a1576026..1e65e4a219 100644 --- a/third_party/libwebrtc/modules/audio_coding/test/TestStereo.cc +++ b/third_party/libwebrtc/modules/audio_coding/test/TestStereo.cc @@ -469,7 +469,7 @@ void TestStereo::RegisterSendCodec(char side, : sampling_freq_hz; const std::string ptime = rtc::ToString(rtc::CheckedDivExact( pack_size, rtc::CheckedDivExact(sampling_freq_hz, 1000))); - SdpAudioFormat::Parameters params = {{"ptime", ptime}}; + CodecParameterMap params = {{"ptime", ptime}}; RTC_CHECK(channels == 1 || channels == 2); if (absl::EqualsIgnoreCase(codec_name, "opus")) { if (channels == 2) { diff --git a/third_party/libwebrtc/modules/audio_device/BUILD.gn b/third_party/libwebrtc/modules/audio_device/BUILD.gn index a135f042db..1672be3f95 100644 --- a/third_party/libwebrtc/modules/audio_device/BUILD.gn +++ b/third_party/libwebrtc/modules/audio_device/BUILD.gn @@ -91,6 +91,7 @@ if (!build_with_mozilla) { # See Bug 1820869. "../../system_wrappers", "../../system_wrappers:metrics", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } } @@ -213,7 +214,6 @@ if (!build_with_chromium) { "../../rtc_base:platform_thread", "../../rtc_base:random", "../../rtc_base:rtc_event", - "../../rtc_base:rtc_task_queue", "../../rtc_base:safe_conversions", "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", @@ -461,6 +461,7 @@ rtc_source_set("mock_audio_device") { "../../api:make_ref_counted", "../../test:test_support", ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } } diff --git a/third_party/libwebrtc/modules/audio_device/fine_audio_buffer.cc b/third_party/libwebrtc/modules/audio_device/fine_audio_buffer.cc index 86240da196..f483b8dc79 100644 --- a/third_party/libwebrtc/modules/audio_device/fine_audio_buffer.cc +++ b/third_party/libwebrtc/modules/audio_device/fine_audio_buffer.cc @@ -13,6 +13,7 @@ #include #include +#include "api/array_view.h" #include "modules/audio_device/audio_device_buffer.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" @@ -107,7 +108,8 @@ void FineAudioBuffer::GetPlayoutData(rtc::ArrayView audio_buffer, void FineAudioBuffer::DeliverRecordedData( rtc::ArrayView audio_buffer, - int record_delay_ms) { + int record_delay_ms, + absl::optional capture_time_ns) { RTC_DCHECK(IsReadyForRecord()); // Always append new data and grow the buffer when needed. record_buffer_.AppendData(audio_buffer.data(), audio_buffer.size()); @@ -118,7 +120,8 @@ void FineAudioBuffer::DeliverRecordedData( record_channels_ * record_samples_per_channel_10ms_; while (record_buffer_.size() >= num_elements_10ms) { audio_device_buffer_->SetRecordedBuffer(record_buffer_.data(), - record_samples_per_channel_10ms_); + record_samples_per_channel_10ms_, + capture_time_ns); audio_device_buffer_->SetVQEData(playout_delay_ms_, record_delay_ms); audio_device_buffer_->DeliverRecordedData(); memmove(record_buffer_.data(), record_buffer_.data() + num_elements_10ms, diff --git a/third_party/libwebrtc/modules/audio_device/fine_audio_buffer.h b/third_party/libwebrtc/modules/audio_device/fine_audio_buffer.h index a6c3042bb2..7af41d3b21 100644 --- a/third_party/libwebrtc/modules/audio_device/fine_audio_buffer.h +++ b/third_party/libwebrtc/modules/audio_device/fine_audio_buffer.h @@ -11,6 +11,10 @@ #ifndef MODULES_AUDIO_DEVICE_FINE_AUDIO_BUFFER_H_ #define MODULES_AUDIO_DEVICE_FINE_AUDIO_BUFFER_H_ +#include +#include + +#include "absl/types/optional.h" #include "api/array_view.h" #include "rtc_base/buffer.h" @@ -61,7 +65,12 @@ class FineAudioBuffer { // 5ms of data and sends a total of 10ms to WebRTC and clears the internal // cache. Call #3 restarts the scheme above. void DeliverRecordedData(rtc::ArrayView audio_buffer, - int record_delay_ms); + int record_delay_ms) { + DeliverRecordedData(audio_buffer, record_delay_ms, absl::nullopt); + } + void DeliverRecordedData(rtc::ArrayView audio_buffer, + int record_delay_ms, + absl::optional capture_time_ns); private: // Device buffer that works with 10ms chunks of data both for playout and diff --git a/third_party/libwebrtc/modules/audio_device/fine_audio_buffer_unittest.cc b/third_party/libwebrtc/modules/audio_device/fine_audio_buffer_unittest.cc index 36ea85f7dd..bb9fe63922 100644 --- a/third_party/libwebrtc/modules/audio_device/fine_audio_buffer_unittest.cc +++ b/third_party/libwebrtc/modules/audio_device/fine_audio_buffer_unittest.cc @@ -113,7 +113,7 @@ void RunFineBufferTest(int frame_size_in_samples) { { InSequence s; for (int j = 0; j < kNumberOfUpdateBufferCalls - 1; ++j) { - EXPECT_CALL(audio_device_buffer, SetRecordedBuffer(_, kSamplesPer10Ms)) + EXPECT_CALL(audio_device_buffer, SetRecordedBuffer(_, kSamplesPer10Ms, _)) .WillOnce(VerifyInputBuffer(j, kChannels * kSamplesPer10Ms)) .RetiresOnSaturation(); } diff --git a/third_party/libwebrtc/modules/audio_device/include/test_audio_device.cc b/third_party/libwebrtc/modules/audio_device/include/test_audio_device.cc index 4c29c98f2c..b3923ae67d 100644 --- a/third_party/libwebrtc/modules/audio_device/include/test_audio_device.cc +++ b/third_party/libwebrtc/modules/audio_device/include/test_audio_device.cc @@ -21,6 +21,7 @@ #include "absl/strings/string_view.h" #include "api/array_view.h" #include "api/make_ref_counted.h" +#include "api/task_queue/task_queue_factory.h" #include "common_audio/wav_file.h" #include "modules/audio_device/audio_device_impl.h" #include "modules/audio_device/include/audio_device_default.h" @@ -33,7 +34,6 @@ #include "rtc_base/platform_thread.h" #include "rtc_base/random.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" #include "rtc_base/task_utils/repeating_task.h" #include "rtc_base/thread_annotations.h" #include "rtc_base/time_utils.h" diff --git a/third_party/libwebrtc/modules/audio_device/mock_audio_device_buffer.h b/third_party/libwebrtc/modules/audio_device/mock_audio_device_buffer.h index b0f54c20ff..0b276185da 100644 --- a/third_party/libwebrtc/modules/audio_device/mock_audio_device_buffer.h +++ b/third_party/libwebrtc/modules/audio_device/mock_audio_device_buffer.h @@ -11,6 +11,7 @@ #ifndef MODULES_AUDIO_DEVICE_MOCK_AUDIO_DEVICE_BUFFER_H_ #define MODULES_AUDIO_DEVICE_MOCK_AUDIO_DEVICE_BUFFER_H_ +#include "absl/types/optional.h" #include "modules/audio_device/audio_device_buffer.h" #include "test/gmock.h" @@ -24,7 +25,9 @@ class MockAudioDeviceBuffer : public AudioDeviceBuffer { MOCK_METHOD(int32_t, GetPlayoutData, (void* audioBuffer), (override)); MOCK_METHOD(int32_t, SetRecordedBuffer, - (const void* audioBuffer, size_t nSamples), + (const void* audioBuffer, + size_t nSamples, + absl::optional capture_time_ns), (override)); MOCK_METHOD(void, SetVQEData, (int playDelayMS, int recDelayMS), (override)); MOCK_METHOD(int32_t, DeliverRecordedData, (), (override)); diff --git a/third_party/libwebrtc/modules/audio_device/test_audio_device_impl.cc b/third_party/libwebrtc/modules/audio_device/test_audio_device_impl.cc index 627e68b36f..a3742ea581 100644 --- a/third_party/libwebrtc/modules/audio_device/test_audio_device_impl.cc +++ b/third_party/libwebrtc/modules/audio_device/test_audio_device_impl.cc @@ -19,7 +19,6 @@ #include "modules/audio_device/include/test_audio_device.h" #include "rtc_base/checks.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" #include "rtc_base/task_utils/repeating_task.h" namespace webrtc { @@ -59,11 +58,10 @@ TestAudioDevice::TestAudioDevice( } AudioDeviceGeneric::InitStatus TestAudioDevice::Init() { - task_queue_ = - std::make_unique(task_queue_factory_->CreateTaskQueue( - "TestAudioDeviceModuleImpl", TaskQueueFactory::Priority::NORMAL)); + task_queue_ = task_queue_factory_->CreateTaskQueue( + "TestAudioDeviceModuleImpl", TaskQueueFactory::Priority::NORMAL); - RepeatingTaskHandle::Start(task_queue_->Get(), [this]() { + RepeatingTaskHandle::Start(task_queue_.get(), [this]() { ProcessAudio(); return TimeDelta::Micros(process_interval_us_); }); diff --git a/third_party/libwebrtc/modules/audio_device/test_audio_device_impl.h b/third_party/libwebrtc/modules/audio_device/test_audio_device_impl.h index 36192b7f7f..84b48948ba 100644 --- a/third_party/libwebrtc/modules/audio_device/test_audio_device_impl.h +++ b/third_party/libwebrtc/modules/audio_device/test_audio_device_impl.h @@ -14,6 +14,7 @@ #include #include +#include "api/task_queue/task_queue_base.h" #include "api/task_queue/task_queue_factory.h" #include "modules/audio_device/audio_device_buffer.h" #include "modules/audio_device/audio_device_generic.h" @@ -22,7 +23,6 @@ #include "modules/audio_device/include/test_audio_device.h" #include "rtc_base/buffer.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" namespace webrtc { @@ -190,7 +190,7 @@ class TestAudioDevice : public AudioDeviceGeneric { std::vector playout_buffer_ RTC_GUARDED_BY(lock_); rtc::BufferT recording_buffer_ RTC_GUARDED_BY(lock_); - std::unique_ptr task_queue_; + std::unique_ptr task_queue_; }; } // namespace webrtc diff --git a/third_party/libwebrtc/modules/audio_processing/BUILD.gn b/third_party/libwebrtc/modules/audio_processing/BUILD.gn index 6aca7dee46..817a3515b0 100644 --- a/third_party/libwebrtc/modules/audio_processing/BUILD.gn +++ b/third_party/libwebrtc/modules/audio_processing/BUILD.gn @@ -34,6 +34,7 @@ rtc_library("api") { "../../api/audio:aec3_config", "../../api/audio:audio_frame_api", "../../api/audio:echo_control", + "../../api/task_queue", "../../rtc_base:macromagic", "../../rtc_base:refcount", "../../rtc_base:stringutils", @@ -43,6 +44,7 @@ rtc_library("api") { "agc:gain_control_interface", ] absl_deps = [ + "//third_party/abseil-cpp/absl/base:nullability", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] @@ -185,6 +187,7 @@ rtc_library("audio_processing") { "../../api/audio:aec3_config", "../../api/audio:audio_frame_api", "../../api/audio:echo_control", + "../../api/task_queue", "../../audio/utility:audio_frame_operations", "../../common_audio:common_audio_c", "../../common_audio/third_party/ooura:fft_size_256", @@ -217,6 +220,7 @@ rtc_library("audio_processing") { "vad", ] absl_deps = [ + "//third_party/abseil-cpp/absl/base:nullability", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] @@ -337,9 +341,13 @@ if (rtc_include_tests) { ":audio_buffer", ":audio_processing", ":audio_processing_statistics", + "../../api/task_queue", "../../test:test_support", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:nullability", + "//third_party/abseil-cpp/absl/strings", + ] } if (!build_with_chromium) { diff --git a/third_party/libwebrtc/modules/audio_processing/aec_dump/BUILD.gn b/third_party/libwebrtc/modules/audio_processing/aec_dump/BUILD.gn index 78bae56835..5193e28dff 100644 --- a/third_party/libwebrtc/modules/audio_processing/aec_dump/BUILD.gn +++ b/third_party/libwebrtc/modules/audio_processing/aec_dump/BUILD.gn @@ -14,10 +14,14 @@ rtc_source_set("aec_dump") { deps = [ "..:aec_dump_interface", + "../../../api/task_queue", "../../../rtc_base/system:file_wrapper", "../../../rtc_base/system:rtc_export", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:nullability", + "//third_party/abseil-cpp/absl/strings", + ] } if (rtc_include_tests) { @@ -71,11 +75,13 @@ if (rtc_enable_protobuf) { "../../../rtc_base:protobuf_utils", "../../../rtc_base:race_checker", "../../../rtc_base:rtc_event", - "../../../rtc_base:rtc_task_queue", "../../../rtc_base/system:file_wrapper", "../../../system_wrappers", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:nullability", + "//third_party/abseil-cpp/absl/strings", + ] deps += [ "../:audioproc_debug_proto" ] } @@ -106,6 +112,10 @@ rtc_library("null_aec_dump_factory") { deps = [ ":aec_dump", "..:aec_dump_interface", + "../../../api/task_queue", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:nullability", + "//third_party/abseil-cpp/absl/strings", ] - absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } diff --git a/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_factory.h b/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_factory.h index 20718c3d7f..0d258a9ebc 100644 --- a/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_factory.h +++ b/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_factory.h @@ -13,34 +13,34 @@ #include +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" +#include "api/task_queue/task_queue_base.h" #include "modules/audio_processing/include/aec_dump.h" #include "rtc_base/system/file_wrapper.h" #include "rtc_base/system/rtc_export.h" -namespace rtc { -class TaskQueue; -} // namespace rtc - namespace webrtc { class RTC_EXPORT AecDumpFactory { public: - // The `worker_queue` may not be null and must outlive the created - // AecDump instance. `max_log_size_bytes == -1` means the log size - // will be unlimited. `handle` may not be null. The AecDump takes - // responsibility for `handle` and closes it in the destructor. A - // non-null return value indicates that the file has been + // The `worker_queue` must outlive the created AecDump instance. + // `max_log_size_bytes == -1` means the log size will be unlimited. + // The AecDump takes responsibility for `handle` and closes it in the + // destructor. A non-null return value indicates that the file has been // sucessfully opened. - static std::unique_ptr Create(webrtc::FileWrapper file, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue); - static std::unique_ptr Create(absl::string_view file_name, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue); - static std::unique_ptr Create(FILE* handle, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue); + static absl::Nullable> Create( + FileWrapper file, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue); + static absl::Nullable> Create( + absl::string_view file_name, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue); + static absl::Nullable> Create( + absl::Nonnull handle, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue); }; } // namespace webrtc diff --git a/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc b/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc index 94c24048e0..8484fcc6e1 100644 --- a/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc +++ b/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc @@ -13,11 +13,12 @@ #include #include +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" +#include "api/task_queue/task_queue_base.h" #include "modules/audio_processing/aec_dump/aec_dump_factory.h" #include "rtc_base/checks.h" #include "rtc_base/event.h" -#include "rtc_base/task_queue.h" namespace webrtc { @@ -59,7 +60,7 @@ void CopyFromConfigToEvent(const webrtc::InternalAPMConfig& config, AecDumpImpl::AecDumpImpl(FileWrapper debug_file, int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) + absl::Nonnull worker_queue) : debug_file_(std::move(debug_file)), num_bytes_left_for_log_(max_log_size_bytes), worker_queue_(worker_queue) {} @@ -254,9 +255,10 @@ void AecDumpImpl::PostWriteToFileTask(std::unique_ptr event) { }); } -std::unique_ptr AecDumpFactory::Create(webrtc::FileWrapper file, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) { +absl::Nullable> AecDumpFactory::Create( + FileWrapper file, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) { RTC_DCHECK(worker_queue); if (!file.is_open()) return nullptr; @@ -265,16 +267,18 @@ std::unique_ptr AecDumpFactory::Create(webrtc::FileWrapper file, worker_queue); } -std::unique_ptr AecDumpFactory::Create(absl::string_view file_name, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) { +absl::Nullable> AecDumpFactory::Create( + absl::string_view file_name, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) { return Create(FileWrapper::OpenWriteOnly(file_name), max_log_size_bytes, worker_queue); } -std::unique_ptr AecDumpFactory::Create(FILE* handle, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) { +absl::Nullable> AecDumpFactory::Create( + absl::Nonnull handle, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) { return Create(FileWrapper(handle), max_log_size_bytes, worker_queue); } diff --git a/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_impl.h b/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_impl.h index 429808f9af..d5af31b01e 100644 --- a/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_impl.h +++ b/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_impl.h @@ -15,11 +15,11 @@ #include #include +#include "api/task_queue/task_queue_base.h" #include "modules/audio_processing/aec_dump/capture_stream_info.h" #include "modules/audio_processing/include/aec_dump.h" #include "rtc_base/race_checker.h" #include "rtc_base/system/file_wrapper.h" -#include "rtc_base/task_queue.h" #include "rtc_base/thread_annotations.h" // Files generated at build-time by the protobuf compiler. @@ -39,7 +39,7 @@ class AecDumpImpl : public AecDump { // `max_log_size_bytes == -1` means the log size will be unlimited. AecDumpImpl(FileWrapper debug_file, int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue); + absl::Nonnull worker_queue); AecDumpImpl(const AecDumpImpl&) = delete; AecDumpImpl& operator=(const AecDumpImpl&) = delete; ~AecDumpImpl() override; @@ -74,7 +74,7 @@ class AecDumpImpl : public AecDump { FileWrapper debug_file_; int64_t num_bytes_left_for_log_ = 0; rtc::RaceChecker race_checker_; - rtc::TaskQueue* worker_queue_; + absl::Nonnull worker_queue_; CaptureStreamInfo capture_stream_info_; }; } // namespace webrtc diff --git a/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_unittest.cc b/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_unittest.cc index 62f896fe14..2a8110c4fc 100644 --- a/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_unittest.cc +++ b/third_party/libwebrtc/modules/audio_processing/aec_dump/aec_dump_unittest.cc @@ -28,7 +28,7 @@ TEST(AecDumper, APICallsDoNotCrash) { { std::unique_ptr aec_dump = - webrtc::AecDumpFactory::Create(filename, -1, &file_writer_queue); + webrtc::AecDumpFactory::Create(filename, -1, file_writer_queue.Get()); constexpr int kNumChannels = 1; constexpr int kNumSamplesPerChannel = 160; @@ -63,7 +63,7 @@ TEST(AecDumper, WriteToFile) { { std::unique_ptr aec_dump = - webrtc::AecDumpFactory::Create(filename, -1, &file_writer_queue); + webrtc::AecDumpFactory::Create(filename, -1, file_writer_queue.Get()); constexpr int kNumChannels = 1; constexpr int kNumSamplesPerChannel = 160; diff --git a/third_party/libwebrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc b/third_party/libwebrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc index 9bd9745069..63929afac4 100644 --- a/third_party/libwebrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc +++ b/third_party/libwebrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc @@ -8,27 +8,32 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" +#include "api/task_queue/task_queue_base.h" #include "modules/audio_processing/aec_dump/aec_dump_factory.h" #include "modules/audio_processing/include/aec_dump.h" namespace webrtc { -std::unique_ptr AecDumpFactory::Create(webrtc::FileWrapper file, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) { +absl::Nullable> AecDumpFactory::Create( + FileWrapper file, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) { return nullptr; } -std::unique_ptr AecDumpFactory::Create(absl::string_view file_name, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) { +absl::Nullable> AecDumpFactory::Create( + absl::string_view file_name, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) { return nullptr; } -std::unique_ptr AecDumpFactory::Create(FILE* handle, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) { +absl::Nullable> AecDumpFactory::Create( + absl::Nonnull handle, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) { return nullptr; } } // namespace webrtc diff --git a/third_party/libwebrtc/modules/audio_processing/audio_processing_impl.cc b/third_party/libwebrtc/modules/audio_processing/audio_processing_impl.cc index c304453388..4ac074526c 100644 --- a/third_party/libwebrtc/modules/audio_processing/audio_processing_impl.cc +++ b/third_party/libwebrtc/modules/audio_processing/audio_processing_impl.cc @@ -18,11 +18,13 @@ #include #include +#include "absl/base/nullability.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/array_view.h" #include "api/audio/audio_frame.h" +#include "api/task_queue/task_queue_base.h" #include "common_audio/audio_converter.h" #include "common_audio/include/audio_util.h" #include "modules/audio_processing/aec_dump/aec_dump_factory.h" @@ -2083,9 +2085,10 @@ void AudioProcessingImpl::UpdateRecommendedInputVolumeLocked() { capture_.recommended_input_volume = capture_.applied_input_volume; } -bool AudioProcessingImpl::CreateAndAttachAecDump(absl::string_view file_name, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) { +bool AudioProcessingImpl::CreateAndAttachAecDump( + absl::string_view file_name, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) { std::unique_ptr aec_dump = AecDumpFactory::Create(file_name, max_log_size_bytes, worker_queue); if (!aec_dump) { @@ -2096,9 +2099,10 @@ bool AudioProcessingImpl::CreateAndAttachAecDump(absl::string_view file_name, return true; } -bool AudioProcessingImpl::CreateAndAttachAecDump(FILE* handle, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) { +bool AudioProcessingImpl::CreateAndAttachAecDump( + FILE* handle, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) { std::unique_ptr aec_dump = AecDumpFactory::Create(handle, max_log_size_bytes, worker_queue); if (!aec_dump) { diff --git a/third_party/libwebrtc/modules/audio_processing/audio_processing_impl.h b/third_party/libwebrtc/modules/audio_processing/audio_processing_impl.h index 1e058b5a32..2c0ab198db 100644 --- a/third_party/libwebrtc/modules/audio_processing/audio_processing_impl.h +++ b/third_party/libwebrtc/modules/audio_processing/audio_processing_impl.h @@ -19,10 +19,12 @@ #include #include +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/array_view.h" #include "api/function_view.h" +#include "api/task_queue/task_queue_base.h" #include "modules/audio_processing/aec3/echo_canceller3.h" #include "modules/audio_processing/agc/agc_manager_direct.h" #include "modules/audio_processing/agc/gain_control.h" @@ -71,12 +73,14 @@ class AudioProcessingImpl : public AudioProcessing { int Initialize() override; int Initialize(const ProcessingConfig& processing_config) override; void ApplyConfig(const AudioProcessing::Config& config) override; - bool CreateAndAttachAecDump(absl::string_view file_name, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) override; - bool CreateAndAttachAecDump(FILE* handle, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) override; + bool CreateAndAttachAecDump( + absl::string_view file_name, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) override; + bool CreateAndAttachAecDump( + FILE* handle, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) override; // TODO(webrtc:5298) Deprecated variant. void AttachAecDump(std::unique_ptr aec_dump) override; void DetachAecDump() override; diff --git a/third_party/libwebrtc/modules/audio_processing/audio_processing_unittest.cc b/third_party/libwebrtc/modules/audio_processing/audio_processing_unittest.cc index c2bedb2da4..2d3684e9b5 100644 --- a/third_party/libwebrtc/modules/audio_processing/audio_processing_unittest.cc +++ b/third_party/libwebrtc/modules/audio_processing/audio_processing_unittest.cc @@ -1485,8 +1485,8 @@ void ApmTest::ProcessDebugDump(absl::string_view in_filename, if (first_init) { // AttachAecDump() writes an additional init message. Don't start // recording until after the first init to avoid the extra message. - auto aec_dump = - AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue); + auto aec_dump = AecDumpFactory::Create(out_filename, max_size_bytes, + worker_queue.Get()); EXPECT_TRUE(aec_dump); apm_->AttachAecDump(std::move(aec_dump)); first_init = false; @@ -1632,7 +1632,7 @@ TEST_F(ApmTest, DebugDump) { const std::string filename = test::TempFilename(test::OutputPath(), "debug_aec"); { - auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue); + auto aec_dump = AecDumpFactory::Create("", -1, worker_queue.Get()); EXPECT_FALSE(aec_dump); } @@ -1640,7 +1640,7 @@ TEST_F(ApmTest, DebugDump) { // Stopping without having started should be OK. apm_->DetachAecDump(); - auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue); + auto aec_dump = AecDumpFactory::Create(filename, -1, worker_queue.Get()); EXPECT_TRUE(aec_dump); apm_->AttachAecDump(std::move(aec_dump)); EXPECT_EQ(apm_->kNoError, @@ -1683,7 +1683,7 @@ TEST_F(ApmTest, DebugDumpFromFileHandle) { // Stopping without having started should be OK. apm_->DetachAecDump(); - auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue); + auto aec_dump = AecDumpFactory::Create(std::move(f), -1, worker_queue.Get()); EXPECT_TRUE(aec_dump); apm_->AttachAecDump(std::move(aec_dump)); EXPECT_EQ(apm_->kNoError, diff --git a/third_party/libwebrtc/modules/audio_processing/include/audio_processing.h b/third_party/libwebrtc/modules/audio_processing/include/audio_processing.h index e3223513af..dd484be4f1 100644 --- a/third_party/libwebrtc/modules/audio_processing/include/audio_processing.h +++ b/third_party/libwebrtc/modules/audio_processing/include/audio_processing.h @@ -23,6 +23,7 @@ #include +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/array_view.h" @@ -30,15 +31,12 @@ #include "api/audio/echo_control.h" #include "api/ref_count.h" #include "api/scoped_refptr.h" +#include "api/task_queue/task_queue_base.h" #include "modules/audio_processing/include/audio_processing_statistics.h" #include "rtc_base/arraysize.h" #include "rtc_base/system/file_wrapper.h" #include "rtc_base/system/rtc_export.h" -namespace rtc { -class TaskQueue; -} // namespace rtc - namespace webrtc { class AecDump; @@ -632,12 +630,14 @@ class RTC_EXPORT AudioProcessing : public RefCountInterface { // return value of true indicates that the file has been // sucessfully opened, while a value of false indicates that // opening the file failed. - virtual bool CreateAndAttachAecDump(absl::string_view file_name, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) = 0; - virtual bool CreateAndAttachAecDump(FILE* handle, - int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue) = 0; + virtual bool CreateAndAttachAecDump( + absl::string_view file_name, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) = 0; + virtual bool CreateAndAttachAecDump( + absl::Nonnull handle, + int64_t max_log_size_bytes, + absl::Nonnull worker_queue) = 0; // TODO(webrtc:5298) Deprecated variant. // Attaches provided webrtc::AecDump for recording debugging diff --git a/third_party/libwebrtc/modules/audio_processing/include/mock_audio_processing.h b/third_party/libwebrtc/modules/audio_processing/include/mock_audio_processing.h index 2ea1a865c3..dfe7d84e07 100644 --- a/third_party/libwebrtc/modules/audio_processing/include/mock_audio_processing.h +++ b/third_party/libwebrtc/modules/audio_processing/include/mock_audio_processing.h @@ -13,7 +13,9 @@ #include +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" +#include "api/task_queue/task_queue_base.h" #include "modules/audio_processing/include/aec_dump.h" #include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/include/audio_processing_statistics.h" @@ -155,13 +157,13 @@ class MockAudioProcessing : public AudioProcessing { CreateAndAttachAecDump, (absl::string_view file_name, int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue), + absl::Nonnull worker_queue), (override)); MOCK_METHOD(bool, CreateAndAttachAecDump, (FILE * handle, int64_t max_log_size_bytes, - rtc::TaskQueue* worker_queue), + absl::Nonnull worker_queue), (override)); MOCK_METHOD(void, AttachAecDump, (std::unique_ptr), (override)); MOCK_METHOD(void, DetachAecDump, (), (override)); diff --git a/third_party/libwebrtc/modules/audio_processing/test/audio_processing_simulator.cc b/third_party/libwebrtc/modules/audio_processing/test/audio_processing_simulator.cc index 7bd6da0133..500005f26a 100644 --- a/third_party/libwebrtc/modules/audio_processing/test/audio_processing_simulator.cc +++ b/third_party/libwebrtc/modules/audio_processing/test/audio_processing_simulator.cc @@ -622,7 +622,7 @@ void AudioProcessingSimulator::ConfigureAudioProcessor() { if (settings_.aec_dump_output_filename) { ap_->AttachAecDump(AecDumpFactory::Create( - *settings_.aec_dump_output_filename, -1, &worker_queue_)); + *settings_.aec_dump_output_filename, -1, worker_queue_.Get())); } } diff --git a/third_party/libwebrtc/modules/audio_processing/test/debug_dump_test.cc b/third_party/libwebrtc/modules/audio_processing/test/debug_dump_test.cc index cded5de217..0d3eefa94a 100644 --- a/third_party/libwebrtc/modules/audio_processing/test/debug_dump_test.cc +++ b/third_party/libwebrtc/modules/audio_processing/test/debug_dump_test.cc @@ -197,7 +197,7 @@ void DebugDumpGenerator::SetOutputChannels(int channels) { void DebugDumpGenerator::StartRecording() { apm_->AttachAecDump( - AecDumpFactory::Create(dump_file_name_.c_str(), -1, &worker_queue_)); + AecDumpFactory::Create(dump_file_name_.c_str(), -1, worker_queue_.Get())); } void DebugDumpGenerator::Process(size_t num_blocks) { diff --git a/third_party/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc b/third_party/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc index 16bd4153a6..e56aa4a09c 100644 --- a/third_party/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc +++ b/third_party/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc @@ -26,6 +26,7 @@ #include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h" #include "rtc_base/checks.h" #include "test/field_trial.h" +#include "test/gtest.h" namespace webrtc { constexpr size_t kMtu = 1200; @@ -52,6 +53,7 @@ RtpStream::RtpStream(int fps, int bitrate_bps) // previous frame, no frame will be generated. The frame is split into // packets. int64_t RtpStream::GenerateFrame(int64_t time_now_us, + int64_t* next_sequence_number, std::vector* packets) { if (time_now_us < next_rtp_time_) { return next_rtp_time_; @@ -66,6 +68,7 @@ int64_t RtpStream::GenerateFrame(int64_t time_now_us, packet.sent_packet.send_time = Timestamp::Micros(time_now_us + kSendSideOffsetUs); packet.sent_packet.size = DataSize::Bytes(payload_size); + packet.sent_packet.sequence_number = (*next_sequence_number)++; packets->push_back(packet); } next_rtp_time_ = time_now_us + (1000000 + fps_ / 2) / fps_; @@ -131,14 +134,15 @@ void StreamGenerator::SetBitrateBps(int bitrate_bps) { // TODO(holmer): Break out the channel simulation part from this class to make // it possible to simulate different types of channels. -int64_t StreamGenerator::GenerateFrame(std::vector* packets, - int64_t time_now_us) { +int64_t StreamGenerator::GenerateFrame(int64_t time_now_us, + int64_t* next_sequence_number, + std::vector* packets) { RTC_CHECK(packets != NULL); RTC_CHECK(packets->empty()); RTC_CHECK_GT(capacity_, 0); auto it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); - (*it)->GenerateFrame(time_now_us, packets); + (*it)->GenerateFrame(time_now_us, next_sequence_number, packets); for (PacketResult& packet : *packets) { int capacity_bpus = capacity_ / 1000; int64_t required_network_time_us = @@ -233,8 +237,8 @@ bool DelayBasedBweTest::GenerateAndProcessFrame(uint32_t ssrc, stream_generator_->SetBitrateBps(bitrate_bps); std::vector packets; - int64_t next_time_us = - stream_generator_->GenerateFrame(&packets, clock_.TimeInMicroseconds()); + int64_t next_time_us = stream_generator_->GenerateFrame( + clock_.TimeInMicroseconds(), &next_sequence_number_, &packets); if (packets.empty()) return false; diff --git a/third_party/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h b/third_party/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h index 89eb1a353f..634e6a4d82 100644 --- a/third_party/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h +++ b/third_party/libwebrtc/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h @@ -15,12 +15,11 @@ #include #include -#include #include -#include "absl/strings/string_view.h" #include "api/transport/field_trial_based_config.h" #include "api/transport/network_types.h" +#include "api/units/timestamp.h" #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe.h" #include "system_wrappers/include/clock.h" @@ -61,6 +60,7 @@ class RtpStream { // previous frame, no frame will be generated. The frame is split into // packets. int64_t GenerateFrame(int64_t time_now_us, + int64_t* next_sequence_number, std::vector* packets); // The send-side time when the next frame can be generated. @@ -102,8 +102,9 @@ class StreamGenerator { // TODO(holmer): Break out the channel simulation part from this class to make // it possible to simulate different types of channels. - int64_t GenerateFrame(std::vector* packets, - int64_t time_now_us); + int64_t GenerateFrame(int64_t time_now_us, + int64_t* next_sequence_number, + std::vector* packets); private: // Capacity of the simulated channel in bits per second. diff --git a/third_party/libwebrtc/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc b/third_party/libwebrtc/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc index 22693d67e9..211d86c95d 100644 --- a/third_party/libwebrtc/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc +++ b/third_party/libwebrtc/modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.cc @@ -281,7 +281,8 @@ void SendSideBandwidthEstimation::OnRouteChange() { uma_update_state_ = kNoUpdate; uma_rtt_state_ = kNoUpdate; last_rtc_event_log_ = Timestamp::MinusInfinity(); - if (loss_based_bandwidth_estimator_v2_->UseInStartPhase()) { + if (LossBasedBandwidthEstimatorV2Enabled() && + loss_based_bandwidth_estimator_v2_->UseInStartPhase()) { loss_based_bandwidth_estimator_v2_.reset( new LossBasedBweV2(key_value_config_)); } diff --git a/third_party/libwebrtc/modules/congestion_controller/rtp/BUILD.gn b/third_party/libwebrtc/modules/congestion_controller/rtp/BUILD.gn index cd13332b7f..8ec755e1aa 100644 --- a/third_party/libwebrtc/modules/congestion_controller/rtp/BUILD.gn +++ b/third_party/libwebrtc/modules/congestion_controller/rtp/BUILD.gn @@ -34,7 +34,6 @@ rtc_library("control_handler") { "../../../rtc_base:safe_conversions", "../../../rtc_base:safe_minmax", "../../../rtc_base/system:no_unique_address", - "../../../system_wrappers:field_trial", "../../pacing", ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] diff --git a/third_party/libwebrtc/modules/congestion_controller/rtp/control_handler.cc b/third_party/libwebrtc/modules/congestion_controller/rtp/control_handler.cc index da6451c97e..357a0f0798 100644 --- a/third_party/libwebrtc/modules/congestion_controller/rtp/control_handler.cc +++ b/third_party/libwebrtc/modules/congestion_controller/rtp/control_handler.cc @@ -18,21 +18,8 @@ #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/numerics/safe_minmax.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { -namespace { - -// By default, pacer emergency stops encoder when buffer reaches a high level. -bool IsPacerEmergencyStopDisabled() { - return field_trial::IsEnabled("WebRTC-DisablePacerEmergencyStop"); -} - -} // namespace -CongestionControlHandler::CongestionControlHandler() - : disable_pacer_emergency_stop_(IsPacerEmergencyStopDisabled()) {} - -CongestionControlHandler::~CongestionControlHandler() {} void CongestionControlHandler::SetTargetRate( TargetTransferRate new_target_rate) { @@ -60,9 +47,8 @@ absl::optional CongestionControlHandler::GetUpdate() { bool pause_encoding = false; if (!network_available_) { pause_encoding = true; - } else if (!disable_pacer_emergency_stop_ && - pacer_expected_queue_ms_ > - PacingController::kMaxExpectedQueueLength.ms()) { + } else if (pacer_expected_queue_ms_ > + PacingController::kMaxExpectedQueueLength.ms()) { pause_encoding = true; } if (pause_encoding) diff --git a/third_party/libwebrtc/modules/congestion_controller/rtp/control_handler.h b/third_party/libwebrtc/modules/congestion_controller/rtp/control_handler.h index d8e7263a02..649d2f911e 100644 --- a/third_party/libwebrtc/modules/congestion_controller/rtp/control_handler.h +++ b/third_party/libwebrtc/modules/congestion_controller/rtp/control_handler.h @@ -28,12 +28,13 @@ namespace webrtc { // destruction unless members are properly ordered. class CongestionControlHandler { public: - CongestionControlHandler(); - ~CongestionControlHandler(); + CongestionControlHandler() = default; CongestionControlHandler(const CongestionControlHandler&) = delete; CongestionControlHandler& operator=(const CongestionControlHandler&) = delete; + ~CongestionControlHandler() = default; + void SetTargetRate(TargetTransferRate new_target_rate); void SetNetworkAvailability(bool network_available); void SetPacerQueue(TimeDelta expected_queue_time); @@ -45,7 +46,6 @@ class CongestionControlHandler { bool network_available_ = true; bool encoder_paused_in_last_report_ = false; - const bool disable_pacer_emergency_stop_; int64_t pacer_expected_queue_ms_ = 0; RTC_NO_UNIQUE_ADDRESS SequenceChecker sequenced_checker_; diff --git a/third_party/libwebrtc/modules/pacing/BUILD.gn b/third_party/libwebrtc/modules/pacing/BUILD.gn index ea80c8c819..87498817b6 100644 --- a/third_party/libwebrtc/modules/pacing/BUILD.gn +++ b/third_party/libwebrtc/modules/pacing/BUILD.gn @@ -63,6 +63,7 @@ rtc_library("pacing") { ] absl_deps = [ "//third_party/abseil-cpp/absl/cleanup", + "//third_party/abseil-cpp/absl/container:inlined_vector", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", diff --git a/third_party/libwebrtc/modules/pacing/pacing_controller.cc b/third_party/libwebrtc/modules/pacing/pacing_controller.cc index 5b81207d56..41f97a37fb 100644 --- a/third_party/libwebrtc/modules/pacing/pacing_controller.cc +++ b/third_party/libwebrtc/modules/pacing/pacing_controller.cc @@ -19,11 +19,11 @@ #include "absl/strings/match.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "modules/pacing/bitrate_prober.h" -#include "modules/pacing/interval_budget.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" -#include "rtc_base/time_utils.h" #include "system_wrappers/include/clock.h" namespace webrtc { @@ -44,8 +44,6 @@ bool IsEnabled(const FieldTrialsView& field_trials, absl::string_view key) { } // namespace -const TimeDelta PacingController::kMaxExpectedQueueLength = - TimeDelta::Millis(2000); const TimeDelta PacingController::kPausedProcessInterval = kCongestedPacketInterval; const TimeDelta PacingController::kMinSleepTime = TimeDelta::Millis(1); @@ -57,11 +55,13 @@ const TimeDelta PacingController::kMaxEarlyProbeProcessing = PacingController::PacingController(Clock* clock, PacketSender* packet_sender, - const FieldTrialsView& field_trials) + const FieldTrialsView& field_trials, + Configuration configuration) : clock_(clock), packet_sender_(packet_sender), field_trials_(field_trials), drain_large_queues_( + configuration.drain_large_queues && !IsDisabled(field_trials_, "WebRTC-Pacer-DrainQueue")), send_padding_if_silent_( IsEnabled(field_trials_, "WebRTC-Pacer-PadInSilence")), @@ -71,9 +71,10 @@ PacingController::PacingController(Clock* clock, fast_retransmissions_( IsEnabled(field_trials_, "WebRTC-Pacer-FastRetransmissions")), keyframe_flushing_( + configuration.keyframe_flushing || IsEnabled(field_trials_, "WebRTC-Pacer-KeyframeFlushing")), transport_overhead_per_packet_(DataSize::Zero()), - send_burst_interval_(kDefaultBurstInterval), + send_burst_interval_(configuration.send_burst_interval), last_timestamp_(clock_->CurrentTime()), paused_(false), media_debt_(DataSize::Zero()), @@ -86,9 +87,11 @@ PacingController::PacingController(Clock* clock, last_process_time_(clock->CurrentTime()), last_send_time_(last_process_time_), seen_first_packet_(false), - packet_queue_(/*creation_time=*/last_process_time_), + packet_queue_(/*creation_time=*/last_process_time_, + configuration.prioritize_audio_retransmission, + configuration.packet_queue_ttl), congested_(false), - queue_time_limit_(kMaxExpectedQueueLength), + queue_time_limit_(configuration.queue_time_limit), account_for_audio_(false), include_overhead_(false), circuit_breaker_threshold_(1 << 16) { @@ -710,8 +713,7 @@ Timestamp PacingController::NextUnpacedSendTime() const { } if (fast_retransmissions_) { Timestamp leading_retransmission_send_time = - packet_queue_.LeadingPacketEnqueueTime( - RtpPacketMediaType::kRetransmission); + packet_queue_.LeadingPacketEnqueueTimeForRetransmission(); if (leading_retransmission_send_time.IsFinite()) { return leading_retransmission_send_time; } diff --git a/third_party/libwebrtc/modules/pacing/pacing_controller.h b/third_party/libwebrtc/modules/pacing/pacing_controller.h index 04e0a820f9..fe6ee737a9 100644 --- a/third_party/libwebrtc/modules/pacing/pacing_controller.h +++ b/third_party/libwebrtc/modules/pacing/pacing_controller.h @@ -67,11 +67,6 @@ class PacingController { } }; - // Expected max pacer delay. If ExpectedQueueTime() is higher than - // this value, the packet producers should wait (eg drop frames rather than - // encoding them). Bitrate sent may temporarily exceed target set by - // UpdateBitrate() so that this limit will be upheld. - static const TimeDelta kMaxExpectedQueueLength; // If no media or paused, wake up at least every `kPausedProcessIntervalMs` in // order to send a keep-alive packet so we don't get stuck in a bad state due // to lack of feedback. @@ -93,14 +88,45 @@ class PacingController { // the send burst interval. // Ex: max send burst interval = 63Kb / 10Mbit/s = 50ms. static constexpr DataSize kMaxBurstSize = DataSize::Bytes(63 * 1000); - // The pacer is allowed to send enqued packets in bursts and can build up a - // packet "debt" that correspond to approximately the send rate during - // the burst interval. + + // Configuration default values. static constexpr TimeDelta kDefaultBurstInterval = TimeDelta::Millis(40); + static constexpr TimeDelta kMaxExpectedQueueLength = TimeDelta::Millis(2000); + + struct Configuration { + // If the pacer queue grows longer than the configured max queue limit, + // pacer sends at the minimum rate needed to keep the max queue limit and + // ignore the current bandwidth estimate. + bool drain_large_queues = true; + // Expected max pacer delay. If ExpectedQueueTime() is higher than + // this value, the packet producers should wait (eg drop frames rather than + // encoding them). Bitrate sent may temporarily exceed target set by + // SetPacingRates() so that this limit will be upheld if + // `drain_large_queues` is set. + TimeDelta queue_time_limit = kMaxExpectedQueueLength; + // If the first packet of a keyframe is enqueued on a RTP stream, pacer + // skips forward to that packet and drops other enqueued packets on that + // stream, unless a keyframe is already being paced. + bool keyframe_flushing = false; + // Audio retransmission is prioritized before video retransmission packets. + bool prioritize_audio_retransmission = false; + // Configure separate timeouts per priority. After a timeout, a packet of + // that sort will not be paced and instead dropped. + // Note: to set TTL on audio retransmission, + // `prioritize_audio_retransmission` must be true. + PacketQueueTTL packet_queue_ttl; + // The pacer is allowed to send enqueued packets in bursts and can build up + // a packet "debt" that correspond to approximately the send rate during the + // burst interval. + TimeDelta send_burst_interval = kDefaultBurstInterval; + }; + + static Configuration DefaultConfiguration() { return Configuration{}; } PacingController(Clock* clock, PacketSender* packet_sender, - const FieldTrialsView& field_trials); + const FieldTrialsView& field_trials, + Configuration configuration = DefaultConfiguration()); ~PacingController(); diff --git a/third_party/libwebrtc/modules/pacing/pacing_controller_unittest.cc b/third_party/libwebrtc/modules/pacing/pacing_controller_unittest.cc index 9e6ede6dc0..2c3a71b369 100644 --- a/third_party/libwebrtc/modules/pacing/pacing_controller_unittest.cc +++ b/third_party/libwebrtc/modules/pacing/pacing_controller_unittest.cc @@ -2348,5 +2348,43 @@ TEST_F(PacingControllerTest, FlushesPacketsOnKeyFrames) { pacer->ProcessPackets(); } +TEST_F(PacingControllerTest, CanControlQueueSizeUsingTtl) { + const uint32_t kSsrc = 12345; + const uint32_t kAudioSsrc = 2345; + uint16_t sequence_number = 1234; + + PacingController::Configuration config; + config.drain_large_queues = false; + config.packet_queue_ttl.video = TimeDelta::Millis(500); + auto pacer = + std::make_unique(&clock_, &callback_, trials_, config); + pacer->SetPacingRates(DataRate::BitsPerSec(100'000), DataRate::Zero()); + + Timestamp send_time = Timestamp::Zero(); + for (int i = 0; i < 100; ++i) { + // Enqueue a new audio and video frame every 33ms. + if (clock_.CurrentTime() - send_time > TimeDelta::Millis(33)) { + for (int j = 0; j < 3; ++j) { + auto packet = BuildPacket(RtpPacketMediaType::kVideo, kSsrc, + /*sequence_number=*/++sequence_number, + /*capture_time_ms=*/2, + /*size_bytes=*/1000); + pacer->EnqueuePacket(std::move(packet)); + } + auto packet = BuildPacket(RtpPacketMediaType::kAudio, kAudioSsrc, + /*sequence_number=*/++sequence_number, + /*capture_time_ms=*/2, + /*size_bytes=*/100); + pacer->EnqueuePacket(std::move(packet)); + send_time = clock_.CurrentTime(); + } + + EXPECT_LE(clock_.CurrentTime() - pacer->OldestPacketEnqueueTime(), + TimeDelta::Millis(500)); + clock_.AdvanceTime(pacer->NextSendTime() - clock_.CurrentTime()); + pacer->ProcessPackets(); + } +} + } // namespace } // namespace webrtc diff --git a/third_party/libwebrtc/modules/pacing/prioritized_packet_queue.cc b/third_party/libwebrtc/modules/pacing/prioritized_packet_queue.cc index ea211ea683..2d0d829648 100644 --- a/third_party/libwebrtc/modules/pacing/prioritized_packet_queue.cc +++ b/third_party/libwebrtc/modules/pacing/prioritized_packet_queue.cc @@ -10,41 +10,70 @@ #include "modules/pacing/prioritized_packet_queue.h" +#include +#include #include +#include "absl/container/inlined_vector.h" +#include "absl/types/optional.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "rtc_base/checks.h" +#include "rtc_base/logging.h" namespace webrtc { namespace { constexpr int kAudioPrioLevel = 0; -int GetPriorityForType(RtpPacketMediaType type) { +int GetPriorityForType( + RtpPacketMediaType type, + absl::optional original_type) { // Lower number takes priority over higher. switch (type) { case RtpPacketMediaType::kAudio: // Audio is always prioritized over other packet types. return kAudioPrioLevel; case RtpPacketMediaType::kRetransmission: - // Send retransmissions before new media. + // Send retransmissions before new media. If original_type is set, audio + // retransmission is prioritized more than video retransmission. + if (original_type == RtpPacketToSend::OriginalType::kVideo) { + return kAudioPrioLevel + 2; + } return kAudioPrioLevel + 1; case RtpPacketMediaType::kVideo: case RtpPacketMediaType::kForwardErrorCorrection: // Video has "normal" priority, in the old speak. // Send redundancy concurrently to video. If it is delayed it might have a // lower chance of being useful. - return kAudioPrioLevel + 2; + return kAudioPrioLevel + 3; case RtpPacketMediaType::kPadding: // Packets that are in themselves likely useless, only sent to keep the // BWE high. - return kAudioPrioLevel + 3; + return kAudioPrioLevel + 4; } RTC_CHECK_NOTREACHED(); } } // namespace +absl::InlinedVector +PrioritizedPacketQueue::ToTtlPerPrio(PacketQueueTTL packet_queue_ttl) { + absl::InlinedVector + ttl_per_prio(kNumPriorityLevels, TimeDelta::PlusInfinity()); + ttl_per_prio[GetPriorityForType(RtpPacketMediaType::kRetransmission, + RtpPacketToSend::OriginalType::kAudio)] = + packet_queue_ttl.audio_retransmission; + ttl_per_prio[GetPriorityForType(RtpPacketMediaType::kRetransmission, + RtpPacketToSend::OriginalType::kVideo)] = + packet_queue_ttl.video_retransmission; + ttl_per_prio[GetPriorityForType(RtpPacketMediaType::kVideo, absl::nullopt)] = + packet_queue_ttl.video; + return ttl_per_prio; +} + DataSize PrioritizedPacketQueue::QueuedPacket::PacketSize() const { return DataSize::Bytes(packet->payload_size() + packet->padding_size()); } @@ -109,8 +138,13 @@ PrioritizedPacketQueue::StreamQueue::DequeueAll() { return packets_by_prio; } -PrioritizedPacketQueue::PrioritizedPacketQueue(Timestamp creation_time) - : queue_time_sum_(TimeDelta::Zero()), +PrioritizedPacketQueue::PrioritizedPacketQueue( + Timestamp creation_time, + bool prioritize_audio_retransmission, + PacketQueueTTL packet_queue_ttl) + : prioritize_audio_retransmission_(prioritize_audio_retransmission), + time_to_live_per_prio_(ToTtlPerPrio(packet_queue_ttl)), + queue_time_sum_(TimeDelta::Zero()), pause_time_sum_(TimeDelta::Zero()), size_packets_(0), size_packets_per_media_type_({}), @@ -133,7 +167,11 @@ void PrioritizedPacketQueue::Push(Timestamp enqueue_time, enqueue_times_.insert(enqueue_times_.end(), enqueue_time); RTC_DCHECK(packet->packet_type().has_value()); RtpPacketMediaType packet_type = packet->packet_type().value(); - int prio_level = GetPriorityForType(packet_type); + int prio_level = + GetPriorityForType(packet_type, prioritize_audio_retransmission_ + ? packet->original_packet_type() + : absl::nullopt); + PurgeOldPacketsAtPriorityLevel(prio_level, enqueue_time); RTC_DCHECK_GE(prio_level, 0); RTC_DCHECK_LT(prio_level, kNumPriorityLevels); QueuedPacket queued_packed = {.packet = std::move(packet), @@ -214,7 +252,8 @@ PrioritizedPacketQueue::SizeInPacketsPerRtpPacketMediaType() const { Timestamp PrioritizedPacketQueue::LeadingPacketEnqueueTime( RtpPacketMediaType type) const { - const int priority_level = GetPriorityForType(type); + RTC_DCHECK(type != RtpPacketMediaType::kRetransmission); + const int priority_level = GetPriorityForType(type, absl::nullopt); if (streams_by_prio_[priority_level].empty()) { return Timestamp::MinusInfinity(); } @@ -222,6 +261,39 @@ Timestamp PrioritizedPacketQueue::LeadingPacketEnqueueTime( priority_level); } +Timestamp PrioritizedPacketQueue::LeadingPacketEnqueueTimeForRetransmission() + const { + if (!prioritize_audio_retransmission_) { + const int priority_level = + GetPriorityForType(RtpPacketMediaType::kRetransmission, absl::nullopt); + if (streams_by_prio_[priority_level].empty()) { + return Timestamp::PlusInfinity(); + } + return streams_by_prio_[priority_level].front()->LeadingPacketEnqueueTime( + priority_level); + } + const int audio_priority_level = + GetPriorityForType(RtpPacketMediaType::kRetransmission, + RtpPacketToSend::OriginalType::kAudio); + const int video_priority_level = + GetPriorityForType(RtpPacketMediaType::kRetransmission, + RtpPacketToSend::OriginalType::kVideo); + + Timestamp next_audio = + streams_by_prio_[audio_priority_level].empty() + ? Timestamp::PlusInfinity() + : streams_by_prio_[audio_priority_level] + .front() + ->LeadingPacketEnqueueTime(audio_priority_level); + Timestamp next_video = + streams_by_prio_[video_priority_level].empty() + ? Timestamp::PlusInfinity() + : streams_by_prio_[video_priority_level] + .front() + ->LeadingPacketEnqueueTime(video_priority_level); + return std::min(next_audio, next_video); +} + Timestamp PrioritizedPacketQueue::OldestEnqueueTime() const { return enqueue_times_.empty() ? Timestamp::MinusInfinity() : enqueue_times_.front(); @@ -283,9 +355,6 @@ void PrioritizedPacketQueue::RemovePacketsForSsrc(uint32_t ssrc) { // Update the global top prio level if neccessary. RTC_DCHECK(streams_by_prio_[i].front() == &queue); streams_by_prio_[i].pop_front(); - if (i == top_active_prio_level_) { - MaybeUpdateTopPrioLevel(); - } } else { // More than stream had packets at this prio level, filter this one out. std::deque filtered_queue; @@ -298,6 +367,7 @@ void PrioritizedPacketQueue::RemovePacketsForSsrc(uint32_t ssrc) { } } } + MaybeUpdateTopPrioLevel(); } bool PrioritizedPacketQueue::HasKeyframePackets(uint32_t ssrc) const { @@ -340,18 +410,53 @@ void PrioritizedPacketQueue::DequeuePacketInternal(QueuedPacket& packet) { } void PrioritizedPacketQueue::MaybeUpdateTopPrioLevel() { - if (streams_by_prio_[top_active_prio_level_].empty()) { - // No stream queues have packets at this prio level, find top priority - // that is not empty. - if (size_packets_ == 0) { - top_active_prio_level_ = -1; + if (top_active_prio_level_ != -1 && + !streams_by_prio_[top_active_prio_level_].empty()) { + return; + } + // No stream queues have packets at top_active_prio_level_, find top priority + // that is not empty. + for (int i = 0; i < kNumPriorityLevels; ++i) { + PurgeOldPacketsAtPriorityLevel(i, last_update_time_); + if (!streams_by_prio_[i].empty()) { + top_active_prio_level_ = i; + break; + } + } + if (size_packets_ == 0) { + // There are no packets left to send. Last packet may have been purged. Prio + // will change when a new packet is pushed. + top_active_prio_level_ = -1; + } +} + +void PrioritizedPacketQueue::PurgeOldPacketsAtPriorityLevel(int prio_level, + Timestamp now) { + RTC_DCHECK(prio_level >= 0 && prio_level < kNumPriorityLevels); + TimeDelta time_to_live = time_to_live_per_prio_[prio_level]; + if (time_to_live.IsInfinite()) { + return; + } + + std::deque& queues = streams_by_prio_[prio_level]; + auto iter = queues.begin(); + while (iter != queues.end()) { + StreamQueue* queue_ptr = *iter; + while (queue_ptr->HasPacketsAtPrio(prio_level) && + (now - queue_ptr->LeadingPacketEnqueueTime(prio_level)) > + time_to_live) { + QueuedPacket packet = queue_ptr->DequeuePacket(prio_level); + RTC_LOG(LS_INFO) << "Dropping old packet on SSRC: " + << packet.packet->Ssrc() + << " seq:" << packet.packet->SequenceNumber() + << " time in queue:" << (now - packet.enqueue_time).ms() + << " ms"; + DequeuePacketInternal(packet); + } + if (!queue_ptr->HasPacketsAtPrio(prio_level)) { + iter = queues.erase(iter); } else { - for (int i = 0; i < kNumPriorityLevels; ++i) { - if (!streams_by_prio_[i].empty()) { - top_active_prio_level_ = i; - break; - } - } + ++iter; } } } diff --git a/third_party/libwebrtc/modules/pacing/prioritized_packet_queue.h b/third_party/libwebrtc/modules/pacing/prioritized_packet_queue.h index 935c530027..179ef104fe 100644 --- a/third_party/libwebrtc/modules/pacing/prioritized_packet_queue.h +++ b/third_party/libwebrtc/modules/pacing/prioritized_packet_queue.h @@ -18,8 +18,8 @@ #include #include #include -#include +#include "absl/container/inlined_vector.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" @@ -27,9 +27,19 @@ namespace webrtc { +// Describes how long time a packet may stay in the queue before being dropped. +struct PacketQueueTTL { + TimeDelta audio_retransmission = TimeDelta::PlusInfinity(); + TimeDelta video_retransmission = TimeDelta::PlusInfinity(); + TimeDelta video = TimeDelta::PlusInfinity(); +}; + class PrioritizedPacketQueue { public: - explicit PrioritizedPacketQueue(Timestamp creation_time); + explicit PrioritizedPacketQueue( + Timestamp creation_time, + bool prioritize_audio_retransmission = false, + PacketQueueTTL packet_queue_ttl = PacketQueueTTL()); PrioritizedPacketQueue(const PrioritizedPacketQueue&) = delete; PrioritizedPacketQueue& operator=(const PrioritizedPacketQueue&) = delete; @@ -63,6 +73,7 @@ class PrioritizedPacketQueue { // method, for the given packet type. If queue has no packets, of that type, // returns Timestamp::MinusInfinity(). Timestamp LeadingPacketEnqueueTime(RtpPacketMediaType type) const; + Timestamp LeadingPacketEnqueueTimeForRetransmission() const; // Enqueue time of the oldest packet in the queue, // Timestamp::MinusInfinity() if queue is empty. @@ -90,7 +101,7 @@ class PrioritizedPacketQueue { bool HasKeyframePackets(uint32_t ssrc) const; private: - static constexpr int kNumPriorityLevels = 4; + static constexpr int kNumPriorityLevels = 5; class QueuedPacket { public: @@ -139,6 +150,15 @@ class PrioritizedPacketQueue { // if so move it to the lowest non-empty index. void MaybeUpdateTopPrioLevel(); + void PurgeOldPacketsAtPriorityLevel(int prio_level, Timestamp now); + + static absl::InlinedVector ToTtlPerPrio( + PacketQueueTTL); + + const bool prioritize_audio_retransmission_; + const absl::InlinedVector + time_to_live_per_prio_; + // Cumulative sum, over all packets, of time spent in the queue. TimeDelta queue_time_sum_; // Cumulative sum of time the queue has spent in a paused state. diff --git a/third_party/libwebrtc/modules/pacing/prioritized_packet_queue_unittest.cc b/third_party/libwebrtc/modules/pacing/prioritized_packet_queue_unittest.cc index 9ed19642c7..76c31036b3 100644 --- a/third_party/libwebrtc/modules/pacing/prioritized_packet_queue_unittest.cc +++ b/third_party/libwebrtc/modules/pacing/prioritized_packet_queue_unittest.cc @@ -10,6 +10,7 @@ #include "modules/pacing/prioritized_packet_queue.h" +#include #include #include "api/units/time_delta.h" @@ -26,18 +27,39 @@ constexpr uint32_t kDefaultSsrc = 123; constexpr int kDefaultPayloadSize = 789; std::unique_ptr CreatePacket(RtpPacketMediaType type, - uint16_t sequence_number, + uint16_t seq, uint32_t ssrc = kDefaultSsrc, bool is_key_frame = false) { auto packet = std::make_unique(/*extensions=*/nullptr); packet->set_packet_type(type); packet->SetSsrc(ssrc); - packet->SetSequenceNumber(sequence_number); + packet->SetSequenceNumber(seq); packet->SetPayloadSize(kDefaultPayloadSize); packet->set_is_key_frame(is_key_frame); return packet; } +std::unique_ptr CreateRetransmissionPacket( + RtpPacketMediaType original_type, + uint16_t seq, + uint32_t ssrc = kDefaultSsrc) { + auto packet = std::make_unique(/*extensions=*/nullptr); + packet->set_packet_type(original_type); + packet->set_packet_type(RtpPacketMediaType::kRetransmission); + RTC_DCHECK(packet->packet_type() == RtpPacketMediaType::kRetransmission); + if (original_type == RtpPacketMediaType::kVideo) { + RTC_DCHECK(packet->original_packet_type() == + RtpPacketToSend::OriginalType::kVideo); + } else { + RTC_DCHECK(packet->original_packet_type() == + RtpPacketToSend::OriginalType::kAudio); + } + packet->SetSsrc(ssrc); + packet->SetSequenceNumber(seq); + packet->SetPayloadSize(kDefaultPayloadSize); + return packet; +} + } // namespace TEST(PrioritizedPacketQueue, ReturnsPacketsInPrioritizedOrder) { @@ -49,18 +71,42 @@ TEST(PrioritizedPacketQueue, ReturnsPacketsInPrioritizedOrder) { queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, /*seq=*/2)); queue.Push(now, CreatePacket(RtpPacketMediaType::kForwardErrorCorrection, /*seq=*/3)); - queue.Push(now, CreatePacket(RtpPacketMediaType::kRetransmission, /*seq=*/4)); - queue.Push(now, CreatePacket(RtpPacketMediaType::kAudio, /*seq=*/5)); + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kVideo, /*seq=*/4)); + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kAudio, /*seq=*/5)); + queue.Push(now, CreatePacket(RtpPacketMediaType::kAudio, /*seq=*/6)); // Packets should be returned in high to low order. - EXPECT_EQ(queue.Pop()->SequenceNumber(), 5); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 6); + // Audio and video retransmission has same prio, but video was enqueued first. EXPECT_EQ(queue.Pop()->SequenceNumber(), 4); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 5); // Video and FEC prioritized equally - but video was enqueued first. EXPECT_EQ(queue.Pop()->SequenceNumber(), 2); EXPECT_EQ(queue.Pop()->SequenceNumber(), 3); EXPECT_EQ(queue.Pop()->SequenceNumber(), 1); } +TEST(PrioritizedPacketQueue, + PrioritizeAudioRetransmissionBeforeVideoRetransmissionIfConfigured) { + Timestamp now = Timestamp::Zero(); + PrioritizedPacketQueue queue(now, /*prioritize_audio_retransmission=*/true); + + // Add packets in low to high packet order. + queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, /*seq=*/3)); + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kVideo, /*seq=*/4)); + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kAudio, /*seq=*/5)); + queue.Push(now, CreatePacket(RtpPacketMediaType::kAudio, /*seq=*/6)); + + // Packets should be returned in high to low order. + EXPECT_EQ(queue.Pop()->SequenceNumber(), 6); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 5); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 4); +} + TEST(PrioritizedPacketQueue, ReturnsEqualPrioPacketsInRoundRobinOrder) { Timestamp now = Timestamp::Zero(); PrioritizedPacketQueue queue(now); @@ -251,6 +297,26 @@ TEST(PrioritizedPacketQueue, ReportsLeadingPacketEnqueueTime) { Timestamp::MinusInfinity()); } +TEST(PrioritizedPacketQueue, ReportsLeadingPacketEnqueueTimeForRetransmission) { + PrioritizedPacketQueue queue(/*creation_time=*/Timestamp::Zero(), + /*prioritize_audio_retransmission=*/true); + EXPECT_EQ(queue.LeadingPacketEnqueueTimeForRetransmission(), + Timestamp::PlusInfinity()); + + queue.Push(Timestamp::Millis(10), + CreateRetransmissionPacket(RtpPacketMediaType::kVideo, /*seq=*/1)); + queue.Push(Timestamp::Millis(11), + CreateRetransmissionPacket(RtpPacketMediaType::kAudio, /*seq=*/2)); + EXPECT_EQ(queue.LeadingPacketEnqueueTimeForRetransmission(), + Timestamp::Millis(10)); + queue.Pop(); // Pop audio retransmission since it has higher prio. + EXPECT_EQ(queue.LeadingPacketEnqueueTimeForRetransmission(), + Timestamp::Millis(10)); + queue.Pop(); // Pop video retransmission. + EXPECT_EQ(queue.LeadingPacketEnqueueTimeForRetransmission(), + Timestamp::PlusInfinity()); +} + TEST(PrioritizedPacketQueue, PushAndPopUpdatesSizeInPacketsPerRtpPacketMediaType) { Timestamp now = Timestamp::Zero(); @@ -272,7 +338,7 @@ TEST(PrioritizedPacketQueue, RtpPacketMediaType::kVideo)], 1); - queue.Push(now, CreatePacket(RtpPacketMediaType::kRetransmission, 3)); + queue.Push(now, CreateRetransmissionPacket(RtpPacketMediaType::kVideo, 3)); EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[static_cast( RtpPacketMediaType::kRetransmission)], 1); @@ -326,6 +392,8 @@ TEST(PrioritizedPacketQueue, ClearsPackets) { // Remove all of them. queue.RemovePacketsForSsrc(kSsrc); EXPECT_TRUE(queue.Empty()); + queue.RemovePacketsForSsrc(kSsrc); + EXPECT_TRUE(queue.Empty()); } TEST(PrioritizedPacketQueue, ClearPacketsAffectsOnlySpecifiedSsrc) { @@ -338,16 +406,16 @@ TEST(PrioritizedPacketQueue, ClearPacketsAffectsOnlySpecifiedSsrc) { // ensuring they are first in line. queue.Push( now, CreatePacket(RtpPacketMediaType::kAudio, /*seq=*/1, kRemovingSsrc)); - queue.Push(now, CreatePacket(RtpPacketMediaType::kRetransmission, /*seq=*/2, - kRemovingSsrc)); + queue.Push(now, CreateRetransmissionPacket(RtpPacketMediaType::kVideo, + /*seq=*/2, kRemovingSsrc)); // Add a video packet and a retransmission for the SSRC that will remain. // The retransmission packets now both have pointers to their respective qeues // from the same prio level. queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, /*seq=*/3, kStayingSsrc)); - queue.Push(now, CreatePacket(RtpPacketMediaType::kRetransmission, /*seq=*/4, - kStayingSsrc)); + queue.Push(now, CreateRetransmissionPacket(RtpPacketMediaType::kVideo, + /*seq=*/4, kStayingSsrc)); EXPECT_EQ(queue.SizeInPackets(), 4); @@ -413,4 +481,87 @@ TEST(PrioritizedPacketQueue, ReportsKeyframePackets) { EXPECT_FALSE(queue.HasKeyframePackets(kVideoSsrc2)); } +TEST(PrioritizedPacketQueue, PacketsDroppedIfNotPulledWithinTttl) { + Timestamp now = Timestamp::Zero(); + PacketQueueTTL ttls; + ttls.audio_retransmission = TimeDelta::Millis(200); + PrioritizedPacketQueue queue(now, /*prioritize_audio_retransmission=*/true, + ttls); + + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kAudio, /*seq=*/1)); + now += ttls.audio_retransmission + TimeDelta::Millis(1); + EXPECT_EQ(queue.SizeInPackets(), 1); + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kAudio, /*seq=*/2)); + EXPECT_EQ(queue.SizeInPackets(), 1); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 2); +} + +TEST(PrioritizedPacketQueue, DontSendPacketsAfterTttl) { + Timestamp now = Timestamp::Zero(); + PacketQueueTTL ttls; + ttls.audio_retransmission = TimeDelta::Millis(200); + PrioritizedPacketQueue queue(now, /*prioritize_audio_retransmission=*/true, + ttls); + + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kAudio, /*seq=*/1)); + now += ttls.audio_retransmission + TimeDelta::Millis(1); + EXPECT_EQ(queue.SizeInPackets(), 1); + queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, /*seq=*/2)); + queue.Push(now, CreatePacket(RtpPacketMediaType::kAudio, /*seq=*/3)); + // Expect the old packet to have been removed since it was not popped in time. + EXPECT_EQ(queue.SizeInPackets(), 3); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 3); + EXPECT_EQ(queue.SizeInPackets(), 1); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 2); + EXPECT_EQ(queue.SizeInPackets(), 0); +} + +TEST(PrioritizedPacketQueue, SendsNewVideoPacketAfterPurgingLastOldRtxPacket) { + Timestamp now = Timestamp::Zero(); + PacketQueueTTL ttls; + ttls.video_retransmission = TimeDelta::Millis(400); + PrioritizedPacketQueue queue(now, /*prioritize_audio_retransmission=*/true, + ttls); + + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kVideo, /*seq=*/1)); + now += ttls.video_retransmission + TimeDelta::Millis(1); + queue.Push(now, CreatePacket(RtpPacketMediaType::kAudio, /*seq=*/2)); + EXPECT_EQ(queue.SizeInPackets(), 2); + // Expect the audio packet to be send and the video retransmission packet to + // be dropped since it is old. + EXPECT_EQ(queue.Pop()->SequenceNumber(), 2); + EXPECT_EQ(queue.SizeInPackets(), 0); + + queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, /*seq=*/3)); + EXPECT_EQ(queue.SizeInPackets(), 1); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 3); + EXPECT_EQ(queue.SizeInPackets(), 0); +} + +TEST(PrioritizedPacketQueue, + SendsPacketsAfterTttlIfPrioHigherThanPushedPackets) { + Timestamp now = Timestamp::Zero(); + PacketQueueTTL ttls; + ttls.audio_retransmission = TimeDelta::Millis(200); + PrioritizedPacketQueue queue(now, /*prioritize_audio_retransmission=*/true, + ttls); + + queue.Push(now, + CreateRetransmissionPacket(RtpPacketMediaType::kAudio, /*seq=*/1)); + now += ttls.audio_retransmission + TimeDelta::Millis(1); + EXPECT_EQ(queue.SizeInPackets(), 1); + queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, /*seq=*/2)); + + // This test just show that TTL is not enforced strictly. If a new audio + // packet had been queued before a packet was popped, the audio retransmission + // packet would have been dropped. + EXPECT_EQ(queue.SizeInPackets(), 2); + EXPECT_EQ(queue.Pop()->SequenceNumber(), 1); + EXPECT_EQ(queue.SizeInPackets(), 1); +} + } // namespace webrtc diff --git a/third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc b/third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc index e100995b8e..6953ec8400 100644 --- a/third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc +++ b/third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc @@ -260,8 +260,11 @@ void RemoteEstimatorProxy::SendFeedbackOnRequest( feedback_request.include_timestamps, first_sequence_number, sequence_number + 1, /*is_periodic_update=*/false); - // This is called when a packet has just been added. - RTC_DCHECK(feedback_packet != nullptr); + // Even though this is called when a packet has just been added, + // no feedback may be produced when that new packet is too old. + if (feedback_packet == nullptr) { + return; + } // Clear up to the first packet that is included in this feedback packet. packet_arrival_times_.EraseTo(first_sequence_number); diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc index 0e5e40f502..1dc56bb96f 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc @@ -18,6 +18,7 @@ #include "api/units/time_delta.h" #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" #include "modules/rtp_rtcp/source/rtp_packet_received.h" #include "modules/rtp_rtcp/source/rtp_rtcp_config.h" @@ -159,16 +160,15 @@ void StreamStatisticianImpl::UpdateJitter(const RtpPacketReceived& packet, int32_t time_diff_samples = receive_diff_rtp - (packet.Timestamp() - last_received_timestamp_); - time_diff_samples = std::abs(time_diff_samples); - ReviseFrequencyAndJitter(packet.payload_type_frequency()); // lib_jingle sometimes deliver crazy jumps in TS for the same stream. // If this happens, don't update jitter value. Use 5 secs video frequency // as the threshold. - if (time_diff_samples < 450000) { + if (time_diff_samples < 5 * kVideoPayloadTypeFrequency && + time_diff_samples > -5 * kVideoPayloadTypeFrequency) { // Note we calculate in Q4 to avoid using float. - int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_; + int32_t jitter_diff_q4 = (std::abs(time_diff_samples) << 4) - jitter_q4_; jitter_q4_ += ((jitter_diff_q4 + 8) >> 4); } } diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc index a2558545f0..8b31912f0f 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc @@ -898,5 +898,22 @@ TEST(ReviseJitterTest, EXPECT_EQ(GetJitter(*statistics), 172U); } +TEST(ReviseJitterTest, TwoPacketsWithMaximumRtpTimestampDifference) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/90'000, + /*timestamp=*/0x01234567); + RtpPacketReceived packet2 = + MakeNextRtpPacket(packet1, + /*payload_type_frequency=*/90'000, + /*timestamp=*/0x81234567); + statistics->OnRtpPacket(packet1); + statistics->OnRtpPacket(packet2); + + // Expect large jump in RTP timestamp is ignored for jitter calculation. + EXPECT_EQ(GetJitter(*statistics), 0U); +} + } // namespace } // namespace webrtc diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtcp_receiver.cc index bda6ad9a52..756136866d 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -1190,11 +1190,11 @@ std::vector RTCPReceiver::TmmbrReceived() { MutexLock lock(&rtcp_receiver_lock_); std::vector candidates; - Timestamp timeout = clock_->CurrentTime() - kTmmbrTimeoutInterval; + Timestamp now = clock_->CurrentTime(); for (auto& kv : tmmbr_infos_) { for (auto it = kv.second.tmmbr.begin(); it != kv.second.tmmbr.end();) { - if (it->second.last_updated < timeout) { + if (now - it->second.last_updated > kTmmbrTimeoutInterval) { // Erase timeout entries. it = kv.second.tmmbr.erase(it); } else { diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.cc index fd42b798d4..27b0420926 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.cc @@ -52,4 +52,17 @@ bool RtpDependencyDescriptorExtension::Write( return writer.Write(); } +bool RtpDependencyDescriptorExtensionMandatory::Parse( + rtc::ArrayView data, + DependencyDescriptorMandatory* descriptor) { + if (data.size() < 3) { + return false; + } + descriptor->set_first_packet_in_frame(data[0] & 0b1000'0000); + descriptor->set_last_packet_in_frame(data[0] & 0b0100'0000); + descriptor->set_template_id(data[0] & 0b0011'1111); + descriptor->set_frame_number((uint16_t{data[1]} << 8) | data[2]); + return true; +} + } // namespace webrtc diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h index 8d6e4b8d37..a3e415917c 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h @@ -54,6 +54,16 @@ class RtpDependencyDescriptorExtension { static constexpr std::bitset<32> kAllChainsAreActive = ~uint32_t{0}; }; +// Trait to only read the mandatory part of the descriptor. +class RtpDependencyDescriptorExtensionMandatory { + public: + static constexpr webrtc::RTPExtensionType kId = + webrtc::RtpDependencyDescriptorExtension::kId; + + static bool Parse(rtc::ArrayView data, + DependencyDescriptorMandatory* descriptor); +}; + } // namespace webrtc #endif // MODULES_RTP_RTCP_SOURCE_RTP_DEPENDENCY_DESCRIPTOR_EXTENSION_H_ diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_h264.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_h264.cc index d066bafb90..9c1dc4edb8 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_h264.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_h264.cc @@ -19,6 +19,7 @@ #include #include +#include "absl/algorithm/container.h" #include "absl/types/optional.h" #include "absl/types/variant.h" #include "common_video/h264/h264_common.h" @@ -52,11 +53,14 @@ RtpPacketizerH264::RtpPacketizerH264(rtc::ArrayView payload, input_fragments_.push_back( payload.subview(nalu.payload_start_offset, nalu.payload_size)); } - - if (!GeneratePackets(packetization_mode)) { - // If failed to generate all the packets, discard already generated - // packets in case the caller would ignore return value and still try to - // call NextPacket(). + bool has_empty_fragments = absl::c_any_of( + input_fragments_, [](const rtc::ArrayView fragment) { + return fragment.empty(); + }); + if (has_empty_fragments || !GeneratePackets(packetization_mode)) { + // If empty fragments were found or we failed to generate all the packets, + // discard already generated packets in case the caller would ignore the + // return value and still try to call NextPacket(). num_packets_left_ = 0; while (!packets_.empty()) { packets_.pop(); @@ -73,6 +77,7 @@ size_t RtpPacketizerH264::NumPackets() const { bool RtpPacketizerH264::GeneratePackets( H264PacketizationMode packetization_mode) { for (size_t i = 0; i < input_fragments_.size();) { + RTC_DCHECK(!input_fragments_[i].empty()); switch (packetization_mode) { case H264PacketizationMode::SingleNalUnit: if (!PacketizeSingleNalu(i)) @@ -173,11 +178,11 @@ size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) { return fragment_size; } }; - while (payload_size_left >= payload_size_needed()) { RTC_CHECK_GT(fragment.size(), 0); - packets_.push(PacketUnit(fragment, aggregated_fragments == 0, false, true, - fragment[0])); + + packets_.push(PacketUnit(fragment, /*first=*/aggregated_fragments == 0, + /*last=*/false, /*aggregated=*/true, fragment[0])); payload_size_left -= fragment.size(); payload_size_left -= fragment_headers_length; @@ -218,9 +223,9 @@ bool RtpPacketizerH264::PacketizeSingleNalu(size_t fragment_index) { << limits_.max_payload_len; return false; } - RTC_CHECK_GT(fragment.size(), 0u); - packets_.push(PacketUnit(fragment, true /* first */, true /* last */, - false /* aggregated */, fragment[0])); + RTC_CHECK(!fragment.empty()); + packets_.push(PacketUnit(fragment, /*first=*/true, /*last=*/true, + /*aggregated=*/false, fragment[0])); ++num_packets_left_; return true; } diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc index 18311c6e8c..3920c4acd5 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc @@ -116,6 +116,7 @@ std::vector FetchAllPackets(RtpPacketizerH264* packetizer) { RtpPacketToSend packet(kNoExtensions); while (packetizer->NextPacket(&packet)) { result.push_back(packet); + packet.Clear(); } EXPECT_THAT(result, SizeIs(num_packets)); return result; @@ -527,5 +528,190 @@ TEST(RtpPacketizerH264Test, RejectsOverlongDataInPacketizationMode0) { EXPECT_THAT(packets, IsEmpty()); } + +TEST(RtpPacketizerH264Test, DoesNotPacketizeWithEmptyNalUnit) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = kMaxPayloadSize; + + uint8_t empty_nal_input[] = {0x00, 0x00, 0x01, /* empty NAL unit data */ + 0x00, 0x00, 0x01, 0x01}; + RtpPacketizerH264 packetizer(empty_nal_input, limits, + H264PacketizationMode::NonInterleaved); + EXPECT_EQ(packetizer.NumPackets(), 0u); +} + +TEST(RtpPacketizerH264Test, MultipleStapA) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = kMaxPayloadSize; + limits.first_packet_reduction_len = 0; + limits.last_packet_reduction_len = 0; + limits.single_packet_reduction_len = 0; + // A lot of small NAL units that will result in two STAP-A being generated. + // Input data must exceed the size of a single RTP packet. + uint8_t long_input[] = { + 0x19, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x00, 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, + 0x04, 0x00, 0x19, 0x00, 0x00, 0x01, 0xf9, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf7, 0x01, + 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x01, 0x04, 0x00, + 0x19, 0x00, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, + 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, + 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x19, + 0x7a, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, + 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, + 0x00, 0x00, 0x11, 0xd4, 0x00, 0x19, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x01, 0x00, 0xaf, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, + 0x00, 0x01, 0xf9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x08, 0xfe, 0xfb, 0xff, 0xff, 0xf4, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x01, 0x00, 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x11, 0xd4, 0x00, 0x19, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, + 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, + 0x00, 0x00, 0x00, 0x00, 0x11, 0xd4, 0x00, 0x19, 0x00, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, + 0x01, 0xf9, 0x01, 0x00, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0xf7, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, 0x01, 0x01, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xf7, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x00, 0xf7, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x26, 0x00, 0x00, 0x01, 0x00, + 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, + 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, + 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, 0x01, 0xf9, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0xf7, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x2c, + 0x01, 0x04, 0x00, 0x19, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, + 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, + 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x19, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, + 0x00, 0x01, 0xf9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x08, 0xfe, 0xfb, 0xff, 0xff, 0xf4, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x01, 0x00, 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, + 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x11, 0xd4, 0x00, + 0x19, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x00, 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, + 0x04, 0x00, 0x19, 0x00, 0x00, 0x01, 0xf9, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf7, 0x01, + 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, + 0x19, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, + 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf7, 0x01, 0x04, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0xf7, 0x01, 0x04, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, + 0x26, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, + 0x00, 0x00, 0x00, 0x11, 0xd4, 0x00, 0x19, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x01, 0x04, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0xaf, 0x00, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, + 0x00, 0xaf, 0x01, 0x04, 0x00, 0x19, 0x00, 0x00, 0x01, 0xf9, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0xf7, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, + 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x8e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01}; + RtpPacketizerH264 packetizer(long_input, limits, + H264PacketizationMode::NonInterleaved); + EXPECT_EQ(packetizer.NumPackets(), 2u); + EXPECT_THAT(FetchAllPackets(&packetizer), SizeIs(2)); +} + } // namespace } // namespace webrtc diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc index ae5f4e50a4..34b3fd9d2f 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc @@ -63,7 +63,9 @@ RtpPacketizerVp8::RtpPacketizerVp8(rtc::ArrayView payload, const RTPVideoHeaderVP8& hdr_info) : hdr_(BuildHeader(hdr_info)), remaining_payload_(payload) { limits.max_payload_len -= hdr_.size(); - payload_sizes_ = SplitAboutEqually(payload.size(), limits); + if (!payload.empty()) { + payload_sizes_ = SplitAboutEqually(payload.size(), limits); + } current_packet_ = payload_sizes_.begin(); } diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc index 7934ff8ea9..cab7fc4422 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc @@ -21,6 +21,18 @@ namespace { constexpr RtpPacketizer::PayloadSizeLimits kNoSizeLimits; +TEST(RtpPacketizerVp8Test, EmptyPayload) { + RTPVideoHeaderVP8 hdr_info; + hdr_info.InitRTPVideoHeaderVP8(); + hdr_info.pictureId = 200; + RtpFormatVp8TestHelper helper(&hdr_info, /*payload_len=*/30); + + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 12; // Small enough to produce 4 packets. + RtpPacketizerVp8 packetizer({}, limits, hdr_info); + EXPECT_EQ(packetizer.NumPackets(), 0u); +} + TEST(RtpPacketizerVp8Test, ResultPacketsAreAlmostEqualSize) { RTPVideoHeaderVP8 hdr_info; hdr_info.InitRTPVideoHeaderVP8(); diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc index 9ad4aa97c3..5e037859ce 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc @@ -321,8 +321,9 @@ RtpPacketizerVp9::RtpPacketizerVp9(rtc::ArrayView payload, limits.max_payload_len -= header_size_; limits.first_packet_reduction_len += first_packet_extra_header_size_; limits.single_packet_reduction_len += first_packet_extra_header_size_; - - payload_sizes_ = SplitAboutEqually(payload.size(), limits); + if (!payload.empty()) { + payload_sizes_ = SplitAboutEqually(payload.size(), limits); + } current_packet_ = payload_sizes_.begin(); } diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc index e18b8a803f..948bcf3bdb 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc @@ -186,6 +186,11 @@ class RtpPacketizerVp9Test : public ::testing::Test { } }; +TEST_F(RtpPacketizerVp9Test, EmptyPayload) { + RTPVideoHeader video_header; + VideoRtpDepacketizerVp9::ParseRtpPayload({}, &video_header); +} + TEST_F(RtpPacketizerVp9Test, TestEqualSizedMode_OnePacket) { const size_t kFrameSize = 25; const size_t kPacketSize = 26; diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet.h b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet.h index e91ec6368b..c002e51de6 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet.h +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet.h @@ -11,6 +11,7 @@ #define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_ #include +#include #include #include "absl/types/optional.h" @@ -127,7 +128,7 @@ class RtpPacket { bool IsRegistered() const; template - bool GetExtension(FirstValue, Values...) const; + bool GetExtension(FirstValue&&, Values&&...) const; template absl::optional GetExtension() const; @@ -231,11 +232,12 @@ bool RtpPacket::IsRegistered() const { } template -bool RtpPacket::GetExtension(FirstValue first, Values... values) const { +bool RtpPacket::GetExtension(FirstValue&& first, Values&&... values) const { auto raw = FindExtension(Extension::kId); if (raw.empty()) return false; - return Extension::Parse(raw, first, values...); + return Extension::Parse(raw, std::forward(first), + std::forward(values)...); } template diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_to_send.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_to_send.cc index b55e74aaf0..691a243c5f 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_to_send.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_to_send.cc @@ -12,6 +12,8 @@ #include +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" + namespace webrtc { RtpPacketToSend::RtpPacketToSend(const ExtensionManager* extensions) @@ -28,4 +30,13 @@ RtpPacketToSend& RtpPacketToSend::operator=(RtpPacketToSend&& packet) = default; RtpPacketToSend::~RtpPacketToSend() = default; +void RtpPacketToSend::set_packet_type(RtpPacketMediaType type) { + if (packet_type_ == RtpPacketMediaType::kAudio) { + original_packet_type_ = OriginalType::kAudio; + } else if (packet_type_ == RtpPacketMediaType::kVideo) { + original_packet_type_ = OriginalType::kVideo; + } + packet_type_ = type; +} + } // namespace webrtc diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h index 438ca354ed..64f9ee1ab1 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h @@ -49,11 +49,18 @@ class RtpPacketToSend : public RtpPacket { webrtc::Timestamp capture_time() const { return capture_time_; } void set_capture_time(webrtc::Timestamp time) { capture_time_ = time; } - void set_packet_type(RtpPacketMediaType type) { packet_type_ = type; } + void set_packet_type(RtpPacketMediaType type); + absl::optional packet_type() const { return packet_type_; } + enum class OriginalType { kAudio, kVideo }; + // Original type does not change if packet type is changed to kRetransmission. + absl::optional original_packet_type() const { + return original_packet_type_; + } + // If this is a retransmission, indicates the sequence number of the original // media packet that this packet represents. If RTX is used this will likely // be different from SequenceNumber(). @@ -133,6 +140,7 @@ class RtpPacketToSend : public RtpPacket { private: webrtc::Timestamp capture_time_ = webrtc::Timestamp::Zero(); absl::optional packet_type_; + absl::optional original_packet_type_; bool allow_retransmission_ = false; absl::optional retransmitted_sequence_number_; rtc::scoped_refptr additional_data_; diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc index b3a9452df9..44f1a9e742 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc @@ -933,6 +933,41 @@ TEST(RtpPacketTest, GetUncopyableExtension) { EXPECT_TRUE(rtp_packet.GetExtension(&value2)); } +struct ParseByReferenceExtension { + static constexpr RTPExtensionType kId = kRtpExtensionDependencyDescriptor; + static constexpr absl::string_view Uri() { return "uri"; } + + static size_t ValueSize(uint8_t value1, uint8_t value2) { return 2; } + static bool Write(rtc::ArrayView data, + uint8_t value1, + uint8_t value2) { + data[0] = value1; + data[1] = value2; + return true; + } + static bool Parse(rtc::ArrayView data, + uint8_t& value1, + uint8_t& value2) { + value1 = data[0]; + value2 = data[1]; + return true; + } +}; + +TEST(RtpPacketTest, GetExtensionByReference) { + RtpHeaderExtensionMap extensions; + extensions.Register(1); + RtpPacket rtp_packet(&extensions); + rtp_packet.SetExtension(13, 42); + + uint8_t value1 = 1; + uint8_t value2 = 1; + EXPECT_TRUE( + rtp_packet.GetExtension(value1, value2)); + EXPECT_EQ(int{value1}, 13); + EXPECT_EQ(int{value2}, 42); +} + TEST(RtpPacketTest, CreateAndParseTimingFrameExtension) { // Create a packet with video frame timing extension populated. RtpPacketToSend::ExtensionManager send_extensions; diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc index 2151a59295..83a2be24ea 100644 --- a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc @@ -99,6 +99,12 @@ Av1Frame ReassembleFrame(rtc::ArrayView rtp_payloads) { return Av1Frame(VideoRtpDepacketizerAv1().AssembleFrame(payloads)); } +TEST(RtpPacketizerAv1Test, EmptyPayload) { + RtpPacketizer::PayloadSizeLimits limits; + RtpPacketizerAv1 packetizer({}, limits, VideoFrameType::kVideoFrameKey, true); + EXPECT_EQ(packetizer.NumPackets(), 0u); +} + TEST(RtpPacketizerAv1Test, PacketizeOneObuWithoutSizeAndExtension) { auto kFrame = BuildAv1Frame({Av1Obu(kAv1ObuTypeFrame) .WithoutSize() diff --git a/third_party/libwebrtc/modules/video_capture/BUILD.gn b/third_party/libwebrtc/modules/video_capture/BUILD.gn index 45a0272eee..3132e452ba 100644 --- a/third_party/libwebrtc/modules/video_capture/BUILD.gn +++ b/third_party/libwebrtc/modules/video_capture/BUILD.gn @@ -173,6 +173,7 @@ if (!build_with_chromium || is_linux || is_chromeos) { "../../api/video:video_frame", "../../api/video:video_rtp_headers", "../../common_video", + "../../rtc_base:gunit_helpers", "../../rtc_base:timeutils", "../../rtc_base/synchronization:mutex", "../../system_wrappers", diff --git a/third_party/libwebrtc/modules/video_capture/test/video_capture_unittest.cc b/third_party/libwebrtc/modules/video_capture/test/video_capture_unittest.cc index c8af222b57..dec8de70cb 100644 --- a/third_party/libwebrtc/modules/video_capture/test/video_capture_unittest.cc +++ b/third_party/libwebrtc/modules/video_capture/test/video_capture_unittest.cc @@ -22,35 +22,16 @@ #include "api/video/video_frame.h" #include "common_video/libyuv/include/webrtc_libyuv.h" #include "modules/video_capture/video_capture_factory.h" +#include "rtc_base/gunit.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/time_utils.h" -#include "system_wrappers/include/sleep.h" #include "test/frame_utils.h" #include "test/gtest.h" -using webrtc::SleepMs; using webrtc::VideoCaptureCapability; using webrtc::VideoCaptureFactory; using webrtc::VideoCaptureModule; -#define WAIT_(ex, timeout, res) \ - do { \ - res = (ex); \ - int64_t start = rtc::TimeMillis(); \ - while (!res && rtc::TimeMillis() < start + timeout) { \ - SleepMs(5); \ - res = (ex); \ - } \ - } while (0) - -#define EXPECT_TRUE_WAIT(ex, timeout) \ - do { \ - bool res; \ - WAIT_(ex, timeout, res); \ - if (!res) \ - EXPECT_TRUE(ex); \ - } while (0) - static const int kTimeOut = 5000; #ifdef WEBRTC_MAC static const int kTestHeight = 288; diff --git a/third_party/libwebrtc/modules/video_coding/BUILD.gn b/third_party/libwebrtc/modules/video_coding/BUILD.gn index d9e614ff81..0457b818c3 100644 --- a/third_party/libwebrtc/modules/video_coding/BUILD.gn +++ b/third_party/libwebrtc/modules/video_coding/BUILD.gn @@ -218,6 +218,7 @@ rtc_library("video_coding") { "../../api:rtp_packet_info", "../../api:scoped_refptr", "../../api:sequence_checker", + "../../api/environment", "../../api/task_queue", "../../api/units:data_rate", "../../api/units:data_size", @@ -258,7 +259,6 @@ rtc_library("video_coding") { "../../rtc_base/task_utils:repeating_task", "../../rtc_base/third_party/base64", "../../system_wrappers", - "../../system_wrappers:field_trial", "../../system_wrappers:metrics", "../../video/config:encoder_config", "../rtp_rtcp", @@ -1217,6 +1217,7 @@ if (rtc_include_tests) { "../../api:scoped_refptr", "../../api:simulcast_test_fixture_api", "../../api:videocodec_test_fixture_api", + "../../api/environment:environment_factory", "../../api/task_queue", "../../api/task_queue:default_task_queue_factory", "../../api/test/video:function_video_factory", diff --git a/third_party/libwebrtc/modules/video_coding/codecs/av1/dav1d_decoder.cc b/third_party/libwebrtc/modules/video_coding/codecs/av1/dav1d_decoder.cc index 6a787ff935..d658e401e8 100644 --- a/third_party/libwebrtc/modules/video_coding/codecs/av1/dav1d_decoder.cc +++ b/third_party/libwebrtc/modules/video_coding/codecs/av1/dav1d_decoder.cc @@ -87,6 +87,8 @@ bool Dav1dDecoder::Configure(const Settings& settings) { s.n_threads = std::max(2, settings.number_of_cores()); s.max_frame_delay = 1; // For low latency decoding. s.all_layers = 0; // Don't output a frame for every spatial layer. + // Limit max frame size to avoid OOM'ing fuzzers. crbug.com/325284120. + s.frame_size_limit = 16384 * 16384; s.operating_point = 31; // Decode all operating points. return dav1d_open(&context_, &s) == 0; diff --git a/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc b/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc index 766b7660e4..d486c1d062 100644 --- a/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc +++ b/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc @@ -350,7 +350,8 @@ INSTANTIATE_TEST_SUITE_P( SvcTestParam{"L3T1", /*num_frames_to_generate=*/3}, SvcTestParam{"L3T3", /*num_frames_to_generate=*/8}, SvcTestParam{"S2T1", /*num_frames_to_generate=*/3}, - SvcTestParam{"S3T3", /*num_frames_to_generate=*/8}, + // TODO: bugs.webrtc.org/15715 - Re-enable once AV1 is fixed. + // SvcTestParam{"S3T3", /*num_frames_to_generate=*/8}, SvcTestParam{"L2T2", /*num_frames_to_generate=*/4}, SvcTestParam{"L2T2_KEY", /*num_frames_to_generate=*/4}, SvcTestParam{"L2T2_KEY_SHIFT", diff --git a/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc b/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc index a9e9926c4f..c6446c25ce 100644 --- a/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc +++ b/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc @@ -80,7 +80,11 @@ int H264DecoderImpl::AVGetBuffer2(AVCodecContext* context, kPixelFormatsSupported.begin(), kPixelFormatsSupported.end(), [context](AVPixelFormat format) { return context->pix_fmt == format; }); - RTC_CHECK(pixelFormatSupported != kPixelFormatsSupported.end()); + if (pixelFormatSupported == kPixelFormatsSupported.end()) { + RTC_LOG(LS_ERROR) << "Unsupported pixel format: " << context->pix_fmt; + decoder->ReportError(); + return -1; + } // `av_frame->width` and `av_frame->height` are set by FFmpeg. These are the // actual image's dimensions and may be different from `context->width` and diff --git a/third_party/libwebrtc/modules/video_coding/codecs/test/video_codec_test.cc b/third_party/libwebrtc/modules/video_coding/codecs/test/video_codec_test.cc index 60c2fcbb6e..2ab1106a59 100644 --- a/third_party/libwebrtc/modules/video_coding/codecs/test/video_codec_test.cc +++ b/third_party/libwebrtc/modules/video_coding/codecs/test/video_codec_test.cc @@ -178,7 +178,8 @@ std::string TestOutputPath() { } // namespace std::unique_ptr RunEncodeDecodeTest( - std::string codec_impl, + std::string encoder_impl, + std::string decoder_impl, const VideoInfo& video_info, const std::map& encoding_settings) { VideoSourceSettings source_settings{ @@ -190,28 +191,34 @@ std::unique_ptr RunEncodeDecodeTest( encoding_settings.begin()->second.sdp_video_format; std::unique_ptr encoder_factory = - CreateEncoderFactory(codec_impl); + CreateEncoderFactory(encoder_impl); if (!encoder_factory ->QueryCodecSupport(sdp_video_format, /*scalability_mode=*/absl::nullopt) .is_supported) { - RTC_LOG(LS_WARNING) << "No encoder for video format " + RTC_LOG(LS_WARNING) << "No " << encoder_impl << " encoder for video format " << sdp_video_format.ToString(); return nullptr; } std::unique_ptr decoder_factory = - CreateDecoderFactory(codec_impl); + CreateDecoderFactory(decoder_impl); if (!decoder_factory ->QueryCodecSupport(sdp_video_format, /*reference_scaling=*/false) .is_supported) { + RTC_LOG(LS_WARNING) << "No " << decoder_impl << " decoder for video format " + << sdp_video_format.ToString() + << ". Trying built-in decoder."; + // TODO(ssilkin): No H264 support in ffmpeg on ARM. Consider trying HW + // decoder. decoder_factory = CreateDecoderFactory("builtin"); if (!decoder_factory ->QueryCodecSupport(sdp_video_format, /*reference_scaling=*/false) .is_supported) { - RTC_LOG(LS_WARNING) << "No decoder for video format " + RTC_LOG(LS_WARNING) << "No " << decoder_impl + << " decoder for video format " << sdp_video_format.ToString(); return nullptr; } @@ -221,7 +228,7 @@ std::unique_ptr RunEncodeDecodeTest( VideoCodecTester::EncoderSettings encoder_settings; encoder_settings.pacing_settings.mode = - codec_impl == "builtin" ? PacingMode::kNoPacing : PacingMode::kRealTime; + encoder_impl == "builtin" ? PacingMode::kNoPacing : PacingMode::kRealTime; if (absl::GetFlag(FLAGS_dump_encoder_input)) { encoder_settings.encoder_input_base_path = output_path + "_enc_input"; } @@ -231,7 +238,7 @@ std::unique_ptr RunEncodeDecodeTest( VideoCodecTester::DecoderSettings decoder_settings; decoder_settings.pacing_settings.mode = - codec_impl == "builtin" ? PacingMode::kNoPacing : PacingMode::kRealTime; + decoder_impl == "builtin" ? PacingMode::kNoPacing : PacingMode::kRealTime; if (absl::GetFlag(FLAGS_dump_decoder_input)) { decoder_settings.decoder_input_base_path = output_path + "_dec_input"; } @@ -318,7 +325,7 @@ TEST_P(SpatialQualityTest, SpatialQuality) { {bitrate_kbps}, framerate_fps, num_frames); std::unique_ptr stats = - RunEncodeDecodeTest(codec_impl, video_info, frames_settings); + RunEncodeDecodeTest(codec_impl, codec_impl, video_info, frames_settings); VideoCodecStats::Stream stream; if (stats != nullptr) { @@ -348,15 +355,15 @@ INSTANTIATE_TEST_SUITE_P( Values("builtin"), #endif Values(kRawVideos.at("FourPeople_1280x720_30")), - Values(std::make_tuple(320, 180, 30, 32, 28), - std::make_tuple(320, 180, 30, 64, 30), - std::make_tuple(320, 180, 30, 128, 33), + Values(std::make_tuple(320, 180, 30, 32, 26), + std::make_tuple(320, 180, 30, 64, 29), + std::make_tuple(320, 180, 30, 128, 32), std::make_tuple(320, 180, 30, 256, 36), - std::make_tuple(640, 360, 30, 128, 31), + std::make_tuple(640, 360, 30, 128, 29), std::make_tuple(640, 360, 30, 256, 33), std::make_tuple(640, 360, 30, 384, 35), std::make_tuple(640, 360, 30, 512, 36), - std::make_tuple(1280, 720, 30, 256, 32), + std::make_tuple(1280, 720, 30, 256, 30), std::make_tuple(1280, 720, 30, 512, 34), std::make_tuple(1280, 720, 30, 1024, 37), std::make_tuple(1280, 720, 30, 2048, 39))), @@ -538,6 +545,7 @@ TEST(VideoCodecTest, DISABLED_EncodeDecode) { // Sync with changes in Stream::LogMetrics (see TODOs there). std::unique_ptr stats = RunEncodeDecodeTest( CodecNameToCodecImpl(absl::GetFlag(FLAGS_encoder)), + CodecNameToCodecImpl(absl::GetFlag(FLAGS_decoder)), kRawVideos.at(absl::GetFlag(FLAGS_video_name)), frames_settings); ASSERT_NE(nullptr, stats); diff --git a/third_party/libwebrtc/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc b/third_party/libwebrtc/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc index eb264e5285..35355d4387 100644 --- a/third_party/libwebrtc/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc +++ b/third_party/libwebrtc/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc @@ -167,7 +167,7 @@ SdpVideoFormat CreateSdpVideoFormat( H264PacketizationMode::NonInterleaved ? "1" : "0"; - SdpVideoFormat::Parameters codec_params = { + CodecParameterMap codec_params = { {cricket::kH264FmtpProfileLevelId, *H264ProfileLevelIdToString(H264ProfileLevelId( config.h264_codec_settings.profile, H264Level::kLevel3_1))}, diff --git a/third_party/libwebrtc/modules/video_coding/fec_controller_default.cc b/third_party/libwebrtc/modules/video_coding/fec_controller_default.cc index f204b01c7c..d548d6580c 100644 --- a/third_party/libwebrtc/modules/video_coding/fec_controller_default.cc +++ b/third_party/libwebrtc/modules/video_coding/fec_controller_default.cc @@ -15,30 +15,28 @@ #include #include +#include "api/environment/environment.h" +#include "api/field_trials_view.h" #include "modules/include/module_fec_types.h" #include "rtc_base/logging.h" -#include "system_wrappers/include/field_trial.h" +#include "system_wrappers/include/clock.h" namespace webrtc { const float kProtectionOverheadRateThreshold = 0.5; FecControllerDefault::FecControllerDefault( - Clock* clock, + const Environment& env, VCMProtectionCallback* protection_callback) - : clock_(clock), + : env_(env), protection_callback_(protection_callback), loss_prot_logic_(new media_optimization::VCMLossProtectionLogic( - clock_->TimeInMilliseconds())), + env_.clock().TimeInMilliseconds())), max_payload_size_(1460), overhead_threshold_(GetProtectionOverheadRateThreshold()) {} -FecControllerDefault::FecControllerDefault(Clock* clock) - : clock_(clock), - loss_prot_logic_(new media_optimization::VCMLossProtectionLogic( - clock_->TimeInMilliseconds())), - max_payload_size_(1460), - overhead_threshold_(GetProtectionOverheadRateThreshold()) {} +FecControllerDefault::FecControllerDefault(const Environment& env) + : FecControllerDefault(env, nullptr) {} FecControllerDefault::~FecControllerDefault(void) { loss_prot_logic_->Release(); @@ -61,8 +59,8 @@ void FecControllerDefault::SetEncodingData(size_t width, float FecControllerDefault::GetProtectionOverheadRateThreshold() { float overhead_threshold = - strtof(webrtc::field_trial::FindFullName( - "WebRTC-ProtectionOverheadRateThreshold") + strtof(env_.field_trials() + .Lookup("WebRTC-ProtectionOverheadRateThreshold") .c_str(), nullptr); if (overhead_threshold > 0 && overhead_threshold <= 1) { @@ -107,7 +105,7 @@ uint32_t FecControllerDefault::UpdateFecRates( media_optimization::FilterPacketLossMode filter_mode = media_optimization::kMaxFilter; uint8_t packet_loss_enc = loss_prot_logic_->FilteredLoss( - clock_->TimeInMilliseconds(), filter_mode, fraction_lost); + env_.clock().TimeInMilliseconds(), filter_mode, fraction_lost); // For now use the filtered loss for computing the robustness settings. loss_prot_logic_->UpdateFilteredLossPr(packet_loss_enc); if (loss_prot_logic_->SelectedType() == media_optimization::kNone) { @@ -191,11 +189,11 @@ void FecControllerDefault::UpdateWithEncodedData( const float min_packets_per_frame = encoded_length / static_cast(max_payload_size_); if (delta_frame) { - loss_prot_logic_->UpdatePacketsPerFrame(min_packets_per_frame, - clock_->TimeInMilliseconds()); + loss_prot_logic_->UpdatePacketsPerFrame( + min_packets_per_frame, env_.clock().TimeInMilliseconds()); } else { loss_prot_logic_->UpdatePacketsPerFrameKey( - min_packets_per_frame, clock_->TimeInMilliseconds()); + min_packets_per_frame, env_.clock().TimeInMilliseconds()); } } if (!delta_frame && encoded_length > 0) { diff --git a/third_party/libwebrtc/modules/video_coding/fec_controller_default.h b/third_party/libwebrtc/modules/video_coding/fec_controller_default.h index a97dea011b..f60302b2d8 100644 --- a/third_party/libwebrtc/modules/video_coding/fec_controller_default.h +++ b/third_party/libwebrtc/modules/video_coding/fec_controller_default.h @@ -17,24 +17,25 @@ #include #include +#include "api/environment/environment.h" #include "api/fec_controller.h" #include "modules/video_coding/media_opt_util.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" -#include "system_wrappers/include/clock.h" namespace webrtc { class FecControllerDefault : public FecController { public: - FecControllerDefault(Clock* clock, + FecControllerDefault(const Environment& env, VCMProtectionCallback* protection_callback); - explicit FecControllerDefault(Clock* clock); - ~FecControllerDefault() override; + explicit FecControllerDefault(const Environment& env); FecControllerDefault(const FecControllerDefault&) = delete; FecControllerDefault& operator=(const FecControllerDefault&) = delete; + ~FecControllerDefault() override; + void SetProtectionCallback( VCMProtectionCallback* protection_callback) override; void SetProtectionMethod(bool enable_fec, bool enable_nack) override; @@ -54,7 +55,7 @@ class FecControllerDefault : public FecController { private: enum { kBitrateAverageWinMs = 1000 }; - Clock* const clock_; + const Environment env_; VCMProtectionCallback* protection_callback_; Mutex mutex_; std::unique_ptr loss_prot_logic_ diff --git a/third_party/libwebrtc/modules/video_coding/fec_controller_unittest.cc b/third_party/libwebrtc/modules/video_coding/fec_controller_unittest.cc index fa3cc7a93b..c4a0a08fd1 100644 --- a/third_party/libwebrtc/modules/video_coding/fec_controller_unittest.cc +++ b/third_party/libwebrtc/modules/video_coding/fec_controller_unittest.cc @@ -14,6 +14,7 @@ #include +#include "api/environment/environment_factory.h" #include "modules/include/module_fec_types.h" #include "modules/video_coding/fec_controller_default.h" #include "system_wrappers/include/clock.h" @@ -50,7 +51,8 @@ class ProtectionBitrateCalculatorTest : public ::testing::Test { // Note: simulated clock starts at 1 seconds, since parts of webrtc use 0 as // a special case (e.g. frame rate in media optimization). ProtectionBitrateCalculatorTest() - : clock_(1000), fec_controller_(&clock_, &protection_callback_) {} + : clock_(1000), + fec_controller_(CreateEnvironment(&clock_), &protection_callback_) {} SimulatedClock clock_; ProtectionCallback protection_callback_; diff --git a/third_party/libwebrtc/modules/video_coding/nack_requester.cc b/third_party/libwebrtc/modules/video_coding/nack_requester.cc index 008420f4da..b3e928d05e 100644 --- a/third_party/libwebrtc/modules/video_coding/nack_requester.cc +++ b/third_party/libwebrtc/modules/video_coding/nack_requester.cc @@ -141,13 +141,12 @@ void NackRequester::ProcessNacks() { } } -int NackRequester::OnReceivedPacket(uint16_t seq_num, bool is_keyframe) { +int NackRequester::OnReceivedPacket(uint16_t seq_num) { RTC_DCHECK_RUN_ON(worker_thread_); - return OnReceivedPacket(seq_num, is_keyframe, false); + return OnReceivedPacket(seq_num, false); } int NackRequester::OnReceivedPacket(uint16_t seq_num, - bool is_keyframe, bool is_recovered) { RTC_DCHECK_RUN_ON(worker_thread_); // TODO(philipel): When the packet includes information whether it is @@ -158,8 +157,6 @@ int NackRequester::OnReceivedPacket(uint16_t seq_num, if (!initialized_) { newest_seq_num_ = seq_num; - if (is_keyframe) - keyframe_list_.insert(seq_num); initialized_ = true; return 0; } @@ -182,15 +179,6 @@ int NackRequester::OnReceivedPacket(uint16_t seq_num, return nacks_sent_for_packet; } - // Keep track of new keyframes. - if (is_keyframe) - keyframe_list_.insert(seq_num); - - // And remove old ones so we don't accumulate keyframes. - auto it = keyframe_list_.lower_bound(seq_num - kMaxPacketAge); - if (it != keyframe_list_.begin()) - keyframe_list_.erase(keyframe_list_.begin(), it); - if (is_recovered) { recovered_list_.insert(seq_num); @@ -225,8 +213,6 @@ void NackRequester::ClearUpTo(uint16_t seq_num) { // thread. RTC_DCHECK_RUN_ON(worker_thread_); nack_list_.erase(nack_list_.begin(), nack_list_.lower_bound(seq_num)); - keyframe_list_.erase(keyframe_list_.begin(), - keyframe_list_.lower_bound(seq_num)); recovered_list_.erase(recovered_list_.begin(), recovered_list_.lower_bound(seq_num)); } @@ -236,25 +222,6 @@ void NackRequester::UpdateRtt(int64_t rtt_ms) { rtt_ = TimeDelta::Millis(rtt_ms); } -bool NackRequester::RemovePacketsUntilKeyFrame() { - // Called on worker_thread_. - while (!keyframe_list_.empty()) { - auto it = nack_list_.lower_bound(*keyframe_list_.begin()); - - if (it != nack_list_.begin()) { - // We have found a keyframe that actually is newer than at least one - // packet in the nack list. - nack_list_.erase(nack_list_.begin(), it); - return true; - } - - // If this keyframe is so old it does not remove any packets from the list, - // remove it from the list of keyframes and try the next keyframe. - keyframe_list_.erase(keyframe_list_.begin()); - } - return false; -} - void NackRequester::AddPacketsToNack(uint16_t seq_num_start, uint16_t seq_num_end) { // Called on worker_thread_. @@ -262,22 +229,13 @@ void NackRequester::AddPacketsToNack(uint16_t seq_num_start, auto it = nack_list_.lower_bound(seq_num_end - kMaxPacketAge); nack_list_.erase(nack_list_.begin(), it); - // If the nack list is too large, remove packets from the nack list until - // the latest first packet of a keyframe. If the list is still too large, - // clear it and request a keyframe. uint16_t num_new_nacks = ForwardDiff(seq_num_start, seq_num_end); if (nack_list_.size() + num_new_nacks > kMaxNackPackets) { - while (RemovePacketsUntilKeyFrame() && - nack_list_.size() + num_new_nacks > kMaxNackPackets) { - } - - if (nack_list_.size() + num_new_nacks > kMaxNackPackets) { - nack_list_.clear(); - RTC_LOG(LS_WARNING) << "NACK list full, clearing NACK" - " list and requesting keyframe."; - keyframe_request_sender_->RequestKeyFrame(); - return; - } + nack_list_.clear(); + RTC_LOG(LS_WARNING) << "NACK list full, clearing NACK" + " list and requesting keyframe."; + keyframe_request_sender_->RequestKeyFrame(); + return; } for (uint16_t seq_num = seq_num_start; seq_num != seq_num_end; ++seq_num) { diff --git a/third_party/libwebrtc/modules/video_coding/nack_requester.h b/third_party/libwebrtc/modules/video_coding/nack_requester.h index c860787dcf..b5ef30f01b 100644 --- a/third_party/libwebrtc/modules/video_coding/nack_requester.h +++ b/third_party/libwebrtc/modules/video_coding/nack_requester.h @@ -78,8 +78,8 @@ class NackRequester final : public NackRequesterBase { void ProcessNacks() override; - int OnReceivedPacket(uint16_t seq_num, bool is_keyframe); - int OnReceivedPacket(uint16_t seq_num, bool is_keyframe, bool is_recovered); + int OnReceivedPacket(uint16_t seq_num); + int OnReceivedPacket(uint16_t seq_num, bool is_recovered); void ClearUpTo(uint16_t seq_num); void UpdateRtt(int64_t rtt_ms); @@ -108,10 +108,6 @@ class NackRequester final : public NackRequesterBase { void AddPacketsToNack(uint16_t seq_num_start, uint16_t seq_num_end) RTC_EXCLUSIVE_LOCKS_REQUIRED(worker_thread_); - // Removes packets from the nack list until the next keyframe. Returns true - // if packets were removed. - bool RemovePacketsUntilKeyFrame() - RTC_EXCLUSIVE_LOCKS_REQUIRED(worker_thread_); std::vector GetNackBatch(NackFilterOptions options) RTC_EXCLUSIVE_LOCKS_REQUIRED(worker_thread_); @@ -134,8 +130,6 @@ class NackRequester final : public NackRequesterBase { // synchronized access. std::map> nack_list_ RTC_GUARDED_BY(worker_thread_); - std::set> keyframe_list_ - RTC_GUARDED_BY(worker_thread_); std::set> recovered_list_ RTC_GUARDED_BY(worker_thread_); video_coding::Histogram reordering_histogram_ RTC_GUARDED_BY(worker_thread_); diff --git a/third_party/libwebrtc/modules/video_coding/nack_requester_unittest.cc b/third_party/libwebrtc/modules/video_coding/nack_requester_unittest.cc index 6f11cb6e91..2f24df2aef 100644 --- a/third_party/libwebrtc/modules/video_coding/nack_requester_unittest.cc +++ b/third_party/libwebrtc/modules/video_coding/nack_requester_unittest.cc @@ -102,90 +102,25 @@ class TestNackRequester : public ::testing::Test, TEST_F(TestNackRequester, NackOnePacket) { NackRequester& nack_module = CreateNackModule(); - nack_module.OnReceivedPacket(1, false, false); - nack_module.OnReceivedPacket(3, false, false); + nack_module.OnReceivedPacket(1); + nack_module.OnReceivedPacket(3); ASSERT_EQ(1u, sent_nacks_.size()); EXPECT_EQ(2, sent_nacks_[0]); } TEST_F(TestNackRequester, WrappingSeqNum) { NackRequester& nack_module = CreateNackModule(); - nack_module.OnReceivedPacket(0xfffe, false, false); - nack_module.OnReceivedPacket(1, false, false); + nack_module.OnReceivedPacket(0xfffe); + nack_module.OnReceivedPacket(1); ASSERT_EQ(2u, sent_nacks_.size()); EXPECT_EQ(0xffff, sent_nacks_[0]); EXPECT_EQ(0, sent_nacks_[1]); } -TEST_F(TestNackRequester, WrappingSeqNumClearToKeyframe) { - NackRequester& nack_module = CreateNackModule(TimeDelta::Millis(10)); - nack_module.OnReceivedPacket(0xfffe, false, false); - nack_module.OnReceivedPacket(1, false, false); - ASSERT_EQ(2u, sent_nacks_.size()); - EXPECT_EQ(0xffff, sent_nacks_[0]); - EXPECT_EQ(0, sent_nacks_[1]); - - sent_nacks_.clear(); - nack_module.OnReceivedPacket(2, true, false); - ASSERT_EQ(0u, sent_nacks_.size()); - - nack_module.OnReceivedPacket(501, true, false); - ASSERT_EQ(498u, sent_nacks_.size()); - for (int seq_num = 3; seq_num < 501; ++seq_num) - EXPECT_EQ(seq_num, sent_nacks_[seq_num - 3]); - - sent_nacks_.clear(); - nack_module.OnReceivedPacket(1001, false, false); - EXPECT_EQ(499u, sent_nacks_.size()); - for (int seq_num = 502; seq_num < 1001; ++seq_num) - EXPECT_EQ(seq_num, sent_nacks_[seq_num - 502]); - - sent_nacks_.clear(); - clock_->AdvanceTimeMilliseconds(100); - ASSERT_TRUE(WaitForSendNack()); - ASSERT_EQ(999u, sent_nacks_.size()); - EXPECT_EQ(0xffff, sent_nacks_[0]); - EXPECT_EQ(0, sent_nacks_[1]); - for (int seq_num = 3; seq_num < 501; ++seq_num) - EXPECT_EQ(seq_num, sent_nacks_[seq_num - 1]); - for (int seq_num = 502; seq_num < 1001; ++seq_num) - EXPECT_EQ(seq_num, sent_nacks_[seq_num - 2]); - - // Adding packet 1004 will cause the nack list to reach it's max limit. - // It will then clear all nacks up to the next keyframe (seq num 2), - // thus removing 0xffff and 0 from the nack list. - sent_nacks_.clear(); - nack_module.OnReceivedPacket(1004, false, false); - ASSERT_EQ(2u, sent_nacks_.size()); - EXPECT_EQ(1002, sent_nacks_[0]); - EXPECT_EQ(1003, sent_nacks_[1]); - - sent_nacks_.clear(); - clock_->AdvanceTimeMilliseconds(100); - ASSERT_TRUE(WaitForSendNack()); - ASSERT_EQ(999u, sent_nacks_.size()); - for (int seq_num = 3; seq_num < 501; ++seq_num) - EXPECT_EQ(seq_num, sent_nacks_[seq_num - 3]); - for (int seq_num = 502; seq_num < 1001; ++seq_num) - EXPECT_EQ(seq_num, sent_nacks_[seq_num - 4]); - - // Adding packet 1007 will cause the nack module to overflow again, thus - // clearing everything up to 501 which is the next keyframe. - nack_module.OnReceivedPacket(1007, false, false); - sent_nacks_.clear(); - clock_->AdvanceTimeMilliseconds(100); - ASSERT_TRUE(WaitForSendNack()); - ASSERT_EQ(503u, sent_nacks_.size()); - for (int seq_num = 502; seq_num < 1001; ++seq_num) - EXPECT_EQ(seq_num, sent_nacks_[seq_num - 502]); - EXPECT_EQ(1005, sent_nacks_[501]); - EXPECT_EQ(1006, sent_nacks_[502]); -} - TEST_F(TestNackRequester, ResendNack) { NackRequester& nack_module = CreateNackModule(TimeDelta::Millis(1)); - nack_module.OnReceivedPacket(1, false, false); - nack_module.OnReceivedPacket(3, false, false); + nack_module.OnReceivedPacket(1); + nack_module.OnReceivedPacket(3); size_t expected_nacks_sent = 1; ASSERT_EQ(expected_nacks_sent, sent_nacks_.size()); EXPECT_EQ(2, sent_nacks_[0]); @@ -225,8 +160,8 @@ TEST_F(TestNackRequester, ResendNack) { TEST_F(TestNackRequester, ResendPacketMaxRetries) { NackRequester& nack_module = CreateNackModule(TimeDelta::Millis(1)); - nack_module.OnReceivedPacket(1, false, false); - nack_module.OnReceivedPacket(3, false, false); + nack_module.OnReceivedPacket(1); + nack_module.OnReceivedPacket(3); ASSERT_EQ(1u, sent_nacks_.size()); EXPECT_EQ(2, sent_nacks_[0]); @@ -246,37 +181,22 @@ TEST_F(TestNackRequester, ResendPacketMaxRetries) { TEST_F(TestNackRequester, TooLargeNackList) { NackRequester& nack_module = CreateNackModule(); - nack_module.OnReceivedPacket(0, false, false); - nack_module.OnReceivedPacket(1001, false, false); + nack_module.OnReceivedPacket(0); + nack_module.OnReceivedPacket(1001); EXPECT_EQ(1000u, sent_nacks_.size()); EXPECT_EQ(0, keyframes_requested_); - nack_module.OnReceivedPacket(1003, false, false); + nack_module.OnReceivedPacket(1003); EXPECT_EQ(1000u, sent_nacks_.size()); EXPECT_EQ(1, keyframes_requested_); - nack_module.OnReceivedPacket(1004, false, false); - EXPECT_EQ(1000u, sent_nacks_.size()); - EXPECT_EQ(1, keyframes_requested_); -} - -TEST_F(TestNackRequester, TooLargeNackListWithKeyFrame) { - NackRequester& nack_module = CreateNackModule(); - nack_module.OnReceivedPacket(0, false, false); - nack_module.OnReceivedPacket(1, true, false); - nack_module.OnReceivedPacket(1001, false, false); - EXPECT_EQ(999u, sent_nacks_.size()); - EXPECT_EQ(0, keyframes_requested_); - nack_module.OnReceivedPacket(1003, false, false); - EXPECT_EQ(1000u, sent_nacks_.size()); - EXPECT_EQ(0, keyframes_requested_); - nack_module.OnReceivedPacket(1005, false, false); + nack_module.OnReceivedPacket(1004); EXPECT_EQ(1000u, sent_nacks_.size()); EXPECT_EQ(1, keyframes_requested_); } TEST_F(TestNackRequester, ClearUpTo) { NackRequester& nack_module = CreateNackModule(TimeDelta::Millis(1)); - nack_module.OnReceivedPacket(0, false, false); - nack_module.OnReceivedPacket(100, false, false); + nack_module.OnReceivedPacket(0); + nack_module.OnReceivedPacket(100); EXPECT_EQ(99u, sent_nacks_.size()); sent_nacks_.clear(); @@ -289,8 +209,8 @@ TEST_F(TestNackRequester, ClearUpTo) { TEST_F(TestNackRequester, ClearUpToWrap) { NackRequester& nack_module = CreateNackModule(); - nack_module.OnReceivedPacket(0xfff0, false, false); - nack_module.OnReceivedPacket(0xf, false, false); + nack_module.OnReceivedPacket(0xfff0); + nack_module.OnReceivedPacket(0xf); EXPECT_EQ(30u, sent_nacks_.size()); sent_nacks_.clear(); @@ -303,13 +223,13 @@ TEST_F(TestNackRequester, ClearUpToWrap) { TEST_F(TestNackRequester, PacketNackCount) { NackRequester& nack_module = CreateNackModule(TimeDelta::Millis(1)); - EXPECT_EQ(0, nack_module.OnReceivedPacket(0, false, false)); - EXPECT_EQ(0, nack_module.OnReceivedPacket(2, false, false)); - EXPECT_EQ(1, nack_module.OnReceivedPacket(1, false, false)); + EXPECT_EQ(0, nack_module.OnReceivedPacket(0)); + EXPECT_EQ(0, nack_module.OnReceivedPacket(2)); + EXPECT_EQ(1, nack_module.OnReceivedPacket(1)); sent_nacks_.clear(); nack_module.UpdateRtt(100); - EXPECT_EQ(0, nack_module.OnReceivedPacket(5, false, false)); + EXPECT_EQ(0, nack_module.OnReceivedPacket(5)); clock_->AdvanceTimeMilliseconds(100); WaitForSendNack(); EXPECT_EQ(4u, sent_nacks_.size()); @@ -319,40 +239,24 @@ TEST_F(TestNackRequester, PacketNackCount) { EXPECT_EQ(6u, sent_nacks_.size()); - EXPECT_EQ(3, nack_module.OnReceivedPacket(3, false, false)); - EXPECT_EQ(3, nack_module.OnReceivedPacket(4, false, false)); - EXPECT_EQ(0, nack_module.OnReceivedPacket(4, false, false)); -} - -TEST_F(TestNackRequester, NackListFullAndNoOverlapWithKeyframes) { - NackRequester& nack_module = CreateNackModule(); - const int kMaxNackPackets = 1000; - const unsigned int kFirstGap = kMaxNackPackets - 20; - const unsigned int kSecondGap = 200; - uint16_t seq_num = 0; - nack_module.OnReceivedPacket(seq_num++, true, false); - seq_num += kFirstGap; - nack_module.OnReceivedPacket(seq_num++, true, false); - EXPECT_EQ(kFirstGap, sent_nacks_.size()); - sent_nacks_.clear(); - seq_num += kSecondGap; - nack_module.OnReceivedPacket(seq_num, true, false); - EXPECT_EQ(kSecondGap, sent_nacks_.size()); + EXPECT_EQ(3, nack_module.OnReceivedPacket(3)); + EXPECT_EQ(3, nack_module.OnReceivedPacket(4)); + EXPECT_EQ(0, nack_module.OnReceivedPacket(4)); } TEST_F(TestNackRequester, HandleFecRecoveredPacket) { NackRequester& nack_module = CreateNackModule(); - nack_module.OnReceivedPacket(1, false, false); - nack_module.OnReceivedPacket(4, false, true); + nack_module.OnReceivedPacket(1); + nack_module.OnReceivedPacket(4, /*is_recovered=*/true); EXPECT_EQ(0u, sent_nacks_.size()); - nack_module.OnReceivedPacket(5, false, false); + nack_module.OnReceivedPacket(5); EXPECT_EQ(2u, sent_nacks_.size()); } TEST_F(TestNackRequester, SendNackWithoutDelay) { NackRequester& nack_module = CreateNackModule(); - nack_module.OnReceivedPacket(0, false, false); - nack_module.OnReceivedPacket(100, false, false); + nack_module.OnReceivedPacket(0); + nack_module.OnReceivedPacket(100); EXPECT_EQ(99u, sent_nacks_.size()); } @@ -389,14 +293,14 @@ class TestNackRequesterWithFieldTrial : public ::testing::Test, }; TEST_F(TestNackRequesterWithFieldTrial, SendNackWithDelay) { - nack_module_.OnReceivedPacket(0, false, false); - nack_module_.OnReceivedPacket(100, false, false); + nack_module_.OnReceivedPacket(0); + nack_module_.OnReceivedPacket(100); EXPECT_EQ(0u, sent_nacks_.size()); clock_->AdvanceTimeMilliseconds(10); - nack_module_.OnReceivedPacket(106, false, false); + nack_module_.OnReceivedPacket(106); EXPECT_EQ(99u, sent_nacks_.size()); clock_->AdvanceTimeMilliseconds(10); - nack_module_.OnReceivedPacket(109, false, false); + nack_module_.OnReceivedPacket(109); EXPECT_EQ(104u, sent_nacks_.size()); } } // namespace webrtc diff --git a/third_party/libwebrtc/modules/video_coding/utility/qp_parser.cc b/third_party/libwebrtc/modules/video_coding/utility/qp_parser.cc index 3b9aaa377e..a531b54a7e 100644 --- a/third_party/libwebrtc/modules/video_coding/utility/qp_parser.cc +++ b/third_party/libwebrtc/modules/video_coding/utility/qp_parser.cc @@ -37,7 +37,10 @@ absl::optional QpParser::Parse(VideoCodecType codec_type, } else if (codec_type == kVideoCodecH264) { return h264_parsers_[spatial_idx].Parse(frame_data, frame_size); } else if (codec_type == kVideoCodecH265) { - // TODO(bugs.webrtc.org/13485) + // H.265 bitstream parser is conditionally built. +#ifdef RTC_ENABLE_H265 + return h265_parsers_[spatial_idx].Parse(frame_data, frame_size); +#endif } return absl::nullopt; @@ -52,4 +55,15 @@ absl::optional QpParser::H264QpParser::Parse( return bitstream_parser_.GetLastSliceQp(); } +#ifdef RTC_ENABLE_H265 +absl::optional QpParser::H265QpParser::Parse( + const uint8_t* frame_data, + size_t frame_size) { + MutexLock lock(&mutex_); + bitstream_parser_.ParseBitstream( + rtc::ArrayView(frame_data, frame_size)); + return bitstream_parser_.GetLastSliceQp(); +} +#endif + } // namespace webrtc diff --git a/third_party/libwebrtc/modules/video_coding/utility/qp_parser.h b/third_party/libwebrtc/modules/video_coding/utility/qp_parser.h index f132ff9337..210fe02bc3 100644 --- a/third_party/libwebrtc/modules/video_coding/utility/qp_parser.h +++ b/third_party/libwebrtc/modules/video_coding/utility/qp_parser.h @@ -15,6 +15,9 @@ #include "api/video/video_codec_constants.h" #include "api/video/video_codec_type.h" #include "common_video/h264/h264_bitstream_parser.h" +#ifdef RTC_ENABLE_H265 +#include "common_video/h265/h265_bitstream_parser.h" +#endif #include "rtc_base/synchronization/mutex.h" namespace webrtc { @@ -38,6 +41,21 @@ class QpParser { }; H264QpParser h264_parsers_[kMaxSimulcastStreams]; + +#ifdef RTC_ENABLE_H265 + // A thread safe wrapper for H.265 bitstream parser. + class H265QpParser { + public: + absl::optional Parse(const uint8_t* frame_data, + size_t frame_size); + + private: + Mutex mutex_; + H265BitstreamParser bitstream_parser_ RTC_GUARDED_BY(mutex_); + }; + + H265QpParser h265_parsers_[kMaxSimulcastStreams]; +#endif }; } // namespace webrtc diff --git a/third_party/libwebrtc/moz-patch-stack/0001.patch b/third_party/libwebrtc/moz-patch-stack/0001.patch index 6547c47b40..e238c8c130 100644 --- a/third_party/libwebrtc/moz-patch-stack/0001.patch +++ b/third_party/libwebrtc/moz-patch-stack/0001.patch @@ -399,10 +399,10 @@ index 5d4d4190d5..9868365f24 100644 struct RTC_EXPORT RTPHeader { RTPHeader(); diff --git a/api/rtp_parameters.cc b/api/rtp_parameters.cc -index 54132bcdbb..cf8b3ad3dc 100644 +index 3ff4b58a2e..ad0f3c9396 100644 --- a/api/rtp_parameters.cc +++ b/api/rtp_parameters.cc -@@ -151,7 +151,8 @@ bool RtpExtension::IsSupportedForAudio(absl::string_view uri) { +@@ -160,7 +160,8 @@ bool RtpExtension::IsSupportedForAudio(absl::string_view uri) { uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri || uri == webrtc::RtpExtension::kMidUri || uri == webrtc::RtpExtension::kRidUri || @@ -413,7 +413,7 @@ index 54132bcdbb..cf8b3ad3dc 100644 bool RtpExtension::IsSupportedForVideo(absl::string_view uri) { diff --git a/call/BUILD.gn b/call/BUILD.gn -index 9a7be88892..66c8b2011a 100644 +index 32ebc2e9cf..41ed587950 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn @@ -20,6 +20,7 @@ rtc_library("call_interfaces") { @@ -878,7 +878,7 @@ index 2a95a3a816..b152cdbd9e 100644 } } diff --git a/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_unittest.cc -index a1d1c9d4df..b3a9452df9 100644 +index ac464493b8..44f1a9e742 100644 --- a/modules/rtp_rtcp/source/rtp_packet_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_packet_unittest.cc @@ -123,6 +123,18 @@ constexpr uint8_t kPacketWithMid[] = { @@ -1560,7 +1560,7 @@ index 0474e7bc17..1953923f81 100644 std::unique_ptr svc_controller_; absl::optional scalability_mode_; diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn -index 3011d6a797..9f5f0aad56 100644 +index ac30d8708b..84dc1718b4 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -463,6 +463,12 @@ rtc_library("logging") { diff --git a/third_party/libwebrtc/moz-patch-stack/0006.patch b/third_party/libwebrtc/moz-patch-stack/0006.patch index 7decaa705c..1b0eca5f02 100644 --- a/third_party/libwebrtc/moz-patch-stack/0006.patch +++ b/third_party/libwebrtc/moz-patch-stack/0006.patch @@ -30,7 +30,7 @@ index 542067d30c..500ca1447f 100644 // single 'timing frame'. absl::optional timing_frame_info; diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc -index ba5b951f4d..61b88c89b8 100644 +index ee31db2d36..982cda19da 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -361,6 +361,13 @@ RTCPReceiver::ConsumeReceivedXrReferenceTimeInfo() { diff --git a/third_party/libwebrtc/moz-patch-stack/0007.patch b/third_party/libwebrtc/moz-patch-stack/0007.patch index 052a4431bf..81646cfcfa 100644 --- a/third_party/libwebrtc/moz-patch-stack/0007.patch +++ b/third_party/libwebrtc/moz-patch-stack/0007.patch @@ -33,7 +33,7 @@ index 500ca1447f..95f1a47f4e 100644 // Timing frame info: all important timestamps for a full lifetime of a // single 'timing frame'. diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc -index 61b88c89b8..a98b200c05 100644 +index 982cda19da..a596ef5fd4 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -362,10 +362,12 @@ RTCPReceiver::ConsumeReceivedXrReferenceTimeInfo() { diff --git a/third_party/libwebrtc/moz-patch-stack/0008.patch b/third_party/libwebrtc/moz-patch-stack/0008.patch index 4b7bb94bd6..b300b7ac54 100644 --- a/third_party/libwebrtc/moz-patch-stack/0008.patch +++ b/third_party/libwebrtc/moz-patch-stack/0008.patch @@ -32,7 +32,7 @@ diff --git a/modules/desktop_capture/mac/screen_capturer_mac.mm b/modules/deskto index 60089fd0f2..a2370ed695 100644 --- a/modules/desktop_capture/mac/screen_capturer_mac.mm +++ b/modules/desktop_capture/mac/screen_capturer_mac.mm -@@ -182,6 +182,7 @@ DesktopRect GetExcludedWindowPixelBounds(CGWindowID window, float dip_to_pixel_s +@@ -182,6 +182,7 @@ void ScreenCapturerMac::Start(Callback* callback) { "webrtc", "ScreenCapturermac::Start", "target display id ", current_display_); callback_ = callback; @@ -40,7 +40,7 @@ index 60089fd0f2..a2370ed695 100644 // Start and operate CGDisplayStream handler all from capture thread. if (!RegisterRefreshAndMoveHandlers()) { RTC_LOG(LS_ERROR) << "Failed to register refresh and move handlers."; -@@ -202,7 +203,8 @@ DesktopRect GetExcludedWindowPixelBounds(CGWindowID window, float dip_to_pixel_s +@@ -202,7 +203,8 @@ void ScreenCapturerMac::CaptureFrame() { } MacDesktopConfiguration new_config = desktop_config_monitor_->desktop_configuration(); @@ -54,7 +54,7 @@ diff --git a/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/modules/deskt index 3db4332cd1..512103ab5e 100644 --- a/modules/desktop_capture/mouse_cursor_monitor_mac.mm +++ b/modules/desktop_capture/mouse_cursor_monitor_mac.mm -@@ -133,7 +133,7 @@ void DisplaysReconfigured(CGDirectDisplayID display, +@@ -133,7 +133,7 @@ void MouseCursorMonitorMac::CaptureImage(float scale) { NSSize nssize = [nsimage size]; // DIP size // No need to caputre cursor image if it's unchanged since last capture. diff --git a/third_party/libwebrtc/moz-patch-stack/0009.patch b/third_party/libwebrtc/moz-patch-stack/0009.patch index 58b2ab9994..f724dadc84 100644 --- a/third_party/libwebrtc/moz-patch-stack/0009.patch +++ b/third_party/libwebrtc/moz-patch-stack/0009.patch @@ -19,7 +19,7 @@ diff --git a/modules/desktop_capture/mac/screen_capturer_mac.mm b/modules/deskto index a2370ed695..785a15dfa4 100644 --- a/modules/desktop_capture/mac/screen_capturer_mac.mm +++ b/modules/desktop_capture/mac/screen_capturer_mac.mm -@@ -276,7 +276,8 @@ DesktopRect GetExcludedWindowPixelBounds(CGWindowID window, float dip_to_pixel_s +@@ -276,7 +276,8 @@ bool ScreenCapturerMac::GetSourceList(SourceList* screens) { for (MacDisplayConfigurations::iterator it = desktop_config_.displays.begin(); it != desktop_config_.displays.end(); ++it) { diff --git a/third_party/libwebrtc/moz-patch-stack/0030.patch b/third_party/libwebrtc/moz-patch-stack/0030.patch index 8c6652af46..9e8bd7b2fd 100644 --- a/third_party/libwebrtc/moz-patch-stack/0030.patch +++ b/third_party/libwebrtc/moz-patch-stack/0030.patch @@ -63,6 +63,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/136b3fc0377be6dca Bug 1876843 - (fix-b29ff000da) remove mozilla dependency on api:enable_media Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/7f403ee038e9797a1aff6161fc70a2d92769851f + +Bug 1883116 - (fix-3d9c3687a4) Supporting change of call_factory.cc to create_call.cc. + +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/b86cb7278bc4e557104cec0313d83511b9c8f40d --- .gn | 2 + BUILD.gn | 46 ++++++++++++++++++- @@ -202,10 +206,10 @@ index 571049f3e4..f393179bbb 100644 } else { deps += [ diff --git a/api/BUILD.gn b/api/BUILD.gn -index ee162577c8..10a4c8c95f 100644 +index 6af4fa5517..1628660c3c 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn -@@ -49,6 +49,9 @@ rtc_source_set("enable_media") { +@@ -40,6 +40,9 @@ rtc_source_set("enable_media") { "../rtc_base/system:rtc_export", "environment", ] @@ -215,7 +219,7 @@ index ee162577c8..10a4c8c95f 100644 } rtc_source_set("enable_media_with_defaults") { -@@ -75,7 +78,7 @@ rtc_source_set("enable_media_with_defaults") { +@@ -66,7 +69,7 @@ rtc_source_set("enable_media_with_defaults") { ] } @@ -224,7 +228,7 @@ index ee162577c8..10a4c8c95f 100644 rtc_library("create_peerconnection_factory") { visibility = [ "*" ] allow_poison = [ "environment_construction" ] -@@ -228,6 +231,10 @@ rtc_source_set("ice_transport_interface") { +@@ -219,6 +222,10 @@ rtc_source_set("ice_transport_interface") { } rtc_library("dtls_transport_interface") { @@ -235,7 +239,7 @@ index ee162577c8..10a4c8c95f 100644 visibility = [ "*" ] sources = [ -@@ -244,6 +251,7 @@ rtc_library("dtls_transport_interface") { +@@ -235,6 +242,7 @@ rtc_library("dtls_transport_interface") { ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -243,7 +247,7 @@ index ee162577c8..10a4c8c95f 100644 rtc_library("dtmf_sender_interface") { visibility = [ "*" ] -@@ -256,6 +264,10 @@ rtc_library("dtmf_sender_interface") { +@@ -247,6 +255,10 @@ rtc_library("dtmf_sender_interface") { } rtc_library("rtp_sender_interface") { @@ -254,7 +258,7 @@ index ee162577c8..10a4c8c95f 100644 visibility = [ "*" ] sources = [ -@@ -270,16 +282,31 @@ rtc_library("rtp_sender_interface") { +@@ -261,16 +273,31 @@ rtc_library("rtp_sender_interface") { ":ref_count", ":rtc_error", ":rtp_parameters", @@ -286,7 +290,7 @@ index ee162577c8..10a4c8c95f 100644 visibility = [ "*" ] cflags = [] sources = [ -@@ -396,6 +423,7 @@ rtc_library("libjingle_peerconnection_api") { +@@ -387,6 +414,7 @@ rtc_library("libjingle_peerconnection_api") { "//third_party/abseil-cpp/absl/types:optional", ] } @@ -294,7 +298,7 @@ index ee162577c8..10a4c8c95f 100644 rtc_source_set("frame_transformer_interface") { visibility = [ "*" ] -@@ -568,6 +596,7 @@ rtc_source_set("peer_network_dependencies") { +@@ -560,6 +588,7 @@ rtc_source_set("peer_network_dependencies") { } rtc_source_set("peer_connection_quality_test_fixture_api") { @@ -302,7 +306,7 @@ index ee162577c8..10a4c8c95f 100644 visibility = [ "*" ] testonly = true sources = [ "test/peerconnection_quality_test_fixture.h" ] -@@ -618,6 +647,7 @@ rtc_source_set("peer_connection_quality_test_fixture_api") { +@@ -609,6 +638,7 @@ rtc_source_set("peer_connection_quality_test_fixture_api") { "//third_party/abseil-cpp/absl/types:optional", ] } @@ -310,7 +314,7 @@ index ee162577c8..10a4c8c95f 100644 rtc_source_set("frame_generator_api") { visibility = [ "*" ] -@@ -736,6 +766,7 @@ rtc_library("create_frame_generator") { +@@ -728,6 +758,7 @@ rtc_library("create_frame_generator") { absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -318,7 +322,7 @@ index ee162577c8..10a4c8c95f 100644 rtc_library("create_peer_connection_quality_test_frame_generator") { visibility = [ "*" ] testonly = true -@@ -752,6 +783,7 @@ rtc_library("create_peer_connection_quality_test_frame_generator") { +@@ -744,6 +775,7 @@ rtc_library("create_peer_connection_quality_test_frame_generator") { ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -326,7 +330,7 @@ index ee162577c8..10a4c8c95f 100644 rtc_source_set("libjingle_logging_api") { visibility = [ "*" ] -@@ -926,6 +958,7 @@ rtc_source_set("refcountedbase") { +@@ -924,6 +956,7 @@ rtc_source_set("refcountedbase") { ] } @@ -334,7 +338,7 @@ index ee162577c8..10a4c8c95f 100644 rtc_library("ice_transport_factory") { visibility = [ "*" ] sources = [ -@@ -944,6 +977,7 @@ rtc_library("ice_transport_factory") { +@@ -942,6 +975,7 @@ rtc_library("ice_transport_factory") { "rtc_event_log:rtc_event_log", ] } @@ -426,7 +430,7 @@ index 0000000000..45194f5ace + +#endif // API_RTP_SENDER_SETPARAMETERS_CALLBACK_H_ diff --git a/api/task_queue/BUILD.gn b/api/task_queue/BUILD.gn -index 246164c68b..d557d8f100 100644 +index 1b9425d719..afdf47dfc9 100644 --- a/api/task_queue/BUILD.gn +++ b/api/task_queue/BUILD.gn @@ -31,6 +31,7 @@ rtc_library("task_queue") { @@ -466,11 +470,11 @@ index 84a0968ee9..c0209bf0d0 100644 if (rtc_include_tests) { rtc_source_set("test_feedback_generator_interface") { diff --git a/call/BUILD.gn b/call/BUILD.gn -index 66c8b2011a..fa733a67b9 100644 +index 41ed587950..cca88ea7bb 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn -@@ -46,7 +46,7 @@ rtc_library("call_interfaces") { - "../api:rtc_error", +@@ -44,7 +44,7 @@ rtc_library("call_interfaces") { + "../api:network_state_predictor_api", "../api:rtp_headers", "../api:rtp_parameters", - "../api:rtp_sender_interface", @@ -478,13 +482,13 @@ index 66c8b2011a..fa733a67b9 100644 "../api:scoped_refptr", "../api:transport_api", "../api/adaptation:resource_adaptation_api", -@@ -347,6 +347,16 @@ rtc_library("call") { +@@ -345,6 +345,16 @@ rtc_library("call") { "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] + if (build_with_mozilla) { # See Bug 1820869. + sources -= [ -+ "call_factory.cc", ++ "create_call.cc", + "degraded_call.cc", + ] + deps -= [ @@ -495,7 +499,7 @@ index 66c8b2011a..fa733a67b9 100644 } rtc_source_set("receive_stream_interface") { -@@ -374,7 +384,7 @@ rtc_library("video_stream_api") { +@@ -372,7 +382,7 @@ rtc_library("video_stream_api") { "../api:frame_transformer_interface", "../api:rtp_headers", "../api:rtp_parameters", @@ -577,7 +581,7 @@ index 0000000000..f6ff7f218f + #endif +#endif diff --git a/media/BUILD.gn b/media/BUILD.gn -index 295a748802..055bf75a19 100644 +index 2a9cbcbff4..44638d562e 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -64,7 +64,7 @@ rtc_library("rtc_media_base") { @@ -714,7 +718,7 @@ index f941823323..1fe86f9588 100644 namespace cricket { diff --git a/media/base/media_channel_impl.cc b/media/base/media_channel_impl.cc -index e7e84c781c..5b41a9ccda 100644 +index 1c08382969..ff69ea62dc 100644 --- a/media/base/media_channel_impl.cc +++ b/media/base/media_channel_impl.cc @@ -31,19 +31,6 @@ @@ -751,7 +755,7 @@ index 5de99efa45..ddd1fd2656 100644 } diff --git a/modules/audio_device/BUILD.gn b/modules/audio_device/BUILD.gn -index 6f52cf8af1..a135f042db 100644 +index 2088e74dcd..1672be3f95 100644 --- a/modules/audio_device/BUILD.gn +++ b/modules/audio_device/BUILD.gn @@ -30,6 +30,7 @@ rtc_source_set("audio_device_default") { @@ -778,9 +782,9 @@ index 6f52cf8af1..a135f042db 100644 sources = [ "audio_device_buffer.cc", "audio_device_buffer.h", -@@ -89,6 +92,7 @@ rtc_library("audio_device_buffer") { - "../../system_wrappers:metrics", +@@ -90,6 +93,7 @@ rtc_library("audio_device_buffer") { ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } +} @@ -823,9 +827,9 @@ index 6f52cf8af1..a135f042db 100644 rtc_source_set("mock_audio_device") { visibility = [ "*" ] testonly = true -@@ -455,8 +462,10 @@ rtc_source_set("mock_audio_device") { - "../../test:test_support", +@@ -456,8 +463,10 @@ rtc_source_set("mock_audio_device") { ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } +} @@ -1001,7 +1005,7 @@ index 8cefe5653c..b8d75865f7 100644 } } diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn -index 730ec9bfdd..d473dbb74c 100644 +index b583814ebe..aabf545728 100644 --- a/modules/video_capture/BUILD.gn +++ b/modules/video_capture/BUILD.gn @@ -125,21 +125,12 @@ if (!build_with_chromium || is_linux || is_chromeos) { @@ -1028,7 +1032,7 @@ index 730ec9bfdd..d473dbb74c 100644 "/config/external/nspr", "/nsprpub/lib/ds", diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn -index 9f5f0aad56..089b9971a3 100644 +index 84dc1718b4..7372b539c4 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -327,6 +327,7 @@ rtc_library("sample_counter") { @@ -1057,7 +1061,7 @@ index 9f5f0aad56..089b9971a3 100644 if (rtc_build_json) { deps += [ "//third_party/jsoncpp" ] } else { -@@ -1223,6 +1227,7 @@ if (!build_with_chromium) { +@@ -1227,6 +1231,7 @@ if (!build_with_chromium) { } rtc_library("network") { @@ -1065,7 +1069,7 @@ index 9f5f0aad56..089b9971a3 100644 visibility = [ "*" ] sources = [ "network.cc", -@@ -1261,16 +1266,20 @@ rtc_library("network") { +@@ -1265,16 +1270,20 @@ rtc_library("network") { deps += [ ":win32" ] } } @@ -1086,7 +1090,7 @@ index 9f5f0aad56..089b9971a3 100644 visibility = [ "*" ] sources = [ "net_helper.cc", -@@ -1279,8 +1288,10 @@ rtc_library("net_helper") { +@@ -1283,8 +1292,10 @@ rtc_library("net_helper") { absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] deps = [ "system:rtc_export" ] } @@ -1097,7 +1101,7 @@ index 9f5f0aad56..089b9971a3 100644 visibility = [ "*" ] sources = [ "socket_adapters.cc", -@@ -1300,6 +1311,7 @@ rtc_library("socket_adapters") { +@@ -1304,6 +1315,7 @@ rtc_library("socket_adapters") { ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } @@ -1105,7 +1109,7 @@ index 9f5f0aad56..089b9971a3 100644 rtc_library("network_route") { sources = [ -@@ -1314,6 +1326,7 @@ rtc_library("network_route") { +@@ -1318,6 +1330,7 @@ rtc_library("network_route") { } rtc_library("async_tcp_socket") { @@ -1113,7 +1117,7 @@ index 9f5f0aad56..089b9971a3 100644 sources = [ "async_tcp_socket.cc", "async_tcp_socket.h", -@@ -1331,8 +1344,10 @@ rtc_library("async_tcp_socket") { +@@ -1335,8 +1348,10 @@ rtc_library("async_tcp_socket") { "network:sent_packet", ] } @@ -1124,7 +1128,7 @@ index 9f5f0aad56..089b9971a3 100644 visibility = [ "*" ] sources = [ "async_udp_socket.cc", -@@ -1354,8 +1369,10 @@ rtc_library("async_udp_socket") { +@@ -1360,8 +1375,10 @@ rtc_library("async_udp_socket") { ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] } @@ -1135,7 +1139,7 @@ index 9f5f0aad56..089b9971a3 100644 visibility = [ "*" ] sources = [ "async_packet_socket.cc", -@@ -1375,6 +1392,7 @@ rtc_library("async_packet_socket") { +@@ -1381,6 +1398,7 @@ rtc_library("async_packet_socket") { "third_party/sigslot", ] } @@ -1143,7 +1147,7 @@ index 9f5f0aad56..089b9971a3 100644 if (rtc_include_tests) { rtc_library("async_packet_socket_unittest") { -@@ -1402,6 +1420,7 @@ rtc_library("dscp") { +@@ -1408,6 +1426,7 @@ rtc_library("dscp") { } rtc_library("proxy_info") { @@ -1151,7 +1155,7 @@ index 9f5f0aad56..089b9971a3 100644 visibility = [ "*" ] sources = [ "proxy_info.cc", -@@ -1412,6 +1431,7 @@ rtc_library("proxy_info") { +@@ -1418,6 +1437,7 @@ rtc_library("proxy_info") { ":socket_address", ] } @@ -1159,7 +1163,7 @@ index 9f5f0aad56..089b9971a3 100644 rtc_library("file_rotating_stream") { sources = [ -@@ -1440,6 +1460,7 @@ rtc_library("data_rate_limiter") { +@@ -1446,6 +1466,7 @@ rtc_library("data_rate_limiter") { } rtc_library("unique_id_generator") { @@ -1167,7 +1171,7 @@ index 9f5f0aad56..089b9971a3 100644 sources = [ "unique_id_generator.cc", "unique_id_generator.h", -@@ -1454,6 +1475,7 @@ rtc_library("unique_id_generator") { +@@ -1460,6 +1481,7 @@ rtc_library("unique_id_generator") { ] absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } @@ -1175,7 +1179,7 @@ index 9f5f0aad56..089b9971a3 100644 rtc_library("crc32") { sources = [ -@@ -1481,6 +1503,7 @@ rtc_library("stream") { +@@ -1487,6 +1509,7 @@ rtc_library("stream") { } rtc_library("rtc_certificate_generator") { @@ -1183,7 +1187,7 @@ index 9f5f0aad56..089b9971a3 100644 visibility = [ "*" ] sources = [ "rtc_certificate_generator.cc", -@@ -1498,8 +1521,10 @@ rtc_library("rtc_certificate_generator") { +@@ -1504,8 +1527,10 @@ rtc_library("rtc_certificate_generator") { "//third_party/abseil-cpp/absl/types:optional", ] } @@ -1194,7 +1198,7 @@ index 9f5f0aad56..089b9971a3 100644 visibility = [ "*" ] sources = [ "helpers.cc", -@@ -1600,6 +1625,7 @@ rtc_library("ssl") { +@@ -1606,6 +1631,7 @@ rtc_library("ssl") { deps += [ ":win32" ] } } @@ -1202,7 +1206,7 @@ index 9f5f0aad56..089b9971a3 100644 rtc_library("crypt_string") { sources = [ -@@ -1609,6 +1635,7 @@ rtc_library("crypt_string") { +@@ -1615,6 +1641,7 @@ rtc_library("crypt_string") { } rtc_library("http_common") { @@ -1210,7 +1214,7 @@ index 9f5f0aad56..089b9971a3 100644 sources = [ "http_common.cc", "http_common.h", -@@ -1625,6 +1652,7 @@ rtc_library("http_common") { +@@ -1631,6 +1658,7 @@ rtc_library("http_common") { absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] } @@ -1218,7 +1222,7 @@ index 9f5f0aad56..089b9971a3 100644 rtc_source_set("gtest_prod") { sources = [ "gtest_prod_util.h" ] -@@ -2189,7 +2217,7 @@ if (rtc_include_tests) { +@@ -2191,7 +2219,7 @@ if (rtc_include_tests) { } } @@ -1241,10 +1245,10 @@ index 77f5139a2f..486b37590c 100644 deps += [ "..:logging", diff --git a/test/BUILD.gn b/test/BUILD.gn -index d313c6d82d..854530c01e 100644 +index 2a37b78c7c..75d8d9f3a8 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn -@@ -241,6 +241,7 @@ rtc_library("audio_test_common") { +@@ -239,6 +239,7 @@ rtc_library("audio_test_common") { absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } @@ -1252,7 +1256,7 @@ index d313c6d82d..854530c01e 100644 if (!build_with_chromium) { if (is_mac || is_ios) { rtc_library("video_test_mac") { -@@ -294,8 +295,12 @@ if (!build_with_chromium) { +@@ -292,8 +293,12 @@ if (!build_with_chromium) { } } } @@ -1265,7 +1269,7 @@ index d313c6d82d..854530c01e 100644 testonly = true sources = [ "rtcp_packet_parser.cc", -@@ -305,6 +310,7 @@ rtc_library("rtp_test_utils") { +@@ -303,6 +308,7 @@ rtc_library("rtp_test_utils") { "rtp_file_writer.cc", "rtp_file_writer.h", ] @@ -1273,7 +1277,7 @@ index d313c6d82d..854530c01e 100644 deps = [ "../api:array_view", -@@ -560,7 +566,9 @@ rtc_library("video_test_support") { +@@ -558,7 +564,9 @@ rtc_library("video_test_support") { absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] if (!is_ios) { @@ -1300,7 +1304,7 @@ index d313c6d82d..854530c01e 100644 rtc_library("call_config_utils") { testonly = true diff --git a/video/BUILD.gn b/video/BUILD.gn -index 204c6b66f4..0a930053c0 100644 +index 0891a31f7b..2d6d8ab10c 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -17,7 +17,7 @@ rtc_library("video_stream_encoder_interface") { @@ -1312,7 +1316,7 @@ index 204c6b66f4..0a930053c0 100644 "../api:scoped_refptr", "../api/adaptation:resource_adaptation_api", "../api/units:data_rate", -@@ -404,7 +404,7 @@ rtc_library("video_stream_encoder_impl") { +@@ -409,7 +409,7 @@ rtc_library("video_stream_encoder_impl") { ":video_stream_encoder_interface", "../api:field_trials_view", "../api:rtp_parameters", diff --git a/third_party/libwebrtc/moz-patch-stack/0031.patch b/third_party/libwebrtc/moz-patch-stack/0031.patch index 0b1372a1dd..36c96225d0 100644 --- a/third_party/libwebrtc/moz-patch-stack/0031.patch +++ b/third_party/libwebrtc/moz-patch-stack/0031.patch @@ -9,10 +9,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/7163801a480d60700 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/channel_send.cc b/audio/channel_send.cc -index ecf2cb5175..310e0517cf 100644 +index 68cd099a23..ab1b72a2f3 100644 --- a/audio/channel_send.cc +++ b/audio/channel_send.cc -@@ -639,9 +639,9 @@ void ChannelSend::SetSendAudioLevelIndicationStatus(bool enable, int id) { +@@ -643,9 +643,9 @@ void ChannelSend::SetSendAudioLevelIndicationStatus(bool enable, int id) { RTC_DCHECK_RUN_ON(&worker_thread_checker_); include_audio_level_indication_.store(enable); if (enable) { diff --git a/third_party/libwebrtc/moz-patch-stack/0033.patch b/third_party/libwebrtc/moz-patch-stack/0033.patch index 5c69ef0bce..62695eeb23 100644 --- a/third_party/libwebrtc/moz-patch-stack/0033.patch +++ b/third_party/libwebrtc/moz-patch-stack/0033.patch @@ -15,10 +15,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/d380a43d59f4f7cbc 4 files changed, 35 insertions(+) diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc -index c9dc42c04e..e7ebb2bf4e 100644 +index 3701eafd6f..8dc78b18fa 100644 --- a/audio/audio_send_stream.cc +++ b/audio/audio_send_stream.cc -@@ -431,6 +431,7 @@ webrtc::AudioSendStream::Stats AudioSendStream::GetStats( +@@ -432,6 +432,7 @@ webrtc::AudioSendStream::Stats AudioSendStream::GetStats( stats.target_bitrate_bps = channel_send_->GetTargetBitrate(); webrtc::CallSendStatistics call_stats = channel_send_->GetRTCPStatistics(); @@ -27,7 +27,7 @@ index c9dc42c04e..e7ebb2bf4e 100644 stats.header_and_padding_bytes_sent = call_stats.header_and_padding_bytes_sent; diff --git a/audio/channel_send.cc b/audio/channel_send.cc -index 310e0517cf..549e65a59c 100644 +index ab1b72a2f3..db632b3aa8 100644 --- a/audio/channel_send.cc +++ b/audio/channel_send.cc @@ -56,6 +56,31 @@ constexpr int64_t kMinRetransmissionWindowMs = 30; @@ -64,14 +64,14 @@ index 310e0517cf..549e65a59c 100644 // packets from the ACM @@ -210,6 +235,8 @@ class ChannelSend : public ChannelSendInterface, bool input_mute_ RTC_GUARDED_BY(volume_settings_mutex_) = false; - bool previous_frame_muted_ RTC_GUARDED_BY(encoder_queue_) = false; + bool previous_frame_muted_ RTC_GUARDED_BY(encoder_queue_checker_) = false; + const std::unique_ptr rtcp_counter_observer_; + PacketRouter* packet_router_ RTC_GUARDED_BY(&worker_thread_checker_) = nullptr; const std::unique_ptr rtp_packet_pacer_proxy_; -@@ -398,6 +425,7 @@ ChannelSend::ChannelSend( +@@ -397,6 +424,7 @@ ChannelSend::ChannelSend( const FieldTrialsView& field_trials) : ssrc_(ssrc), event_log_(rtc_event_log), @@ -88,7 +88,7 @@ index 310e0517cf..549e65a59c 100644 if (field_trials.IsDisabled("WebRTC-DisableRtxRateLimiter")) { configuration.retransmission_rate_limiter = retransmission_rate_limiter_.get(); -@@ -687,6 +717,7 @@ CallSendStatistics ChannelSend::GetRTCPStatistics() const { +@@ -691,6 +721,7 @@ CallSendStatistics ChannelSend::GetRTCPStatistics() const { RTC_DCHECK_RUN_ON(&worker_thread_checker_); CallSendStatistics stats = {0}; stats.rttMs = GetRTT(); diff --git a/third_party/libwebrtc/moz-patch-stack/0034.patch b/third_party/libwebrtc/moz-patch-stack/0034.patch index 979f7f8528..3dfd2e8007 100644 --- a/third_party/libwebrtc/moz-patch-stack/0034.patch +++ b/third_party/libwebrtc/moz-patch-stack/0034.patch @@ -25,7 +25,7 @@ index 95f1a47f4e..a1fc204e7c 100644 // See LntfConfig for description. diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index 9a38097a93..d12e833cab 100644 +index badb942cd4..1f4cc5b6be 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc @@ -296,9 +296,8 @@ RtpVideoStreamReceiver2::RtpVideoStreamReceiver2( diff --git a/third_party/libwebrtc/moz-patch-stack/0042.patch b/third_party/libwebrtc/moz-patch-stack/0042.patch index 42bc15e1f6..7ffec6a12e 100644 --- a/third_party/libwebrtc/moz-patch-stack/0042.patch +++ b/third_party/libwebrtc/moz-patch-stack/0042.patch @@ -20,7 +20,7 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/d0b311007c033e838 11 files changed, 57 insertions(+), 10 deletions(-) diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc -index 978bbb25b2..655b2761ac 100644 +index 415ad0640a..1e8cff5441 100644 --- a/audio/audio_receive_stream.cc +++ b/audio/audio_receive_stream.cc @@ -39,6 +39,8 @@ std::string AudioReceiveStreamInterface::Config::Rtp::ToString() const { @@ -189,7 +189,7 @@ index 249cf835ba..de85abd4ae 100644 static constexpr size_t kNumMediaTypes = 5; enum class RtpPacketMediaType : size_t { diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc -index a98b200c05..e2ad674012 100644 +index a596ef5fd4..9c6ceb2403 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -144,6 +144,7 @@ RTCPReceiver::RTCPReceiver(const RtpRtcpInterface::Configuration& config, @@ -269,7 +269,7 @@ index 0bdd389795..2c56dccd2a 100644 TransportFeedbackObserver* transport_feedback_callback = nullptr; VideoBitrateAllocationObserver* bitrate_allocation_observer = nullptr; diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index d12e833cab..2ea8ce8c62 100644 +index 1f4cc5b6be..9694f1d0c1 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc @@ -83,7 +83,8 @@ std::unique_ptr CreateRtpRtcpModule( diff --git a/third_party/libwebrtc/moz-patch-stack/0044.patch b/third_party/libwebrtc/moz-patch-stack/0044.patch index 7fdc82d1da..e38e7de18f 100644 --- a/third_party/libwebrtc/moz-patch-stack/0044.patch +++ b/third_party/libwebrtc/moz-patch-stack/0044.patch @@ -15,10 +15,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/edac9d01a9ac7594f 3 files changed, 24 insertions(+) diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index 2ea8ce8c62..0a215f79cc 100644 +index 9694f1d0c1..79ce90794e 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc -@@ -1066,6 +1066,16 @@ absl::optional RtpVideoStreamReceiver2::LastReceivedKeyframePacketMs() +@@ -1062,6 +1062,16 @@ absl::optional RtpVideoStreamReceiver2::LastReceivedKeyframePacketMs() return absl::nullopt; } @@ -36,10 +36,10 @@ index 2ea8ce8c62..0a215f79cc 100644 std::unique_ptr frame) { RTC_DCHECK_RUN_ON(&packet_sequence_checker_); diff --git a/video/rtp_video_stream_receiver2.h b/video/rtp_video_stream_receiver2.h -index 0178355262..be8bce770f 100644 +index d436aa38a7..4a93e53356 100644 --- a/video/rtp_video_stream_receiver2.h +++ b/video/rtp_video_stream_receiver2.h -@@ -207,6 +207,12 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender, +@@ -209,6 +209,12 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender, absl::optional LastReceivedFrameRtpTimestamp() const; absl::optional LastReceivedKeyframePacketMs() const; @@ -53,10 +53,10 @@ index 0178355262..be8bce770f 100644 // Implements RtpVideoFrameReceiver. void ManageFrame(std::unique_ptr frame) override; diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc -index af25c364de..776c49042b 100644 +index 9e095064ba..3d0534bf10 100644 --- a/video/video_receive_stream2.cc +++ b/video/video_receive_stream2.cc -@@ -570,6 +570,14 @@ VideoReceiveStreamInterface::Stats VideoReceiveStream2::GetStats() const { +@@ -568,6 +568,14 @@ VideoReceiveStreamInterface::Stats VideoReceiveStream2::GetStats() const { stats.rtx_rtp_stats = rtx_statistician->GetStats(); } } diff --git a/third_party/libwebrtc/moz-patch-stack/0046.patch b/third_party/libwebrtc/moz-patch-stack/0046.patch index 77e1314bb9..dc5987aed0 100644 --- a/third_party/libwebrtc/moz-patch-stack/0046.patch +++ b/third_party/libwebrtc/moz-patch-stack/0046.patch @@ -16,10 +16,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/c186df8a088e46285 1 file changed, 1 deletion(-) diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc -index 655b2761ac..c49b83f95f 100644 +index 1e8cff5441..32a8e1c172 100644 --- a/audio/audio_receive_stream.cc +++ b/audio/audio_receive_stream.cc -@@ -366,7 +366,6 @@ int AudioReceiveStreamImpl::GetBaseMinimumPlayoutDelayMs() const { +@@ -368,7 +368,6 @@ int AudioReceiveStreamImpl::GetBaseMinimumPlayoutDelayMs() const { } std::vector AudioReceiveStreamImpl::GetSources() const { diff --git a/third_party/libwebrtc/moz-patch-stack/0047.patch b/third_party/libwebrtc/moz-patch-stack/0047.patch index bcaee89ce5..9fd44ff47f 100644 --- a/third_party/libwebrtc/moz-patch-stack/0047.patch +++ b/third_party/libwebrtc/moz-patch-stack/0047.patch @@ -5,14 +5,14 @@ Subject: Bug 1714577 - Part 6 - Copy WebRTC's trace_event.h to Gecko, Differential Revision: https://phabricator.services.mozilla.com/D116843 --- - rtc_base/trace_event.h | 1055 +--------------------------------------- - 1 file changed, 3 insertions(+), 1052 deletions(-) + rtc_base/trace_event.h | 924 +---------------------------------------- + 1 file changed, 3 insertions(+), 921 deletions(-) diff --git a/rtc_base/trace_event.h b/rtc_base/trace_event.h -index 6689bc0c37..b34df0c93f 100644 +index 32ad031385..b34df0c93f 100644 --- a/rtc_base/trace_event.h +++ b/rtc_base/trace_event.h -@@ -1,1052 +1,3 @@ +@@ -1,921 +1,3 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file under third_party_mods/chromium or at: @@ -445,100 +445,6 @@ index 6689bc0c37..b34df0c93f 100644 - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ - arg1_val, arg2_name, arg2_val) - --// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2 --// associated arguments. If the category is not enabled, then this --// does nothing. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --// - `id` is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW --// events are considered to match if their category, name and id values all --// match. `id` must either be a pointer or an integer value up to 64 bits. If --// it's a pointer, the bits will be xored with a hash of the process ID so --// that the same pointer on two different processes will not collide. --// FLOW events are different from ASYNC events in how they are drawn by the --// tracing UI. A FLOW defines asynchronous data flow, such as posting a task --// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be --// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar --// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined --// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP --// macros. When the operation completes, call FLOW_END. An async operation can --// span threads and processes, but all events in that operation must use the --// same `name` and `id`. Each event can have its own args. --#define TRACE_EVENT_FLOW_BEGIN0(category, name, id) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ -- name, id, TRACE_EVENT_FLAG_NONE) --#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ -- name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ -- arg1_val) --#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ -- name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ -- arg1_val, arg2_name, arg2_val) --#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ -- name, id, TRACE_EVENT_FLAG_COPY) --#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ -- name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ -- arg1_val) --#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, category, \ -- name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ -- arg1_val, arg2_name, arg2_val) -- --// Records a single FLOW_STEP event for `step` immediately. If the category --// is not enabled, then this does nothing. The `name` and `id` must match the --// FLOW_BEGIN event above. The `step` param identifies this step within the --// async event. This should be called at the beginning of the next phase of an --// asynchronous operation. --#define TRACE_EVENT_FLOW_STEP0(category, name, id, step) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, \ -- name, id, TRACE_EVENT_FLAG_NONE, "step", \ -- step) --#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, \ -- name, id, TRACE_EVENT_FLAG_NONE, "step", \ -- step, arg1_name, arg1_val) --#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, \ -- name, id, TRACE_EVENT_FLAG_COPY, "step", \ -- step) --#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, arg1_name, \ -- arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, category, \ -- name, id, TRACE_EVENT_FLAG_COPY, "step", \ -- step, arg1_name, arg1_val) -- --// Records a single FLOW_END event for "name" immediately. If the category --// is not enabled, then this does nothing. --#define TRACE_EVENT_FLOW_END0(category, name, id) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ -- id, TRACE_EVENT_FLAG_NONE) --#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ -- id, TRACE_EVENT_FLAG_NONE, arg1_name, \ -- arg1_val) --#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ -- id, TRACE_EVENT_FLAG_NONE, arg1_name, \ -- arg1_val, arg2_name, arg2_val) --#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ -- id, TRACE_EVENT_FLAG_COPY) --#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ -- id, TRACE_EVENT_FLAG_COPY, arg1_name, \ -- arg1_val) --#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category, name, \ -- id, TRACE_EVENT_FLAG_COPY, arg1_name, \ -- arg1_val, arg2_name, arg2_val) -- -//////////////////////////////////////////////////////////////////////////////// -// Implementation specific tracing API definitions. - @@ -645,9 +551,6 @@ index 6689bc0c37..b34df0c93f 100644 -#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') -#define TRACE_EVENT_PHASE_ASYNC_STEP ('T') -#define TRACE_EVENT_PHASE_ASYNC_END ('F') --#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s') --#define TRACE_EVENT_PHASE_FLOW_STEP ('t') --#define TRACE_EVENT_PHASE_FLOW_END ('f') -#define TRACE_EVENT_PHASE_METADATA ('M') -#define TRACE_EVENT_PHASE_COUNTER ('C') - @@ -1024,40 +927,6 @@ index 6689bc0c37..b34df0c93f 100644 - arg2_name, arg2_val) \ - RTC_NOOP() - --#define TRACE_EVENT_FLOW_BEGIN0(category, name, id) RTC_NOOP() --#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ -- RTC_NOOP() --#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- RTC_NOOP() --#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) RTC_NOOP() --#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ -- RTC_NOOP() --#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- RTC_NOOP() -- --#define TRACE_EVENT_FLOW_STEP0(category, name, id, step) RTC_NOOP() --#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, arg1_name, arg1_val) \ -- RTC_NOOP() --#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) RTC_NOOP() --#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, arg1_name, \ -- arg1_val) \ -- RTC_NOOP() -- --#define TRACE_EVENT_FLOW_END0(category, name, id) RTC_NOOP() --#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \ -- RTC_NOOP() --#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- RTC_NOOP() --#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) RTC_NOOP() --#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \ -- RTC_NOOP() --#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- RTC_NOOP() -- -#define TRACE_EVENT_API_GET_CATEGORY_ENABLED "" - -#define TRACE_EVENT_API_ADD_TRACE_EVENT RTC_NOOP() diff --git a/third_party/libwebrtc/moz-patch-stack/0049.patch b/third_party/libwebrtc/moz-patch-stack/0049.patch index e94ab52a26..3074531967 100644 --- a/third_party/libwebrtc/moz-patch-stack/0049.patch +++ b/third_party/libwebrtc/moz-patch-stack/0049.patch @@ -13,7 +13,7 @@ diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_ca index 56c94baada..8f5dc25516 100644 --- a/modules/desktop_capture/window_capturer_mac.mm +++ b/modules/desktop_capture/window_capturer_mac.mm -@@ -169,8 +169,9 @@ explicit WindowCapturerMac( +@@ -169,8 +169,9 @@ void WindowCapturerMac::CaptureFrame() { return webrtc::GetWindowList( [sources](CFDictionaryRef window) { WindowId window_id = GetWindowId(window); diff --git a/third_party/libwebrtc/moz-patch-stack/0050.patch b/third_party/libwebrtc/moz-patch-stack/0050.patch index e36c3b83c6..a3c23bc40a 100644 --- a/third_party/libwebrtc/moz-patch-stack/0050.patch +++ b/third_party/libwebrtc/moz-patch-stack/0050.patch @@ -37,7 +37,7 @@ index 01fb08a009..87ee39e142 100644 // Timing frame info: all important timestamps for a full lifetime of a // single 'timing frame'. diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc -index e2ad674012..94de316421 100644 +index 9c6ceb2403..5c85734e58 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -365,11 +365,13 @@ RTCPReceiver::ConsumeReceivedXrReferenceTimeInfo() { @@ -159,10 +159,10 @@ index 2c56dccd2a..f196d11b58 100644 // Within this list, the sender-source SSRC pair is unique and per-pair the // ReportBlockData represents the latest Report Block that was received for diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index 0a215f79cc..47c31812f3 100644 +index 79ce90794e..029e7a7405 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc -@@ -1071,9 +1071,10 @@ absl::optional RtpVideoStreamReceiver2::LastReceivedKeyframePacketMs() +@@ -1067,9 +1067,10 @@ absl::optional RtpVideoStreamReceiver2::LastReceivedKeyframePacketMs() // seem to be any support for these stats right now. So, we hack this in. void RtpVideoStreamReceiver2::RemoteRTCPSenderInfo( uint32_t* packet_count, uint32_t* octet_count, @@ -176,10 +176,10 @@ index 0a215f79cc..47c31812f3 100644 void RtpVideoStreamReceiver2::ManageFrame( diff --git a/video/rtp_video_stream_receiver2.h b/video/rtp_video_stream_receiver2.h -index be8bce770f..0e96d7f2cd 100644 +index 4a93e53356..00b17a77bd 100644 --- a/video/rtp_video_stream_receiver2.h +++ b/video/rtp_video_stream_receiver2.h -@@ -211,7 +211,8 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender, +@@ -213,7 +213,8 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender, // stats at all, and even on the most recent libwebrtc code there does not // seem to be any support for these stats right now. So, we hack this in. void RemoteRTCPSenderInfo(uint32_t* packet_count, uint32_t* octet_count, @@ -190,10 +190,10 @@ index be8bce770f..0e96d7f2cd 100644 private: // Implements RtpVideoFrameReceiver. diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc -index 776c49042b..c04b43a1d1 100644 +index 3d0534bf10..f135f42f3b 100644 --- a/video/video_receive_stream2.cc +++ b/video/video_receive_stream2.cc -@@ -576,7 +576,8 @@ VideoReceiveStreamInterface::Stats VideoReceiveStream2::GetStats() const { +@@ -574,7 +574,8 @@ VideoReceiveStreamInterface::Stats VideoReceiveStream2::GetStats() const { // seem to be any support for these stats right now. So, we hack this in. rtp_video_stream_receiver_.RemoteRTCPSenderInfo( &stats.rtcp_sender_packets_sent, &stats.rtcp_sender_octets_sent, diff --git a/third_party/libwebrtc/moz-patch-stack/0052.patch b/third_party/libwebrtc/moz-patch-stack/0052.patch index 616b4fdcc7..98c4d5dafd 100644 --- a/third_party/libwebrtc/moz-patch-stack/0052.patch +++ b/third_party/libwebrtc/moz-patch-stack/0052.patch @@ -12,8 +12,6 @@ Differential Revision: https://phabricator.services.mozilla.com/D127714 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/0744d68b8c944e69945de4ac5c4ca71332e78ad8 --- audio/channel_send.cc | 2 +- - call/call.cc | 2 ++ - call/call_factory.cc | 4 ++++ call/degraded_call.cc | 2 ++ modules/audio_coding/acm2/acm_receiver.cc | 2 +- modules/rtp_rtcp/include/flexfec_receiver.h | 2 ++ @@ -21,10 +19,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/0744d68b8c944e699 rtc_base/task_utils/repeating_task.h | 4 ++-- system_wrappers/include/clock.h | 2 +- system_wrappers/source/clock.cc | 2 +- - 10 files changed, 18 insertions(+), 6 deletions(-) + 8 files changed, 12 insertions(+), 6 deletions(-) diff --git a/audio/channel_send.cc b/audio/channel_send.cc -index 549e65a59c..8080f4a3b8 100644 +index db632b3aa8..c8251b4b52 100644 --- a/audio/channel_send.cc +++ b/audio/channel_send.cc @@ -443,7 +443,7 @@ ChannelSend::ChannelSend( @@ -36,48 +34,6 @@ index 549e65a59c..8080f4a3b8 100644 configuration.audio = true; configuration.outgoing_transport = rtp_transport; -diff --git a/call/call.cc b/call/call.cc -index 42b3b988ea..d2ac705274 100644 ---- a/call/call.cc -+++ b/call/call.cc -@@ -473,6 +473,7 @@ std::string Call::Stats::ToString(int64_t time_ms) const { - return ss.str(); - } - -+/* Mozilla: Avoid this since it could use GetRealTimeClock(). - std::unique_ptr Call::Create(const CallConfig& config) { - Clock* clock = - config.env.has_value() ? &config.env->clock() : Clock::GetRealTimeClock(); -@@ -480,6 +481,7 @@ std::unique_ptr Call::Create(const CallConfig& config) { - RtpTransportControllerSendFactory().Create( - config.ExtractTransportConfig(), clock)); - } -+ */ - - std::unique_ptr Call::Create( - const CallConfig& config, -diff --git a/call/call_factory.cc b/call/call_factory.cc -index 043b11da37..78a4f1635f 100644 ---- a/call/call_factory.cc -+++ b/call/call_factory.cc -@@ -94,6 +94,9 @@ std::unique_ptr CallFactory::CreateCall(const CallConfig& config) { - - RtpTransportConfig transportConfig = config.ExtractTransportConfig(); - -+ RTC_CHECK(false); -+ return nullptr; -+ /* Mozilla: Avoid this since it could use GetRealTimeClock(). - std::unique_ptr call = - Call::Create(config, Clock::GetRealTimeClock(), - config.rtp_transport_controller_send_factory->Create( -@@ -106,6 +109,7 @@ std::unique_ptr CallFactory::CreateCall(const CallConfig& config) { - } - - return call; -+ */ - } - - std::unique_ptr CreateCallFactory() { diff --git a/call/degraded_call.cc b/call/degraded_call.cc index a511eda7bd..75a4a1cac0 100644 --- a/call/degraded_call.cc diff --git a/third_party/libwebrtc/moz-patch-stack/0053.patch b/third_party/libwebrtc/moz-patch-stack/0053.patch index 56c0b13b8e..26d747a4fc 100644 --- a/third_party/libwebrtc/moz-patch-stack/0053.patch +++ b/third_party/libwebrtc/moz-patch-stack/0053.patch @@ -32,7 +32,7 @@ index d2ede84941..f595a2951a 100644 defines += [ "WEBRTC_MAC" ] } diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn -index d473dbb74c..8f89918359 100644 +index aabf545728..8dda0e6ef1 100644 --- a/modules/video_capture/BUILD.gn +++ b/modules/video_capture/BUILD.gn @@ -71,7 +71,7 @@ if (!build_with_chromium || is_linux || is_chromeos) { diff --git a/third_party/libwebrtc/moz-patch-stack/0054.patch b/third_party/libwebrtc/moz-patch-stack/0054.patch index 928198e5a4..f07a706f54 100644 --- a/third_party/libwebrtc/moz-patch-stack/0054.patch +++ b/third_party/libwebrtc/moz-patch-stack/0054.patch @@ -4,18 +4,17 @@ Subject: Bug 1766646 - (fix) breakout Call::Stats and SharedModuleThread into seperate files --- - call/BUILD.gn | 6 ++++++ - call/call.cc | 13 ------------- - call/call.h | 12 ++---------- - call/call_basic_stats.cc | 20 ++++++++++++++++++++ - call/call_basic_stats.h | 21 +++++++++++++++++++++ - video/video_send_stream.h | 1 - - 6 files changed, 49 insertions(+), 24 deletions(-) + call/BUILD.gn | 6 ++++++ + call/call.cc | 13 ------------- + call/call.h | 12 ++---------- + call/call_basic_stats.cc | 20 ++++++++++++++++++++ + call/call_basic_stats.h | 21 +++++++++++++++++++++ + 5 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 call/call_basic_stats.cc create mode 100644 call/call_basic_stats.h diff --git a/call/BUILD.gn b/call/BUILD.gn -index fa733a67b9..626ed95066 100644 +index cca88ea7bb..50a8257631 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn @@ -33,6 +33,12 @@ rtc_library("call_interfaces") { @@ -32,10 +31,10 @@ index fa733a67b9..626ed95066 100644 deps = [ ":audio_sender_interface", diff --git a/call/call.cc b/call/call.cc -index d2ac705274..63dc370f1a 100644 +index c97cb6d743..71511b2559 100644 --- a/call/call.cc +++ b/call/call.cc -@@ -460,19 +460,6 @@ class Call final : public webrtc::Call, +@@ -454,19 +454,6 @@ class Call final : public webrtc::Call, }; } // namespace internal @@ -52,11 +51,11 @@ index d2ac705274..63dc370f1a 100644 - return ss.str(); -} - - /* Mozilla: Avoid this since it could use GetRealTimeClock(). std::unique_ptr Call::Create(const CallConfig& config) { - Clock* clock = + std::unique_ptr transport_send; + if (config.rtp_transport_controller_send_factory != nullptr) { diff --git a/call/call.h b/call/call.h -index 6f8e4cd6d7..b36872f5b5 100644 +index a680335192..e7d37c0abd 100644 --- a/call/call.h +++ b/call/call.h @@ -21,6 +21,7 @@ @@ -67,7 +66,7 @@ index 6f8e4cd6d7..b36872f5b5 100644 #include "call/call_config.h" #include "call/flexfec_receive_stream.h" #include "call/packet_receiver.h" -@@ -30,7 +31,6 @@ +@@ -29,7 +30,6 @@ #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/network/sent_packet.h" #include "rtc_base/network_route.h" @@ -75,7 +74,7 @@ index 6f8e4cd6d7..b36872f5b5 100644 namespace webrtc { -@@ -46,15 +46,7 @@ namespace webrtc { +@@ -45,15 +45,7 @@ namespace webrtc { class Call { public: @@ -91,7 +90,7 @@ index 6f8e4cd6d7..b36872f5b5 100644 + using Stats = CallBasicStats; static std::unique_ptr Create(const CallConfig& config); - static std::unique_ptr Create( + diff --git a/call/call_basic_stats.cc b/call/call_basic_stats.cc new file mode 100644 index 0000000000..74333a663b @@ -145,15 +144,3 @@ index 0000000000..98febe9405 +} // namespace webrtc + +#endif // CALL_CALL_BASIC_STATS_H_ -diff --git a/video/video_send_stream.h b/video/video_send_stream.h -index 05970d619e..4afafcf8e4 100644 ---- a/video/video_send_stream.h -+++ b/video/video_send_stream.h -@@ -36,7 +36,6 @@ namespace test { - class VideoSendStreamPeer; - } // namespace test - --class CallStats; - class IvfFileWriter; - class RateLimiter; - class RtpRtcp; diff --git a/third_party/libwebrtc/moz-patch-stack/0064.patch b/third_party/libwebrtc/moz-patch-stack/0064.patch index 4d9c0c6550..e379af2487 100644 --- a/third_party/libwebrtc/moz-patch-stack/0064.patch +++ b/third_party/libwebrtc/moz-patch-stack/0064.patch @@ -13,7 +13,7 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/f097eb8cbd8b7686c 2 files changed, 9 insertions(+) diff --git a/api/task_queue/BUILD.gn b/api/task_queue/BUILD.gn -index d557d8f100..9b2f747e78 100644 +index afdf47dfc9..b9bc81171f 100644 --- a/api/task_queue/BUILD.gn +++ b/api/task_queue/BUILD.gn @@ -31,6 +31,11 @@ rtc_library("task_queue") { @@ -29,7 +29,7 @@ index d557d8f100..9b2f747e78 100644 rtc_library("task_queue_test") { visibility = [ "*" ] diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn -index 089b9971a3..5392e5f472 100644 +index 7372b539c4..57a9c11f01 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -743,10 +743,14 @@ if (is_mac || is_ios) { diff --git a/third_party/libwebrtc/moz-patch-stack/0068.patch b/third_party/libwebrtc/moz-patch-stack/0068.patch index ab46127e4f..38bae4d1e8 100644 --- a/third_party/libwebrtc/moz-patch-stack/0068.patch +++ b/third_party/libwebrtc/moz-patch-stack/0068.patch @@ -215,7 +215,7 @@ index 8e4941f961..7bcfc7c057 100644 int current_delay_ms, int target_delay_ms, diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index 47c31812f3..0954327f1c 100644 +index 029e7a7405..26bd60057d 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc @@ -244,6 +244,7 @@ RtpVideoStreamReceiver2::RtpVideoStreamReceiver2( @@ -234,7 +234,7 @@ index 47c31812f3..0954327f1c 100644 packet_buffer_(kPacketBufferStartSize, PacketBufferMaxSize(field_trials_)), reference_finder_(std::make_unique()), -@@ -1219,7 +1221,8 @@ void RtpVideoStreamReceiver2::FrameDecoded(int64_t picture_id) { +@@ -1250,7 +1252,8 @@ void RtpVideoStreamReceiver2::FrameDecoded(int64_t picture_id) { int64_t unwrapped_rtp_seq_num = rtp_seq_num_unwrapper_.Unwrap(seq_num); packet_infos_.erase(packet_infos_.begin(), packet_infos_.upper_bound(unwrapped_rtp_seq_num)); @@ -245,7 +245,7 @@ index 47c31812f3..0954327f1c 100644 } } diff --git a/video/rtp_video_stream_receiver2.h b/video/rtp_video_stream_receiver2.h -index 0e96d7f2cd..10329005ba 100644 +index 00b17a77bd..b942cb97a6 100644 --- a/video/rtp_video_stream_receiver2.h +++ b/video/rtp_video_stream_receiver2.h @@ -49,6 +49,7 @@ @@ -264,7 +264,7 @@ index 0e96d7f2cd..10329005ba 100644 // The KeyFrameRequestSender is optional; if not provided, key frame // requests are sent via the internal RtpRtcp module. OnCompleteFrameCallback* complete_frame_callback, -@@ -362,6 +364,7 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender, +@@ -365,6 +367,7 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender, std::unique_ptr loss_notification_controller_ RTC_GUARDED_BY(packet_sequence_checker_); @@ -273,10 +273,10 @@ index 0e96d7f2cd..10329005ba 100644 RTC_GUARDED_BY(packet_sequence_checker_); UniqueTimestampCounter frame_counter_ diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc -index c04b43a1d1..33e2f39ced 100644 +index f135f42f3b..8675ab9979 100644 --- a/video/video_receive_stream2.cc +++ b/video/video_receive_stream2.cc -@@ -210,6 +210,7 @@ VideoReceiveStream2::VideoReceiveStream2( +@@ -209,6 +209,7 @@ VideoReceiveStream2::VideoReceiveStream2( &stats_proxy_, &stats_proxy_, nack_periodic_processor, diff --git a/third_party/libwebrtc/moz-patch-stack/0069.patch b/third_party/libwebrtc/moz-patch-stack/0069.patch index 6b36a1a2b7..54357d2957 100644 --- a/third_party/libwebrtc/moz-patch-stack/0069.patch +++ b/third_party/libwebrtc/moz-patch-stack/0069.patch @@ -30,10 +30,10 @@ index 8ef4d553ad..a0f19999d8 100644 void ReceiveStatisticsProxy::OnPreDecode(VideoCodecType codec_type, int qp) { diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index 0954327f1c..12e777c58f 100644 +index 26bd60057d..daf601c6cb 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc -@@ -1222,7 +1222,9 @@ void RtpVideoStreamReceiver2::FrameDecoded(int64_t picture_id) { +@@ -1253,7 +1253,9 @@ void RtpVideoStreamReceiver2::FrameDecoded(int64_t picture_id) { packet_infos_.erase(packet_infos_.begin(), packet_infos_.upper_bound(unwrapped_rtp_seq_num)); uint32_t num_packets_cleared = packet_buffer_.ClearTo(seq_num); diff --git a/third_party/libwebrtc/moz-patch-stack/0070.patch b/third_party/libwebrtc/moz-patch-stack/0070.patch index a63b0af9c2..842b9da193 100644 --- a/third_party/libwebrtc/moz-patch-stack/0070.patch +++ b/third_party/libwebrtc/moz-patch-stack/0070.patch @@ -166,7 +166,7 @@ index a0f19999d8..1764308c0a 100644 } diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index 12e777c58f..a07dad5d4b 100644 +index daf601c6cb..5e563d001c 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc @@ -44,6 +44,7 @@ @@ -177,7 +177,7 @@ index 12e777c58f..a07dad5d4b 100644 #include "system_wrappers/include/metrics.h" #include "system_wrappers/include/ntp_time.h" -@@ -1223,6 +1224,9 @@ void RtpVideoStreamReceiver2::FrameDecoded(int64_t picture_id) { +@@ -1254,6 +1255,9 @@ void RtpVideoStreamReceiver2::FrameDecoded(int64_t picture_id) { packet_infos_.upper_bound(unwrapped_rtp_seq_num)); uint32_t num_packets_cleared = packet_buffer_.ClearTo(seq_num); if (num_packets_cleared > 0) { diff --git a/third_party/libwebrtc/moz-patch-stack/0071.patch b/third_party/libwebrtc/moz-patch-stack/0071.patch index 7aed95255b..5495f3d035 100644 --- a/third_party/libwebrtc/moz-patch-stack/0071.patch +++ b/third_party/libwebrtc/moz-patch-stack/0071.patch @@ -9,10 +9,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/5b2a7894ef1cf096d 1 file changed, 6 insertions(+) diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index a07dad5d4b..db0b87c736 100644 +index 5e563d001c..4df65659f9 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc -@@ -744,6 +744,12 @@ void RtpVideoStreamReceiver2::OnRtpPacket(const RtpPacketReceived& packet) { +@@ -740,6 +740,12 @@ void RtpVideoStreamReceiver2::OnRtpPacket(const RtpPacketReceived& packet) { void RtpVideoStreamReceiver2::RequestKeyFrame() { RTC_DCHECK_RUN_ON(&worker_task_checker_); diff --git a/third_party/libwebrtc/moz-patch-stack/0076.patch b/third_party/libwebrtc/moz-patch-stack/0076.patch index ae3f880387..d3aec3677e 100644 --- a/third_party/libwebrtc/moz-patch-stack/0076.patch +++ b/third_party/libwebrtc/moz-patch-stack/0076.patch @@ -9,10 +9,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/108046c7cbb21c6cf 1 file changed, 1 insertion(+) diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc -index c80cc76a3d..c304453388 100644 +index 0104e0c486..4ac074526c 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc -@@ -450,6 +450,7 @@ AudioProcessingImpl::GetGainController2ExperimentParams() { +@@ -452,6 +452,7 @@ AudioProcessingImpl::GetGainController2ExperimentParams() { }, .adaptive_digital_controller = { diff --git a/third_party/libwebrtc/moz-patch-stack/0078.patch b/third_party/libwebrtc/moz-patch-stack/0078.patch index c7d811ffd7..01ab27f1e6 100644 --- a/third_party/libwebrtc/moz-patch-stack/0078.patch +++ b/third_party/libwebrtc/moz-patch-stack/0078.patch @@ -11,7 +11,7 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/8ff886a4d366b4be3 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn -index 8f89918359..45a0272eee 100644 +index 8dda0e6ef1..3132e452ba 100644 --- a/modules/video_capture/BUILD.gn +++ b/modules/video_capture/BUILD.gn @@ -104,6 +104,10 @@ if (!build_with_chromium || is_linux || is_chromeos) { diff --git a/third_party/libwebrtc/moz-patch-stack/0079.patch b/third_party/libwebrtc/moz-patch-stack/0079.patch index 1e8257408f..15d16557c2 100644 --- a/third_party/libwebrtc/moz-patch-stack/0079.patch +++ b/third_party/libwebrtc/moz-patch-stack/0079.patch @@ -9,7 +9,7 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/154c9cdb386d0f50c 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc -index 94de316421..bda6ad9a52 100644 +index 5c85734e58..756136866d 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -368,10 +368,10 @@ void RTCPReceiver::RemoteRTCPSenderInfo(uint32_t* packet_count, diff --git a/third_party/libwebrtc/moz-patch-stack/0081.patch b/third_party/libwebrtc/moz-patch-stack/0081.patch index 8a60e356af..2fbb974454 100644 --- a/third_party/libwebrtc/moz-patch-stack/0081.patch +++ b/third_party/libwebrtc/moz-patch-stack/0081.patch @@ -10,10 +10,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/a7179d8d75313b6c9 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc -index 552463e143..669f165635 100644 +index 3730f6eecb..d74f440996 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc -@@ -1375,7 +1375,7 @@ void VideoStreamEncoder::ReconfigureEncoder() { +@@ -1383,7 +1383,7 @@ void VideoStreamEncoder::ReconfigureEncoder() { bool is_svc = false; bool single_stream_or_non_first_inactive = true; diff --git a/third_party/libwebrtc/moz-patch-stack/0083.patch b/third_party/libwebrtc/moz-patch-stack/0083.patch index 181d1439da..3c6ab41ddf 100644 --- a/third_party/libwebrtc/moz-patch-stack/0083.patch +++ b/third_party/libwebrtc/moz-patch-stack/0083.patch @@ -12,7 +12,7 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/6ac6592a04a839a61 1 file changed, 2 deletions(-) diff --git a/audio/channel_send.cc b/audio/channel_send.cc -index 8080f4a3b8..61e68d19df 100644 +index c8251b4b52..b8aa573a53 100644 --- a/audio/channel_send.cc +++ b/audio/channel_send.cc @@ -474,8 +474,6 @@ ChannelSend::ChannelSend( diff --git a/third_party/libwebrtc/moz-patch-stack/0084.patch b/third_party/libwebrtc/moz-patch-stack/0084.patch index 8a565cc5d3..f4d9cf5e0a 100644 --- a/third_party/libwebrtc/moz-patch-stack/0084.patch +++ b/third_party/libwebrtc/moz-patch-stack/0084.patch @@ -15,10 +15,10 @@ Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/56555ecee7f36ae73 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/audio/channel_send.cc b/audio/channel_send.cc -index 61e68d19df..3c59be52b4 100644 +index b8aa573a53..ae264a4c77 100644 --- a/audio/channel_send.cc +++ b/audio/channel_send.cc -@@ -286,12 +286,16 @@ class RtpPacketSenderProxy : public RtpPacketSender { +@@ -285,12 +285,16 @@ class RtpPacketSenderProxy : public RtpPacketSender { void EnqueuePackets( std::vector> packets) override { MutexLock lock(&mutex_); diff --git a/third_party/libwebrtc/moz-patch-stack/0085.patch b/third_party/libwebrtc/moz-patch-stack/0085.patch index 62d24fdc20..0593b7ae45 100644 --- a/third_party/libwebrtc/moz-patch-stack/0085.patch +++ b/third_party/libwebrtc/moz-patch-stack/0085.patch @@ -52,7 +52,7 @@ index f08fc692dd..02f2e53923 100644 Clock* const clock_; bool short_circuit_ RTC_GUARDED_BY(network_sequence_checker_) = false; diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc -index db0b87c736..c4a021d6c0 100644 +index 4df65659f9..077f522d41 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc @@ -341,7 +341,7 @@ RtpVideoStreamReceiver2::RtpVideoStreamReceiver2( diff --git a/third_party/libwebrtc/moz-patch-stack/0097.patch b/third_party/libwebrtc/moz-patch-stack/0097.patch index 56c8dca72b..1faafdf8cf 100644 --- a/third_party/libwebrtc/moz-patch-stack/0097.patch +++ b/third_party/libwebrtc/moz-patch-stack/0097.patch @@ -1,2186 +1,35362 @@ -From: Dan Minor -Date: Thu, 24 Sep 2020 18:28:00 +0000 -Subject: Bug 1665166 - Move media/webrtc/trunk/* to third-party/libwebrtc; - r=ng +From: Nico Grunbaum +Date: Fri, 30 Apr 2021 21:51:00 +0000 +Subject: Bug 1654112 - Add grit dep for building webrtc on android; r=mjf -Differential Revision: https://phabricator.services.mozilla.com/D91317 -Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/57e3c54bd7b9a0203e19ff1df272d24bb551ed29 +Differential Revision: https://phabricator.services.mozilla.com/D114027 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/3cce5e6938f0df87bd9ab12a5f556aceb93dfa1d --- - tools/clang/OWNERS | 2 + - tools/clang/plugins/ChromeClassTester.cpp | 294 ++++++++++++ - tools/clang/plugins/ChromeClassTester.h | 84 ++++ - tools/clang/plugins/FindBadConstructs.cpp | 435 ++++++++++++++++++ - tools/clang/plugins/Makefile | 19 + - tools/clang/plugins/OWNERS | 1 + - tools/clang/plugins/README.chromium | 4 + - tools/clang/plugins/tests/base_refcounted.cpp | 72 +++ - tools/clang/plugins/tests/base_refcounted.h | 121 +++++ - tools/clang/plugins/tests/base_refcounted.txt | 23 + - .../clang/plugins/tests/inline_copy_ctor.cpp | 5 + - tools/clang/plugins/tests/inline_copy_ctor.h | 12 + - .../clang/plugins/tests/inline_copy_ctor.txt | 5 + - tools/clang/plugins/tests/inline_ctor.cpp | 25 + - tools/clang/plugins/tests/inline_ctor.h | 21 + - tools/clang/plugins/tests/inline_ctor.txt | 8 + - tools/clang/plugins/tests/missing_ctor.cpp | 23 + - tools/clang/plugins/tests/missing_ctor.h | 19 + - tools/clang/plugins/tests/missing_ctor.txt | 6 + - .../tests/nested_class_inline_ctor.cpp | 5 + - .../plugins/tests/nested_class_inline_ctor.h | 22 + - .../tests/nested_class_inline_ctor.txt | 8 + - .../plugins/tests/overridden_methods.cpp | 38 ++ - .../clang/plugins/tests/overridden_methods.h | 54 +++ - .../plugins/tests/overridden_methods.txt | 20 + - tools/clang/plugins/tests/test.sh | 72 +++ - tools/clang/plugins/tests/virtual_methods.cpp | 36 ++ - tools/clang/plugins/tests/virtual_methods.h | 39 ++ - tools/clang/plugins/tests/virtual_methods.txt | 8 + - tools/clang/scripts/package.sh | 87 ++++ - tools/clang/scripts/plugin_flags.sh | 24 + - tools/clang/scripts/update.py | 34 ++ - tools/clang/scripts/update.sh | 286 ++++++++++++ - 33 files changed, 1912 insertions(+) - create mode 100644 tools/clang/OWNERS - create mode 100644 tools/clang/plugins/ChromeClassTester.cpp - create mode 100644 tools/clang/plugins/ChromeClassTester.h - create mode 100644 tools/clang/plugins/FindBadConstructs.cpp - create mode 100644 tools/clang/plugins/Makefile - create mode 100644 tools/clang/plugins/OWNERS - create mode 100644 tools/clang/plugins/README.chromium - create mode 100644 tools/clang/plugins/tests/base_refcounted.cpp - create mode 100644 tools/clang/plugins/tests/base_refcounted.h - create mode 100644 tools/clang/plugins/tests/base_refcounted.txt - create mode 100644 tools/clang/plugins/tests/inline_copy_ctor.cpp - create mode 100644 tools/clang/plugins/tests/inline_copy_ctor.h - create mode 100644 tools/clang/plugins/tests/inline_copy_ctor.txt - create mode 100644 tools/clang/plugins/tests/inline_ctor.cpp - create mode 100644 tools/clang/plugins/tests/inline_ctor.h - create mode 100644 tools/clang/plugins/tests/inline_ctor.txt - create mode 100644 tools/clang/plugins/tests/missing_ctor.cpp - create mode 100644 tools/clang/plugins/tests/missing_ctor.h - create mode 100644 tools/clang/plugins/tests/missing_ctor.txt - create mode 100644 tools/clang/plugins/tests/nested_class_inline_ctor.cpp - create mode 100644 tools/clang/plugins/tests/nested_class_inline_ctor.h - create mode 100644 tools/clang/plugins/tests/nested_class_inline_ctor.txt - create mode 100644 tools/clang/plugins/tests/overridden_methods.cpp - create mode 100644 tools/clang/plugins/tests/overridden_methods.h - create mode 100644 tools/clang/plugins/tests/overridden_methods.txt - create mode 100755 tools/clang/plugins/tests/test.sh - create mode 100644 tools/clang/plugins/tests/virtual_methods.cpp - create mode 100644 tools/clang/plugins/tests/virtual_methods.h - create mode 100644 tools/clang/plugins/tests/virtual_methods.txt - create mode 100755 tools/clang/scripts/package.sh - create mode 100755 tools/clang/scripts/plugin_flags.sh - create mode 100755 tools/clang/scripts/update.py - create mode 100755 tools/clang/scripts/update.sh + tools/grit/.gitignore | 1 + + tools/grit/BUILD.gn | 48 + + tools/grit/MANIFEST.in | 3 + + tools/grit/OWNERS | 8 + + tools/grit/PRESUBMIT.py | 22 + + tools/grit/README.md | 19 + + tools/grit/grit.py | 31 + + tools/grit/grit/__init__.py | 19 + + tools/grit/grit/clique.py | 491 +++ + tools/grit/grit/clique_unittest.py | 265 ++ + tools/grit/grit/constants.py | 23 + + tools/grit/grit/exception.py | 139 + + tools/grit/grit/extern/BogoFP.py | 22 + + tools/grit/grit/extern/FP.py | 72 + + tools/grit/grit/extern/__init__.py | 0 + tools/grit/grit/extern/tclib.py | 503 +++ + tools/grit/grit/format/__init__.py | 8 + + tools/grit/grit/format/android_xml.py | 212 ++ + .../grit/grit/format/android_xml_unittest.py | 149 + + tools/grit/grit/format/c_format.py | 95 + + tools/grit/grit/format/c_format_unittest.py | 81 + + .../grit/grit/format/chrome_messages_json.py | 59 + + .../format/chrome_messages_json_unittest.py | 190 + + tools/grit/grit/format/data_pack.py | 321 ++ + tools/grit/grit/format/data_pack_unittest.py | 102 + + .../grit/grit/format/gen_predetermined_ids.py | 144 + + .../format/gen_predetermined_ids_unittest.py | 46 + + tools/grit/grit/format/gzip_string.py | 46 + + .../grit/grit/format/gzip_string_unittest.py | 65 + + tools/grit/grit/format/html_inline.py | 602 ++++ + .../grit/grit/format/html_inline_unittest.py | 927 +++++ + tools/grit/grit/format/minifier.py | 45 + + .../grit/grit/format/policy_templates_json.py | 26 + + .../format/policy_templates_json_unittest.py | 207 ++ + tools/grit/grit/format/rc.py | 474 +++ + tools/grit/grit/format/rc_header.py | 48 + + tools/grit/grit/format/rc_header_unittest.py | 138 + + tools/grit/grit/format/rc_unittest.py | 415 +++ + tools/grit/grit/format/resource_map.py | 159 + + .../grit/grit/format/resource_map_unittest.py | 345 ++ + tools/grit/grit/gather/__init__.py | 8 + + tools/grit/grit/gather/admin_template.py | 62 + + .../grit/gather/admin_template_unittest.py | 115 + + tools/grit/grit/gather/chrome_html.py | 377 ++ + .../grit/grit/gather/chrome_html_unittest.py | 610 ++++ + tools/grit/grit/gather/chrome_scaled_image.py | 157 + + .../gather/chrome_scaled_image_unittest.py | 209 ++ + tools/grit/grit/gather/interface.py | 172 + + tools/grit/grit/gather/json_loader.py | 27 + + tools/grit/grit/gather/policy_json.py | 325 ++ + .../grit/grit/gather/policy_json_unittest.py | 347 ++ + tools/grit/grit/gather/rc.py | 343 ++ + tools/grit/grit/gather/rc_unittest.py | 372 ++ + tools/grit/grit/gather/regexp.py | 82 + + tools/grit/grit/gather/skeleton_gatherer.py | 149 + + tools/grit/grit/gather/tr_html.py | 743 ++++ + tools/grit/grit/gather/tr_html_unittest.py | 524 +++ + tools/grit/grit/gather/txt.py | 38 + + tools/grit/grit/gather/txt_unittest.py | 35 + + tools/grit/grit/grd_reader.py | 238 ++ + tools/grit/grit/grd_reader_unittest.py | 346 ++ + tools/grit/grit/grit-todo.xml | 62 + + tools/grit/grit/grit_runner.py | 334 ++ + tools/grit/grit/grit_runner_unittest.py | 42 + + tools/grit/grit/lazy_re.py | 46 + + tools/grit/grit/lazy_re_unittest.py | 40 + + tools/grit/grit/node/__init__.py | 8 + + tools/grit/grit/node/base.py | 670 ++++ + tools/grit/grit/node/base_unittest.py | 259 ++ + tools/grit/grit/node/brotli_util.py | 29 + + tools/grit/grit/node/custom/__init__.py | 8 + + tools/grit/grit/node/custom/filename.py | 29 + + .../grit/node/custom/filename_unittest.py | 34 + + tools/grit/grit/node/empty.py | 64 + + tools/grit/grit/node/include.py | 170 + + tools/grit/grit/node/include_unittest.py | 134 + + tools/grit/grit/node/mapping.py | 60 + + tools/grit/grit/node/message.py | 362 ++ + tools/grit/grit/node/message_unittest.py | 380 ++ + tools/grit/grit/node/misc.py | 707 ++++ + tools/grit/grit/node/misc_unittest.py | 590 ++++ + tools/grit/grit/node/mock_brotli.py | 10 + + tools/grit/grit/node/node_io.py | 117 + + tools/grit/grit/node/node_io_unittest.py | 182 + + tools/grit/grit/node/structure.py | 375 ++ + tools/grit/grit/node/structure_unittest.py | 178 + + tools/grit/grit/node/variant.py | 41 + + tools/grit/grit/pseudo.py | 129 + + tools/grit/grit/pseudo_rtl.py | 104 + + tools/grit/grit/pseudo_unittest.py | 55 + + tools/grit/grit/shortcuts.py | 93 + + tools/grit/grit/shortcuts_unittest.py | 79 + + tools/grit/grit/tclib.py | 246 ++ + tools/grit/grit/tclib_unittest.py | 180 + + tools/grit/grit/test_suite_all.py | 34 + + tools/grit/grit/testdata/GoogleDesktop.adm | 945 +++++ + tools/grit/grit/testdata/README.txt | 87 + + tools/grit/grit/testdata/about.html | 45 + + tools/grit/grit/testdata/android.xml | 24 + + tools/grit/grit/testdata/bad_browser.html | 16 + + tools/grit/grit/testdata/browser.html | 42 + + tools/grit/grit/testdata/buildinfo.grd | 46 + + tools/grit/grit/testdata/cache_prefix.html | 24 + + .../grit/grit/testdata/cache_prefix_file.html | 25 + + tools/grit/grit/testdata/chat_result.html | 24 + + .../chrome/app/generated_resources.grd | 199 ++ + tools/grit/grit/testdata/chrome_html.html | 6 + + .../grit/testdata/default_100_percent/a.png | Bin 0 -> 159 bytes + .../grit/testdata/default_100_percent/b.png | 1 + + tools/grit/grit/testdata/del_footer.html | 8 + + tools/grit/grit/testdata/del_header.html | 60 + + tools/grit/grit/testdata/deleted.html | 21 + + tools/grit/grit/testdata/depfile.grd | 18 + + tools/grit/grit/testdata/details.html | 10 + + .../grit/testdata/duplicate-name-input.xml | 26 + + tools/grit/grit/testdata/email_result.html | 34 + + tools/grit/grit/testdata/email_thread.html | 10 + + tools/grit/grit/testdata/error.html | 8 + + tools/grit/grit/testdata/explicit_web.html | 11 + + tools/grit/grit/testdata/footer.html | 14 + + .../grit/testdata/generated_resources_fr.xtb | 3079 +++++++++++++++++ + .../grit/testdata/generated_resources_iw.xtb | 4 + + .../grit/testdata/generated_resources_no.xtb | 4 + + tools/grit/grit/testdata/grit_part.grdp | 5 + + tools/grit/grit/testdata/header.html | 39 + + tools/grit/grit/testdata/homepage.html | 37 + + tools/grit/grit/testdata/hover.html | 177 + + tools/grit/grit/testdata/include_test.html | 31 + + tools/grit/grit/testdata/included_sample.html | 1 + + tools/grit/grit/testdata/indexing_speed.html | 58 + + tools/grit/grit/testdata/install_prefs.html | 92 + + tools/grit/grit/testdata/install_prefs2.html | 52 + + .../grit/testdata/klonk-alternate-skeleton.rc | Bin 0 -> 1088 bytes + tools/grit/grit/testdata/klonk.ico | Bin 0 -> 766 bytes + tools/grit/grit/testdata/klonk.rc | Bin 0 -> 9824 bytes + .../grit/grit/testdata/ko_oem_enable_bug.html | 1 + + .../grit/testdata/ko_oem_non_admin_bug.html | 1 + + tools/grit/grit/testdata/mini.html | 36 + + tools/grit/grit/testdata/oem_enable.html | 106 + + tools/grit/grit/testdata/oem_non_admin.html | 39 + + tools/grit/grit/testdata/onebox.html | 21 + + tools/grit/grit/testdata/oneclick.html | 34 + + tools/grit/grit/testdata/password.html | 37 + + tools/grit/grit/testdata/preferences.html | 234 ++ + tools/grit/grit/testdata/preprocess_test.html | 7 + + tools/grit/grit/testdata/privacy.html | 35 + + tools/grit/grit/testdata/quit_apps.html | 49 + + tools/grit/grit/testdata/recrawl.html | 30 + + tools/grit/grit/testdata/resource_ids | 13 + + tools/grit/grit/testdata/script.html | 38 + + tools/grit/grit/testdata/searchbox.html | 22 + + tools/grit/grit/testdata/sidebar_h.html | 82 + + tools/grit/grit/testdata/sidebar_v.html | 267 ++ + tools/grit/grit/testdata/simple-input.xml | 52 + + tools/grit/grit/testdata/simple.html | 3 + + tools/grit/grit/testdata/source.rc | 57 + + .../grit/testdata/special_100_percent/a.png | Bin 0 -> 159 bytes + tools/grit/grit/testdata/status.html | 44 + + .../grit/testdata/structure_variables.html | 4 + + tools/grit/grit/testdata/substitute.grd | 31 + + tools/grit/grit/testdata/substitute.xmb | 10 + + .../grit/grit/testdata/substitute_no_ids.grd | 31 + + tools/grit/grit/testdata/substitute_tmpl.grd | 31 + + tools/grit/grit/testdata/test_css.css | 1 + + tools/grit/grit/testdata/test_html.html | 1 + + tools/grit/grit/testdata/test_js.js | 1 + + tools/grit/grit/testdata/test_svg.svg | 1 + + tools/grit/grit/testdata/test_text.txt | 1 + + tools/grit/grit/testdata/time_related.html | 11 + + tools/grit/grit/testdata/toolbar_about.html | 138 + + .../grit/testdata/tools/grit/resource_ids | 176 + + tools/grit/grit/testdata/transl.rc | 56 + + tools/grit/grit/testdata/versions.html | 7 + + tools/grit/grit/testdata/whitelist.txt | 4 + + .../grit/testdata/whitelist_resources.grd | 54 + + .../grit/grit/testdata/whitelist_strings.grd | 23 + + tools/grit/grit/tool/__init__.py | 8 + + tools/grit/grit/tool/android2grd.py | 484 +++ + tools/grit/grit/tool/android2grd_unittest.py | 181 + + tools/grit/grit/tool/build.py | 556 +++ + tools/grit/grit/tool/build_unittest.py | 341 ++ + tools/grit/grit/tool/buildinfo.py | 78 + + tools/grit/grit/tool/buildinfo_unittest.py | 90 + + tools/grit/grit/tool/count.py | 52 + + tools/grit/grit/tool/diff_structures.py | 119 + + .../grit/tool/diff_structures_unittest.py | 46 + + tools/grit/grit/tool/interface.py | 62 + + tools/grit/grit/tool/menu_from_parts.py | 79 + + tools/grit/grit/tool/newgrd.py | 85 + + tools/grit/grit/tool/newgrd_unittest.py | 51 + + tools/grit/grit/tool/postprocess_interface.py | 29 + + tools/grit/grit/tool/postprocess_unittest.py | 64 + + tools/grit/grit/tool/preprocess_interface.py | 25 + + tools/grit/grit/tool/preprocess_unittest.py | 50 + + tools/grit/grit/tool/rc2grd.py | 418 +++ + tools/grit/grit/tool/rc2grd_unittest.py | 163 + + tools/grit/grit/tool/resize.py | 295 ++ + tools/grit/grit/tool/test.py | 24 + + tools/grit/grit/tool/transl2tc.py | 251 ++ + tools/grit/grit/tool/transl2tc_unittest.py | 133 + + tools/grit/grit/tool/unit.py | 43 + + .../grit/tool/update_resource_ids/__init__.py | 305 ++ + .../grit/tool/update_resource_ids/assigner.py | 286 ++ + .../update_resource_ids/assigner_unittest.py | 154 + + .../grit/tool/update_resource_ids/common.py | 101 + + .../grit/tool/update_resource_ids/parser.py | 231 ++ + .../grit/tool/update_resource_ids/reader.py | 83 + + tools/grit/grit/tool/xmb.py | 295 ++ + tools/grit/grit/tool/xmb_unittest.py | 132 + + tools/grit/grit/util.py | 691 ++++ + tools/grit/grit/util_unittest.py | 118 + + tools/grit/grit/xtb_reader.py | 140 + + tools/grit/grit/xtb_reader_unittest.py | 110 + + tools/grit/grit_info.py | 173 + + tools/grit/grit_rule.gni | 485 +++ + tools/grit/minify_with_uglify.py | 44 + + tools/grit/minimize_css.py | 105 + + tools/grit/minimize_css_unittest.py | 58 + + tools/grit/pak_util.py | 223 ++ + tools/grit/repack.gni | 189 + + tools/grit/setup.py | 46 + + tools/grit/stamp_grit_sources.py | 57 + + tools/grit/third_party/six/LICENSE | 18 + + tools/grit/third_party/six/README | 16 + + tools/grit/third_party/six/README.chromium | 13 + + tools/grit/third_party/six/__init__.py | 868 +++++ + 226 files changed, 33440 insertions(+) + create mode 100644 tools/grit/.gitignore + create mode 100644 tools/grit/BUILD.gn + create mode 100644 tools/grit/MANIFEST.in + create mode 100644 tools/grit/OWNERS + create mode 100644 tools/grit/PRESUBMIT.py + create mode 100644 tools/grit/README.md + create mode 100644 tools/grit/grit.py + create mode 100644 tools/grit/grit/__init__.py + create mode 100644 tools/grit/grit/clique.py + create mode 100644 tools/grit/grit/clique_unittest.py + create mode 100644 tools/grit/grit/constants.py + create mode 100644 tools/grit/grit/exception.py + create mode 100644 tools/grit/grit/extern/BogoFP.py + create mode 100644 tools/grit/grit/extern/FP.py + create mode 100644 tools/grit/grit/extern/__init__.py + create mode 100644 tools/grit/grit/extern/tclib.py + create mode 100644 tools/grit/grit/format/__init__.py + create mode 100644 tools/grit/grit/format/android_xml.py + create mode 100644 tools/grit/grit/format/android_xml_unittest.py + create mode 100644 tools/grit/grit/format/c_format.py + create mode 100644 tools/grit/grit/format/c_format_unittest.py + create mode 100644 tools/grit/grit/format/chrome_messages_json.py + create mode 100644 tools/grit/grit/format/chrome_messages_json_unittest.py + create mode 100644 tools/grit/grit/format/data_pack.py + create mode 100644 tools/grit/grit/format/data_pack_unittest.py + create mode 100644 tools/grit/grit/format/gen_predetermined_ids.py + create mode 100644 tools/grit/grit/format/gen_predetermined_ids_unittest.py + create mode 100644 tools/grit/grit/format/gzip_string.py + create mode 100644 tools/grit/grit/format/gzip_string_unittest.py + create mode 100644 tools/grit/grit/format/html_inline.py + create mode 100644 tools/grit/grit/format/html_inline_unittest.py + create mode 100644 tools/grit/grit/format/minifier.py + create mode 100644 tools/grit/grit/format/policy_templates_json.py + create mode 100644 tools/grit/grit/format/policy_templates_json_unittest.py + create mode 100644 tools/grit/grit/format/rc.py + create mode 100644 tools/grit/grit/format/rc_header.py + create mode 100644 tools/grit/grit/format/rc_header_unittest.py + create mode 100644 tools/grit/grit/format/rc_unittest.py + create mode 100644 tools/grit/grit/format/resource_map.py + create mode 100644 tools/grit/grit/format/resource_map_unittest.py + create mode 100644 tools/grit/grit/gather/__init__.py + create mode 100644 tools/grit/grit/gather/admin_template.py + create mode 100644 tools/grit/grit/gather/admin_template_unittest.py + create mode 100644 tools/grit/grit/gather/chrome_html.py + create mode 100644 tools/grit/grit/gather/chrome_html_unittest.py + create mode 100644 tools/grit/grit/gather/chrome_scaled_image.py + create mode 100644 tools/grit/grit/gather/chrome_scaled_image_unittest.py + create mode 100644 tools/grit/grit/gather/interface.py + create mode 100644 tools/grit/grit/gather/json_loader.py + create mode 100644 tools/grit/grit/gather/policy_json.py + create mode 100644 tools/grit/grit/gather/policy_json_unittest.py + create mode 100644 tools/grit/grit/gather/rc.py + create mode 100644 tools/grit/grit/gather/rc_unittest.py + create mode 100644 tools/grit/grit/gather/regexp.py + create mode 100644 tools/grit/grit/gather/skeleton_gatherer.py + create mode 100644 tools/grit/grit/gather/tr_html.py + create mode 100644 tools/grit/grit/gather/tr_html_unittest.py + create mode 100644 tools/grit/grit/gather/txt.py + create mode 100644 tools/grit/grit/gather/txt_unittest.py + create mode 100644 tools/grit/grit/grd_reader.py + create mode 100644 tools/grit/grit/grd_reader_unittest.py + create mode 100644 tools/grit/grit/grit-todo.xml + create mode 100644 tools/grit/grit/grit_runner.py + create mode 100644 tools/grit/grit/grit_runner_unittest.py + create mode 100644 tools/grit/grit/lazy_re.py + create mode 100644 tools/grit/grit/lazy_re_unittest.py + create mode 100644 tools/grit/grit/node/__init__.py + create mode 100644 tools/grit/grit/node/base.py + create mode 100644 tools/grit/grit/node/base_unittest.py + create mode 100644 tools/grit/grit/node/brotli_util.py + create mode 100644 tools/grit/grit/node/custom/__init__.py + create mode 100644 tools/grit/grit/node/custom/filename.py + create mode 100644 tools/grit/grit/node/custom/filename_unittest.py + create mode 100644 tools/grit/grit/node/empty.py + create mode 100644 tools/grit/grit/node/include.py + create mode 100644 tools/grit/grit/node/include_unittest.py + create mode 100644 tools/grit/grit/node/mapping.py + create mode 100644 tools/grit/grit/node/message.py + create mode 100644 tools/grit/grit/node/message_unittest.py + create mode 100644 tools/grit/grit/node/misc.py + create mode 100644 tools/grit/grit/node/misc_unittest.py + create mode 100644 tools/grit/grit/node/mock_brotli.py + create mode 100644 tools/grit/grit/node/node_io.py + create mode 100644 tools/grit/grit/node/node_io_unittest.py + create mode 100644 tools/grit/grit/node/structure.py + create mode 100644 tools/grit/grit/node/structure_unittest.py + create mode 100644 tools/grit/grit/node/variant.py + create mode 100644 tools/grit/grit/pseudo.py + create mode 100644 tools/grit/grit/pseudo_rtl.py + create mode 100644 tools/grit/grit/pseudo_unittest.py + create mode 100644 tools/grit/grit/shortcuts.py + create mode 100644 tools/grit/grit/shortcuts_unittest.py + create mode 100644 tools/grit/grit/tclib.py + create mode 100644 tools/grit/grit/tclib_unittest.py + create mode 100644 tools/grit/grit/test_suite_all.py + create mode 100644 tools/grit/grit/testdata/GoogleDesktop.adm + create mode 100644 tools/grit/grit/testdata/README.txt + create mode 100644 tools/grit/grit/testdata/about.html + create mode 100644 tools/grit/grit/testdata/android.xml + create mode 100644 tools/grit/grit/testdata/bad_browser.html + create mode 100644 tools/grit/grit/testdata/browser.html + create mode 100644 tools/grit/grit/testdata/buildinfo.grd + create mode 100644 tools/grit/grit/testdata/cache_prefix.html + create mode 100644 tools/grit/grit/testdata/cache_prefix_file.html + create mode 100644 tools/grit/grit/testdata/chat_result.html + create mode 100644 tools/grit/grit/testdata/chrome/app/generated_resources.grd + create mode 100644 tools/grit/grit/testdata/chrome_html.html + create mode 100644 tools/grit/grit/testdata/default_100_percent/a.png + create mode 100644 tools/grit/grit/testdata/default_100_percent/b.png + create mode 100644 tools/grit/grit/testdata/del_footer.html + create mode 100644 tools/grit/grit/testdata/del_header.html + create mode 100644 tools/grit/grit/testdata/deleted.html + create mode 100644 tools/grit/grit/testdata/depfile.grd + create mode 100644 tools/grit/grit/testdata/details.html + create mode 100644 tools/grit/grit/testdata/duplicate-name-input.xml + create mode 100644 tools/grit/grit/testdata/email_result.html + create mode 100644 tools/grit/grit/testdata/email_thread.html + create mode 100644 tools/grit/grit/testdata/error.html + create mode 100644 tools/grit/grit/testdata/explicit_web.html + create mode 100644 tools/grit/grit/testdata/footer.html + create mode 100644 tools/grit/grit/testdata/generated_resources_fr.xtb + create mode 100644 tools/grit/grit/testdata/generated_resources_iw.xtb + create mode 100644 tools/grit/grit/testdata/generated_resources_no.xtb + create mode 100644 tools/grit/grit/testdata/grit_part.grdp + create mode 100644 tools/grit/grit/testdata/header.html + create mode 100644 tools/grit/grit/testdata/homepage.html + create mode 100644 tools/grit/grit/testdata/hover.html + create mode 100644 tools/grit/grit/testdata/include_test.html + create mode 100644 tools/grit/grit/testdata/included_sample.html + create mode 100644 tools/grit/grit/testdata/indexing_speed.html + create mode 100644 tools/grit/grit/testdata/install_prefs.html + create mode 100644 tools/grit/grit/testdata/install_prefs2.html + create mode 100644 tools/grit/grit/testdata/klonk-alternate-skeleton.rc + create mode 100644 tools/grit/grit/testdata/klonk.ico + create mode 100644 tools/grit/grit/testdata/klonk.rc + create mode 100644 tools/grit/grit/testdata/ko_oem_enable_bug.html + create mode 100644 tools/grit/grit/testdata/ko_oem_non_admin_bug.html + create mode 100644 tools/grit/grit/testdata/mini.html + create mode 100644 tools/grit/grit/testdata/oem_enable.html + create mode 100644 tools/grit/grit/testdata/oem_non_admin.html + create mode 100644 tools/grit/grit/testdata/onebox.html + create mode 100644 tools/grit/grit/testdata/oneclick.html + create mode 100644 tools/grit/grit/testdata/password.html + create mode 100644 tools/grit/grit/testdata/preferences.html + create mode 100644 tools/grit/grit/testdata/preprocess_test.html + create mode 100644 tools/grit/grit/testdata/privacy.html + create mode 100644 tools/grit/grit/testdata/quit_apps.html + create mode 100644 tools/grit/grit/testdata/recrawl.html + create mode 100644 tools/grit/grit/testdata/resource_ids + create mode 100644 tools/grit/grit/testdata/script.html + create mode 100644 tools/grit/grit/testdata/searchbox.html + create mode 100644 tools/grit/grit/testdata/sidebar_h.html + create mode 100644 tools/grit/grit/testdata/sidebar_v.html + create mode 100644 tools/grit/grit/testdata/simple-input.xml + create mode 100644 tools/grit/grit/testdata/simple.html + create mode 100644 tools/grit/grit/testdata/source.rc + create mode 100644 tools/grit/grit/testdata/special_100_percent/a.png + create mode 100644 tools/grit/grit/testdata/status.html + create mode 100644 tools/grit/grit/testdata/structure_variables.html + create mode 100644 tools/grit/grit/testdata/substitute.grd + create mode 100644 tools/grit/grit/testdata/substitute.xmb + create mode 100644 tools/grit/grit/testdata/substitute_no_ids.grd + create mode 100644 tools/grit/grit/testdata/substitute_tmpl.grd + create mode 100644 tools/grit/grit/testdata/test_css.css + create mode 100644 tools/grit/grit/testdata/test_html.html + create mode 100644 tools/grit/grit/testdata/test_js.js + create mode 100644 tools/grit/grit/testdata/test_svg.svg + create mode 100644 tools/grit/grit/testdata/test_text.txt + create mode 100644 tools/grit/grit/testdata/time_related.html + create mode 100644 tools/grit/grit/testdata/toolbar_about.html + create mode 100644 tools/grit/grit/testdata/tools/grit/resource_ids + create mode 100644 tools/grit/grit/testdata/transl.rc + create mode 100644 tools/grit/grit/testdata/versions.html + create mode 100644 tools/grit/grit/testdata/whitelist.txt + create mode 100644 tools/grit/grit/testdata/whitelist_resources.grd + create mode 100644 tools/grit/grit/testdata/whitelist_strings.grd + create mode 100644 tools/grit/grit/tool/__init__.py + create mode 100644 tools/grit/grit/tool/android2grd.py + create mode 100644 tools/grit/grit/tool/android2grd_unittest.py + create mode 100644 tools/grit/grit/tool/build.py + create mode 100644 tools/grit/grit/tool/build_unittest.py + create mode 100644 tools/grit/grit/tool/buildinfo.py + create mode 100644 tools/grit/grit/tool/buildinfo_unittest.py + create mode 100644 tools/grit/grit/tool/count.py + create mode 100644 tools/grit/grit/tool/diff_structures.py + create mode 100644 tools/grit/grit/tool/diff_structures_unittest.py + create mode 100644 tools/grit/grit/tool/interface.py + create mode 100644 tools/grit/grit/tool/menu_from_parts.py + create mode 100644 tools/grit/grit/tool/newgrd.py + create mode 100644 tools/grit/grit/tool/newgrd_unittest.py + create mode 100644 tools/grit/grit/tool/postprocess_interface.py + create mode 100644 tools/grit/grit/tool/postprocess_unittest.py + create mode 100644 tools/grit/grit/tool/preprocess_interface.py + create mode 100644 tools/grit/grit/tool/preprocess_unittest.py + create mode 100644 tools/grit/grit/tool/rc2grd.py + create mode 100644 tools/grit/grit/tool/rc2grd_unittest.py + create mode 100644 tools/grit/grit/tool/resize.py + create mode 100644 tools/grit/grit/tool/test.py + create mode 100644 tools/grit/grit/tool/transl2tc.py + create mode 100644 tools/grit/grit/tool/transl2tc_unittest.py + create mode 100644 tools/grit/grit/tool/unit.py + create mode 100644 tools/grit/grit/tool/update_resource_ids/__init__.py + create mode 100644 tools/grit/grit/tool/update_resource_ids/assigner.py + create mode 100644 tools/grit/grit/tool/update_resource_ids/assigner_unittest.py + create mode 100644 tools/grit/grit/tool/update_resource_ids/common.py + create mode 100644 tools/grit/grit/tool/update_resource_ids/parser.py + create mode 100644 tools/grit/grit/tool/update_resource_ids/reader.py + create mode 100644 tools/grit/grit/tool/xmb.py + create mode 100644 tools/grit/grit/tool/xmb_unittest.py + create mode 100644 tools/grit/grit/util.py + create mode 100644 tools/grit/grit/util_unittest.py + create mode 100644 tools/grit/grit/xtb_reader.py + create mode 100644 tools/grit/grit/xtb_reader_unittest.py + create mode 100644 tools/grit/grit_info.py + create mode 100644 tools/grit/grit_rule.gni + create mode 100644 tools/grit/minify_with_uglify.py + create mode 100644 tools/grit/minimize_css.py + create mode 100644 tools/grit/minimize_css_unittest.py + create mode 100644 tools/grit/pak_util.py + create mode 100644 tools/grit/repack.gni + create mode 100644 tools/grit/setup.py + create mode 100644 tools/grit/stamp_grit_sources.py + create mode 100644 tools/grit/third_party/six/LICENSE + create mode 100644 tools/grit/third_party/six/README + create mode 100644 tools/grit/third_party/six/README.chromium + create mode 100644 tools/grit/third_party/six/__init__.py -diff --git a/tools/clang/OWNERS b/tools/clang/OWNERS +diff --git a/tools/grit/.gitignore b/tools/grit/.gitignore new file mode 100644 -index 0000000000..d86ef9424a +index 0000000000..0d20b6487c --- /dev/null -+++ b/tools/clang/OWNERS -@@ -0,0 +1,2 @@ -+hans@chromium.org -+thakis@chromium.org -diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp ++++ b/tools/grit/.gitignore +@@ -0,0 +1 @@ ++*.pyc +diff --git a/tools/grit/BUILD.gn b/tools/grit/BUILD.gn new file mode 100644 -index 0000000000..055866c5c5 +index 0000000000..1cd3c75b55 --- /dev/null -+++ b/tools/clang/plugins/ChromeClassTester.cpp -@@ -0,0 +1,294 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+// A general interface for filtering and only acting on classes in Chromium C++ -+// code. -+ -+#include "ChromeClassTester.h" ++++ b/tools/grit/BUILD.gn +@@ -0,0 +1,48 @@ ++# Copyright 2014 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+#include ++# This target creates a stamp file that depends on all the sources in the grit ++# directory. By depending on this, a target can force itself to be rebuilt if ++# grit itself changes. + -+#include "clang/AST/AST.h" -+#include "clang/Basic/FileManager.h" -+#include "clang/Basic/SourceManager.h" ++import("//build/config/sanitizers/sanitizers.gni") + -+using namespace clang; ++action("grit_sources") { ++ depfile = "$target_out_dir/grit_sources.d" ++ script = "stamp_grit_sources.py" + -+namespace { ++ inputs = [ "grit.py" ] + -+bool starts_with(const std::string& one, const std::string& two) { -+ return one.compare(0, two.size(), two) == 0; -+} ++ # Note that we can't call this "grit_sources.stamp" because that file is ++ # implicitly created by GN for script actions. ++ outputs = [ "$target_out_dir/grit_sources.script.stamp" ] + -+std::string lstrip(const std::string& one, const std::string& two) { -+ if (starts_with(one, two)) -+ return one.substr(two.size()); -+ return one; ++ args = [ ++ rebase_path("//tools/grit", root_build_dir), ++ rebase_path(outputs[0], root_build_dir), ++ rebase_path(depfile, root_build_dir), ++ ] +} + -+bool ends_with(const std::string& one, const std::string& two) { -+ if (two.size() > one.size()) -+ return false; ++group("grit_python_unittests") { ++ testonly = true + -+ return one.compare(one.size() - two.size(), two.size(), two) == 0; ++ data = [ ++ "//testing/scripts/common.py", ++ "//testing/scripts/run_isolated_script_test.py", ++ "//testing/xvfb.py", ++ "//tools/grit/", ++ "//third_party/catapult/third_party/typ/", ++ ] +} + -+} // namespace ++# See https://crbug.com/983200 ++if (is_mac && is_asan) { ++ create_bundle("brotli_mac_asan_workaround") { ++ bundle_root_dir = "$target_out_dir/$target_name" ++ bundle_executable_dir = bundle_root_dir + -+ChromeClassTester::ChromeClassTester(CompilerInstance& instance) -+ : instance_(instance), -+ diagnostic_(instance.getDiagnostics()) { -+ BuildBannedLists(); ++ public_deps = [ "//third_party/brotli:brotli($host_toolchain)" ] ++ } +} +diff --git a/tools/grit/MANIFEST.in b/tools/grit/MANIFEST.in +new file mode 100644 +index 0000000000..1cbff42400 +--- /dev/null ++++ b/tools/grit/MANIFEST.in +@@ -0,0 +1,3 @@ ++exclude grit/test_suite_all.py ++exclude grit/tool/test.py ++global-exclude *_unittest.py +diff --git a/tools/grit/OWNERS b/tools/grit/OWNERS +new file mode 100644 +index 0000000000..6a8f447b82 +--- /dev/null ++++ b/tools/grit/OWNERS +@@ -0,0 +1,8 @@ ++agrieve@chromium.org ++flackr@chromium.org ++thakis@chromium.org ++thestig@chromium.org + -+ChromeClassTester::~ChromeClassTester() {} ++# Admin policy related grit tools. ++per-file *policy*=file://components/policy/tools/OWNERS ++per-file *admin_template*=file://components/policy/tools/OWNERS +diff --git a/tools/grit/PRESUBMIT.py b/tools/grit/PRESUBMIT.py +new file mode 100644 +index 0000000000..03b7188551 +--- /dev/null ++++ b/tools/grit/PRESUBMIT.py +@@ -0,0 +1,22 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) { -+ pending_class_decls_.push_back(tag); -+} ++"""grit unittests presubmit script. + -+bool ChromeClassTester::HandleTopLevelDecl(DeclGroupRef group_ref) { -+ for (size_t i = 0; i < pending_class_decls_.size(); ++i) -+ CheckTag(pending_class_decls_[i]); -+ pending_class_decls_.clear(); ++See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for ++details on the presubmit API built into gcl. ++""" + -+ return true; // true means continue parsing. -+} + -+void ChromeClassTester::CheckTag(TagDecl* tag) { -+ // We handle class types here where we have semantic information. We can only -+ // check structs/classes/enums here, but we get a bunch of nice semantic -+ // information instead of just parsing information. ++def RunUnittests(input_api, output_api): ++ return input_api.canned_checks.RunUnitTests(input_api, output_api, ++ [input_api.os_path.join('grit', 'test_suite_all.py')]) + -+ if (CXXRecordDecl* record = dyn_cast(tag)) { -+ // If this is a POD or a class template or a type dependent on a -+ // templated class, assume there's no ctor/dtor/virtual method -+ // optimization that we can do. -+ if (record->isPOD() || -+ record->getDescribedClassTemplate() || -+ record->getTemplateSpecializationKind() || -+ record->isDependentType()) -+ return; + -+ if (InBannedNamespace(record)) -+ return; ++def CheckChangeOnUpload(input_api, output_api): ++ return RunUnittests(input_api, output_api) + -+ SourceLocation record_location = record->getInnerLocStart(); -+ if (InBannedDirectory(record_location)) -+ return; + -+ // We sadly need to maintain a blacklist of types that violate these -+ // rules, but do so for good reason or due to limitations of this -+ // checker (i.e., we don't handle extern templates very well). -+ std::string base_name = record->getNameAsString(); -+ if (IsIgnoredType(base_name)) -+ return; ++def CheckChangeOnCommit(input_api, output_api): ++ return RunUnittests(input_api, output_api) +diff --git a/tools/grit/README.md b/tools/grit/README.md +new file mode 100644 +index 0000000000..b5c3f4b51b +--- /dev/null ++++ b/tools/grit/README.md +@@ -0,0 +1,19 @@ ++# GRIT (Google Resource and Internationalization Tool) + -+ // We ignore all classes that end with "Matcher" because they're probably -+ // GMock artifacts. -+ if (ends_with(base_name, "Matcher")) -+ return; ++This is a tool for projects to manage resources and simplify the localization ++workflow. + -+ CheckChromeClass(record_location, record); -+ } -+} ++See the user guide for more details on using this project: ++https://dev.chromium.org/developers/tools-we-use-in-chromium/grit/grit-users-guide + -+void ChromeClassTester::emitWarning(SourceLocation loc, -+ const char* raw_error) { -+ FullSourceLoc full(loc, instance().getSourceManager()); -+ std::string err; -+ err = "[chromium-style] "; -+ err += raw_error; -+ DiagnosticsEngine::Level level = -+ diagnostic().getWarningsAsErrors() ? -+ DiagnosticsEngine::Error : -+ DiagnosticsEngine::Warning; -+ unsigned id = diagnostic().getCustomDiagID(level, err); -+ DiagnosticBuilder builder = diagnostic().Report(full, id); -+} -+ -+bool ChromeClassTester::InBannedNamespace(const Decl* record) { -+ std::string n = GetNamespace(record); -+ if (!n.empty()) { -+ return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n) -+ != banned_namespaces_.end(); -+ } ++## History + -+ return false; -+} ++This code previously used to live at ++https://code.google.com/p/grit-i18n/source/checkout which still contains the ++project's history. https://chromium.googlesource.com/external/grit-i18n/ is ++a git mirror of the SVN repository that's identical except for the last two ++commits. The project is now developed in the Chromium project directly. + -+std::string ChromeClassTester::GetNamespace(const Decl* record) { -+ return GetNamespaceImpl(record->getDeclContext(), ""); -+} ++There is a read-only mirror of just this directory at ++https://chromium.googlesource.com/chromium/src/tools/grit/ if you don't want to ++check out all of Chromium. +diff --git a/tools/grit/grit.py b/tools/grit/grit.py +new file mode 100644 +index 0000000000..abd1ab6449 +--- /dev/null ++++ b/tools/grit/grit.py +@@ -0,0 +1,31 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+bool ChromeClassTester::InImplementationFile(SourceLocation record_location) { -+ std::string filename; -+ if (!GetFilename(record_location, &filename)) -+ return false; ++'''Bootstrapping for GRIT. ++''' + -+ if (ends_with(filename, ".cc") || ends_with(filename, ".cpp") || -+ ends_with(filename, ".mm")) { -+ return true; -+ } ++from __future__ import print_function + -+ return false; -+} ++import os ++import sys + -+void ChromeClassTester::BuildBannedLists() { -+ banned_namespaces_.push_back("std"); -+ banned_namespaces_.push_back("__gnu_cxx"); -+ banned_namespaces_.push_back("WebKit"); -+ -+ banned_directories_.push_back("third_party/"); -+ banned_directories_.push_back("native_client/"); -+ banned_directories_.push_back("breakpad/"); -+ banned_directories_.push_back("courgette/"); -+ banned_directories_.push_back("pdf/"); -+ banned_directories_.push_back("ppapi/"); -+ banned_directories_.push_back("usr/"); -+ banned_directories_.push_back("testing/"); -+ banned_directories_.push_back("googleurl/"); -+ banned_directories_.push_back("v8/"); -+ banned_directories_.push_back("dart/"); -+ banned_directories_.push_back("sdch/"); -+ banned_directories_.push_back("icu4c/"); -+ banned_directories_.push_back("frameworks/"); -+ -+ // Don't check autogenerated headers. -+ // Make puts them below $(builddir_name)/.../gen and geni. -+ // Ninja puts them below OUTPUT_DIR/.../gen -+ // Xcode has a fixed output directory for everything. -+ banned_directories_.push_back("gen/"); -+ banned_directories_.push_back("geni/"); -+ banned_directories_.push_back("xcodebuild/"); -+ -+ // You are standing in a mazy of twisty dependencies, all resolved by -+ // putting everything in the header. -+ banned_directories_.push_back("automation/"); -+ -+ // Don't check system headers. -+ banned_directories_.push_back("/Developer/"); -+ -+ // Used in really low level threading code that probably shouldn't be out of -+ // lined. -+ ignored_record_names_.insert("ThreadLocalBoolean"); -+ -+ // A complicated pickle derived struct that is all packed integers. -+ ignored_record_names_.insert("Header"); -+ -+ // Part of the GPU system that uses multiple included header -+ // weirdness. Never getting this right. -+ ignored_record_names_.insert("Validators"); -+ -+ // Has a UNIT_TEST only constructor. Isn't *terribly* complex... -+ ignored_record_names_.insert("AutocompleteController"); -+ ignored_record_names_.insert("HistoryURLProvider"); -+ -+ // Because of chrome frame -+ ignored_record_names_.insert("ReliabilityTestSuite"); -+ -+ // Used over in the net unittests. A large enough bundle of integers with 1 -+ // non-pod class member. Probably harmless. -+ ignored_record_names_.insert("MockTransaction"); -+ -+ // Used heavily in ui_unittests and once in views_unittests. Fixing this -+ // isn't worth the overhead of an additional library. -+ ignored_record_names_.insert("TestAnimationDelegate"); -+ -+ // Part of our public interface that nacl and friends use. (Arguably, this -+ // should mean that this is a higher priority but fixing this looks hard.) -+ ignored_record_names_.insert("PluginVersionInfo"); -+} -+ -+std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context, -+ const std::string& candidate) { -+ switch (context->getDeclKind()) { -+ case Decl::TranslationUnit: { -+ return candidate; -+ } -+ case Decl::Namespace: { -+ const NamespaceDecl* decl = dyn_cast(context); -+ std::string name_str; -+ llvm::raw_string_ostream OS(name_str); -+ if (decl->isAnonymousNamespace()) -+ OS << ""; -+ else -+ OS << *decl; -+ return GetNamespaceImpl(context->getParent(), -+ OS.str()); -+ } -+ default: { -+ return GetNamespaceImpl(context->getParent(), candidate); -+ } -+ } -+} ++import grit.grit_runner + -+bool ChromeClassTester::InBannedDirectory(SourceLocation loc) { -+ std::string filename; -+ if (!GetFilename(loc, &filename)) { -+ // If the filename cannot be determined, simply treat this as a banned -+ // location, instead of going through the full lookup process. -+ return true; -+ } ++sys.path.append( ++ os.path.join( ++ os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ++ 'diagnosis')) ++try: ++ import crbug_1001171 ++except ImportError: ++ crbug_1001171 = None + -+ // We need to special case scratch space; which is where clang does its -+ // macro expansion. We explicitly want to allow people to do otherwise bad -+ // things through macros that were defined due to third party libraries. -+ if (filename == "") -+ return true; + -+ // Don't complain about autogenerated protobuf files. -+ if (ends_with(filename, ".pb.h")) { -+ return true; -+ } ++if __name__ == '__main__': ++ if crbug_1001171: ++ with crbug_1001171.DumpStateOnLookupError(): ++ sys.exit(grit.grit_runner.Main(sys.argv[1:])) ++ else: ++ sys.exit(grit.grit_runner.Main(sys.argv[1:])) +diff --git a/tools/grit/grit/__init__.py b/tools/grit/grit/__init__.py +new file mode 100644 +index 0000000000..91ac9ee896 +--- /dev/null ++++ b/tools/grit/grit/__init__.py +@@ -0,0 +1,19 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+ // We need to munge the paths so that they are relative to the repository -+ // srcroot. We first resolve the symlinktastic relative path and then -+ // remove our known srcroot from it if needed. -+ char resolvedPath[MAXPATHLEN]; -+ if (realpath(filename.c_str(), resolvedPath)) { -+ filename = resolvedPath; -+ } ++'''Package 'grit' ++''' + -+ // On linux, chrome is often checked out to /usr/local/google. Due to the -+ // "usr" rule in banned_directories_, all diagnostics would be suppressed -+ // in that case. As a workaround, strip that prefix. -+ filename = lstrip(filename, "/usr/local/google"); -+ -+ for (std::vector::const_iterator it = -+ banned_directories_.begin(); -+ it != banned_directories_.end(); ++it) { -+ // If we can find any of the banned path components in this path, then -+ // this file is rejected. -+ size_t index = filename.find(*it); -+ if (index != std::string::npos) { -+ bool matches_full_dir_name = index == 0 || filename[index - 1] == '/'; -+ if ((*it)[0] == '/') -+ matches_full_dir_name = true; -+ if (matches_full_dir_name) -+ return true; -+ } -+ } ++from __future__ import print_function + -+ return false; -+} ++import os ++import sys + -+bool ChromeClassTester::IsIgnoredType(const std::string& base_name) { -+ return ignored_record_names_.find(base_name) != ignored_record_names_.end(); -+} + -+bool ChromeClassTester::GetFilename(SourceLocation loc, -+ std::string* filename) { -+ const SourceManager& source_manager = instance_.getSourceManager(); -+ SourceLocation spelling_location = source_manager.getSpellingLoc(loc); -+ PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location); -+ if (ploc.isInvalid()) { -+ // If we're in an invalid location, we're looking at things that aren't -+ // actually stated in the source. -+ return false; -+ } ++_CUR_DIR = os.path.abspath(os.path.dirname(__file__)) ++_GRIT_DIR = os.path.dirname(_CUR_DIR) ++_THIRD_PARTY_DIR = os.path.join(_GRIT_DIR, 'third_party') + -+ *filename = ploc.getFilename(); -+ return true; -+} -diff --git a/tools/clang/plugins/ChromeClassTester.h b/tools/clang/plugins/ChromeClassTester.h ++if _THIRD_PARTY_DIR not in sys.path: ++ sys.path.insert(0, _THIRD_PARTY_DIR) +diff --git a/tools/grit/grit/clique.py b/tools/grit/grit/clique.py new file mode 100644 -index 0000000000..588ae9cae5 +index 0000000000..e7be3ec164 --- /dev/null -+++ b/tools/clang/plugins/ChromeClassTester.h -@@ -0,0 +1,84 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#ifndef TOOLS_CLANG_PLUGINS_CHROMECLASSTESTER_H_ -+#define TOOLS_CLANG_PLUGINS_CHROMECLASSTESTER_H_ -+ -+#include -+#include -+ -+#include "clang/AST/ASTConsumer.h" -+#include "clang/AST/TypeLoc.h" -+#include "clang/Frontend/CompilerInstance.h" -+ -+// A class on top of ASTConsumer that forwards classes defined in Chromium -+// headers to subclasses which implement CheckChromeClass(). -+class ChromeClassTester : public clang::ASTConsumer { -+ public: -+ explicit ChromeClassTester(clang::CompilerInstance& instance); -+ virtual ~ChromeClassTester(); -+ -+ // clang::ASTConsumer: -+ virtual void HandleTagDeclDefinition(clang::TagDecl* tag); -+ virtual bool HandleTopLevelDecl(clang::DeclGroupRef group_ref); ++++ b/tools/grit/grit/clique.py +@@ -0,0 +1,491 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+ protected: -+ clang::CompilerInstance& instance() { return instance_; } -+ clang::DiagnosticsEngine& diagnostic() { return diagnostic_; } ++'''Collections of messages and their translations, called cliques. Also ++collections of cliques (uber-cliques). ++''' ++ ++from __future__ import print_function ++ ++import re ++ ++import six ++ ++from grit import constants ++from grit import exception ++from grit import lazy_re ++from grit import pseudo ++from grit import pseudo_rtl ++from grit import tclib ++ ++ ++class UberClique(object): ++ '''A factory (NOT a singleton factory) for making cliques. It has several ++ methods for working with the cliques created using the factory. ++ ''' ++ ++ def __init__(self): ++ # A map from message ID to list of cliques whose source messages have ++ # that ID. This will contain all cliques created using this factory. ++ # Different messages can have the same ID because they have the ++ # same translateable portion and placeholder names, but occur in different ++ # places in the resource tree. ++ # ++ # Each list of cliques is kept sorted by description, to achieve ++ # stable results from the BestClique method, see below. ++ self.cliques_ = {} ++ ++ # A map of clique IDs to list of languages to indicate translations where we ++ # fell back to English. ++ self.fallback_translations_ = {} ++ ++ # A map of clique IDs to list of languages to indicate missing translations. ++ self.missing_translations_ = {} ++ ++ def _AddMissingTranslation(self, lang, clique, is_error): ++ tl = self.fallback_translations_ ++ if is_error: ++ tl = self.missing_translations_ ++ id = clique.GetId() ++ if id not in tl: ++ tl[id] = {} ++ if lang not in tl[id]: ++ tl[id][lang] = 1 ++ ++ def HasMissingTranslations(self): ++ return len(self.missing_translations_) > 0 ++ ++ def MissingTranslationsReport(self): ++ '''Returns a string suitable for printing to report missing ++ and fallback translations to the user. ++ ''' ++ def ReportTranslation(clique, langs): ++ text = clique.GetMessage().GetPresentableContent() ++ # The text 'error' (usually 'Error:' but we are conservative) ++ # can trigger some build environments (Visual Studio, we're ++ # looking at you) to consider invocation of grit to have failed, ++ # so we make sure never to output that word. ++ extract = re.sub(r'(?i)error', 'REDACTED', text[0:40])[0:40] ++ ellipsis = '' ++ if len(text) > 40: ++ ellipsis = '...' ++ langs_extract = langs[0:6] ++ describe_langs = ','.join(langs_extract) ++ if len(langs) > 6: ++ describe_langs += " and %d more" % (len(langs) - 6) ++ return " %s \"%s%s\" %s" % (clique.GetId(), extract, ellipsis, ++ describe_langs) ++ lines = [] ++ if len(self.fallback_translations_): ++ lines.append( ++ "WARNING: Fell back to English for the following translations:") ++ for (id, langs) in self.fallback_translations_.items(): ++ lines.append( ++ ReportTranslation(self.cliques_[id][0], list(langs.keys()))) ++ if len(self.missing_translations_): ++ lines.append("ERROR: The following translations are MISSING:") ++ for (id, langs) in self.missing_translations_.items(): ++ lines.append( ++ ReportTranslation(self.cliques_[id][0], list(langs.keys()))) ++ return '\n'.join(lines) ++ ++ def MakeClique(self, message, translateable=True): ++ '''Create a new clique initialized with a message. ++ ++ Args: ++ message: tclib.Message() ++ translateable: True | False ++ ''' ++ clique = MessageClique(self, message, translateable) ++ ++ # Enable others to find this clique by its message ID ++ if message.GetId() in self.cliques_: ++ presentable_text = clique.GetMessage().GetPresentableContent() ++ if not message.HasAssignedId(): ++ for c in self.cliques_[message.GetId()]: ++ assert c.GetMessage().GetPresentableContent() == presentable_text ++ self.cliques_[message.GetId()].append(clique) ++ # We need to keep each list of cliques sorted by description, to ++ # achieve stable results from the BestClique method, see below. ++ self.cliques_[message.GetId()].sort( ++ key=lambda c:c.GetMessage().GetDescription()) ++ else: ++ self.cliques_[message.GetId()] = [clique] ++ ++ return clique ++ ++ def FindCliqueAndAddTranslation(self, translation, language): ++ '''Adds the specified translation to the clique with the source message ++ it is a translation of. ++ ++ Args: ++ translation: tclib.Translation() ++ language: 'en' | 'fr' ... ++ ++ Return: ++ True if the source message was found, otherwise false. ++ ''' ++ if translation.GetId() in self.cliques_: ++ for clique in self.cliques_[translation.GetId()]: ++ clique.AddTranslation(translation, language) ++ return True ++ else: ++ return False ++ ++ def BestClique(self, id): ++ '''Returns the "best" clique from a list of cliques. All the cliques ++ must have the same ID. The "best" clique is chosen in the following ++ order of preference: ++ - The first clique that has a non-ID-based description. ++ - If no such clique found, the first clique with an ID-based description. ++ - Otherwise the first clique. ++ ++ This method is stable in terms of always returning a clique with ++ an identical description (on different runs of GRIT on the same ++ data) because self.cliques_ is sorted by description. ++ ''' ++ clique_list = self.cliques_[id] ++ clique_with_id = None ++ clique_default = None ++ for clique in clique_list: ++ if not clique_default: ++ clique_default = clique ++ ++ description = clique.GetMessage().GetDescription() ++ if description and len(description) > 0: ++ if not description.startswith('ID:'): ++ # this is the preferred case so we exit right away ++ return clique ++ elif not clique_with_id: ++ clique_with_id = clique ++ if clique_with_id: ++ return clique_with_id ++ else: ++ return clique_default ++ ++ def BestCliquePerId(self): ++ '''Iterates over the list of all cliques and returns the best clique for ++ each ID. This will be the first clique with a source message that has a ++ non-empty description, or an arbitrary clique if none of them has a ++ description. ++ ''' ++ for id in self.cliques_: ++ yield self.BestClique(id) ++ ++ def BestCliqueByOriginalText(self, text, meaning): ++ '''Finds the "best" (as in BestClique()) clique that has original text ++ 'text' and meaning 'meaning'. Returns None if there is no such clique. ++ ''' ++ # If needed, this can be optimized by maintaining a map of ++ # fingerprints of original text+meaning to cliques. ++ for c in self.BestCliquePerId(): ++ msg = c.GetMessage() ++ if msg.GetRealContent() == text and msg.GetMeaning() == meaning: ++ return msg ++ return None ++ ++ def AllMessageIds(self): ++ '''Returns a list of all defined message IDs. ++ ''' ++ return list(self.cliques_.keys()) ++ ++ def AllCliques(self): ++ '''Iterates over all cliques. Note that this can return multiple cliques ++ with the same ID. ++ ''' ++ for cliques in self.cliques_.values(): ++ for c in cliques: ++ yield c ++ ++ def GenerateXtbParserCallback(self, lang, debug=False): ++ '''Creates a callback function as required by grit.xtb_reader.Parse(). ++ This callback will create Translation objects for each message from ++ the XTB that exists in this uberclique, and add them as translations for ++ the relevant cliques. The callback will add translations to the language ++ specified by 'lang' ++ ++ Args: ++ lang: 'fr' ++ debug: True | False ++ ''' ++ def Callback(id, structure): ++ if id not in self.cliques_: ++ if debug: ++ print("Ignoring translation #%s" % id) ++ return ++ ++ if debug: ++ print("Adding translation #%s" % id) ++ ++ # We fetch placeholder information from the original message (the XTB file ++ # only contains placeholder names). ++ original_msg = self.BestClique(id).GetMessage() ++ ++ translation = tclib.Translation(id=id) ++ for is_ph,text in structure: ++ if not is_ph: ++ translation.AppendText(text) ++ else: ++ found_placeholder = False ++ for ph in original_msg.GetPlaceholders(): ++ if ph.GetPresentation() == text: ++ translation.AppendPlaceholder(tclib.Placeholder( ++ ph.GetPresentation(), ph.GetOriginal(), ph.GetExample())) ++ found_placeholder = True ++ break ++ if not found_placeholder: ++ raise exception.MismatchingPlaceholders( ++ 'Translation for message ID %s had , no match\n' ++ 'in original message' % (id, text)) ++ self.FindCliqueAndAddTranslation(translation, lang) ++ return Callback ++ ++ ++class CustomType(object): ++ '''A base class you should implement if you wish to specify a custom type ++ for a message clique (i.e. custom validation and optional modification of ++ translations).''' ++ ++ def Validate(self, message): ++ '''Returns true if the message (a tclib.Message object) is valid, ++ otherwise false. ++ ''' ++ raise NotImplementedError() ++ ++ def ValidateAndModify(self, lang, translation): ++ '''Returns true if the translation (a tclib.Translation object) is valid, ++ otherwise false. The language is also passed in. This method may modify ++ the translation that is passed in, if it so wishes. ++ ''' ++ raise NotImplementedError() ++ ++ def ModifyTextPart(self, lang, text): ++ '''If you call ModifyEachTextPart, it will turn around and call this method ++ for each text part of the translation. You should return the modified ++ version of the text, or just the original text to not change anything. ++ ''' ++ raise NotImplementedError() ++ ++ def ModifyEachTextPart(self, lang, translation): ++ '''Call this to easily modify one or more of the textual parts of a ++ translation. It will call ModifyTextPart for each part of the ++ translation. ++ ''' ++ contents = translation.GetContent() ++ for ix in range(len(contents)): ++ if (isinstance(contents[ix], six.string_types)): ++ contents[ix] = self.ModifyTextPart(lang, contents[ix]) ++ ++ ++class OneOffCustomType(CustomType): ++ '''A very simple custom type that performs the validation expressed by ++ the input expression on all languages including the source language. ++ The expression can access the variables 'lang', 'msg' and 'text()' where ++ 'lang' is the language of 'msg', 'msg' is the message or translation being ++ validated and 'text()' returns the real contents of 'msg' (for shorthand). ++ ''' ++ def __init__(self, expression): ++ self.expr = expression ++ def Validate(self, message): ++ return self.ValidateAndModify(MessageClique.source_language, message) ++ def ValidateAndModify(self, lang, msg): ++ def text(): ++ return msg.GetRealContent() ++ return eval(self.expr, {}, ++ {'lang' : lang, ++ 'text' : text, ++ 'msg' : msg, ++ }) ++ ++ ++class MessageClique(object): ++ '''A message along with all of its translations. Also code to bring ++ translations together with their original message.''' ++ ++ # change this to the language code of Messages you add to cliques_. ++ # TODO(joi) Actually change this based on the node's source language ++ source_language = 'en' ++ ++ # A constant translation we use when asked for a translation into the ++ # special language constants.CONSTANT_LANGUAGE. ++ CONSTANT_TRANSLATION = tclib.Translation(text='TTTTTT') ++ ++ # A pattern to match messages that are empty or whitespace only. ++ WHITESPACE_MESSAGE = lazy_re.compile(r'^\s*$') ++ ++ def __init__(self, uber_clique, message, translateable=True, ++ custom_type=None): ++ '''Create a new clique initialized with just a message. ++ ++ Note that messages with a body comprised only of whitespace will implicitly ++ be marked non-translatable. ++ ++ Args: ++ uber_clique: Our uber-clique (collection of cliques) ++ message: tclib.Message() ++ translateable: True | False ++ custom_type: instance of clique.CustomType interface ++ ''' ++ # Our parent ++ self.uber_clique = uber_clique ++ # If not translateable, we only store the original message. ++ self.translateable = translateable ++ ++ # We implicitly mark messages that have a whitespace-only body as ++ # non-translateable. ++ if MessageClique.WHITESPACE_MESSAGE.match(message.GetRealContent()): ++ self.translateable = False ++ ++ # A mapping of language identifiers to tclib.BaseMessage and its ++ # subclasses (i.e. tclib.Message and tclib.Translation). ++ self.clique = { MessageClique.source_language : message } ++ # A list of the "shortcut groups" this clique is ++ # part of. Within any given shortcut group, no shortcut key (e.g. &J) ++ # must appear more than once in each language for all cliques that ++ # belong to the group. ++ self.shortcut_groups = [] ++ # An instance of the CustomType interface, or None. If this is set, it will ++ # be used to validate the original message and translations thereof, and ++ # will also get a chance to modify translations of the message. ++ self.SetCustomType(custom_type) ++ ++ def GetMessage(self): ++ '''Retrieves the tclib.Message that is the source for this clique.''' ++ return self.clique[MessageClique.source_language] ++ ++ def GetId(self): ++ '''Retrieves the message ID of the messages in this clique.''' ++ return self.GetMessage().GetId() ++ ++ def IsTranslateable(self): ++ return self.translateable ++ ++ def AddToShortcutGroup(self, group): ++ self.shortcut_groups.append(group) ++ ++ def SetCustomType(self, custom_type): ++ '''Makes this clique use custom_type for validating messages and ++ translations, and optionally modifying translations. ++ ''' ++ self.custom_type = custom_type ++ if custom_type and not custom_type.Validate(self.GetMessage()): ++ raise exception.InvalidMessage(self.GetMessage().GetRealContent()) ++ ++ def MessageForLanguage(self, lang, pseudo_if_no_match=True, ++ fallback_to_english=False): ++ '''Returns the message/translation for the specified language, providing ++ a pseudotranslation if there is no available translation and a pseudo- ++ translation is requested. ++ ++ The translation of any message whatsoever in the special language ++ 'x_constant' is the message "TTTTTT". ++ ++ Args: ++ lang: 'en' ++ pseudo_if_no_match: True ++ fallback_to_english: False ++ ++ Return: ++ tclib.BaseMessage ++ ''' ++ if not self.translateable: ++ return self.GetMessage() ++ ++ if lang == constants.CONSTANT_LANGUAGE: ++ return self.CONSTANT_TRANSLATION ++ ++ for msglang in self.clique: ++ if lang == msglang: ++ return self.clique[msglang] ++ ++ if lang == constants.FAKE_BIDI: ++ return pseudo_rtl.PseudoRTLMessage(self.GetMessage()) ++ ++ if fallback_to_english: ++ self.uber_clique._AddMissingTranslation(lang, self, is_error=False) ++ return self.GetMessage() ++ ++ # If we're not supposed to generate pseudotranslations, we add an error ++ # report to a list of errors, then fail at a higher level, so that we ++ # get a list of all messages that are missing translations. ++ if not pseudo_if_no_match: ++ self.uber_clique._AddMissingTranslation(lang, self, is_error=True) ++ ++ return pseudo.PseudoMessage(self.GetMessage()) ++ ++ def AllMessagesThatMatch(self, lang_re, include_pseudo = True): ++ '''Returns a map of all messages that match 'lang', including the pseudo ++ translation if requested. ++ ++ Args: ++ lang_re: re.compile(r'fr|en') ++ include_pseudo: True ++ ++ Return: ++ { 'en' : tclib.Message, ++ 'fr' : tclib.Translation, ++ pseudo.PSEUDO_LANG : tclib.Translation } ++ ''' ++ if not self.translateable: ++ return [self.GetMessage()] ++ ++ matches = {} ++ for msglang in self.clique: ++ if lang_re.match(msglang): ++ matches[msglang] = self.clique[msglang] ++ ++ if include_pseudo: ++ matches[pseudo.PSEUDO_LANG] = pseudo.PseudoMessage(self.GetMessage()) ++ ++ return matches ++ ++ def AddTranslation(self, translation, language): ++ '''Add a translation to this clique. The translation must have the same ++ ID as the message that is the source for this clique. ++ ++ If this clique is not translateable, the function just returns. ++ ++ Args: ++ translation: tclib.Translation() ++ language: 'en' ++ ++ Throws: ++ grit.exception.InvalidTranslation if the translation you're trying to add ++ doesn't have the same message ID as the source message of this clique. ++ ''' ++ if not self.translateable: ++ return ++ if translation.GetId() != self.GetId(): ++ raise exception.InvalidTranslation( ++ 'Msg ID %s, transl ID %s' % (self.GetId(), translation.GetId())) ++ ++ assert not language in self.clique ++ ++ # Because two messages can differ in the original content of their ++ # placeholders yet share the same ID (because they are otherwise the ++ # same), the translation we are getting may have different original ++ # content for placeholders than our message, yet it is still the right ++ # translation for our message (because it is for the same ID). We must ++ # therefore fetch the original content of placeholders from our original ++ # English message. ++ # ++ # See grit.clique_unittest.MessageCliqueUnittest.testSemiIdenticalCliques ++ # for a concrete explanation of why this is necessary. ++ ++ original = self.MessageForLanguage(self.source_language, False) ++ if len(original.GetPlaceholders()) != len(translation.GetPlaceholders()): ++ print("ERROR: '%s' translation of message id %s does not match" % ++ (language, translation.GetId())) ++ assert False ++ ++ transl_msg = tclib.Translation(id=self.GetId(), ++ text=translation.GetPresentableContent(), ++ placeholders=original.GetPlaceholders()) ++ ++ if (self.custom_type and ++ not self.custom_type.ValidateAndModify(language, transl_msg)): ++ print("WARNING: %s translation failed validation: %s" % ++ (language, transl_msg.GetId())) ++ ++ self.clique[language] = transl_msg +diff --git a/tools/grit/grit/clique_unittest.py b/tools/grit/grit/clique_unittest.py +new file mode 100644 +index 0000000000..7d2d7318ba +--- /dev/null ++++ b/tools/grit/grit/clique_unittest.py +@@ -0,0 +1,265 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+ // Emits a simple warning; this shouldn't be used if you require printf-style -+ // printing. -+ void emitWarning(clang::SourceLocation loc, const char* error); ++'''Unit tests for grit.clique''' + -+ // Utility method for subclasses to check if this class is in a banned -+ // namespace. -+ bool InBannedNamespace(const clang::Decl* record); ++from __future__ import print_function + -+ // Utility method for subclasses to determine the namespace of the -+ // specified record, if any. Unnamed namespaces will be identified as -+ // "". -+ std::string GetNamespace(const clang::Decl* record); ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) ++ ++import re ++import unittest ++ ++from six import StringIO ++ ++from grit import clique ++from grit import exception ++from grit import pseudo ++from grit import tclib ++from grit import grd_reader ++from grit import util ++ ++class MessageCliqueUnittest(unittest.TestCase): ++ def testClique(self): ++ factory = clique.UberClique() ++ msg = tclib.Message(text='Hello USERNAME, how are you?', ++ placeholders=[ ++ tclib.Placeholder('USERNAME', '%s', 'Joi')]) ++ c = factory.MakeClique(msg) ++ ++ self.failUnless(c.GetMessage() == msg) ++ self.failUnless(c.GetId() == msg.GetId()) ++ ++ msg_fr = tclib.Translation(text='Bonjour USERNAME, comment ca va?', ++ id=msg.GetId(), placeholders=[ ++ tclib.Placeholder('USERNAME', '%s', 'Joi')]) ++ msg_de = tclib.Translation(text='Guten tag USERNAME, wie geht es dir?', ++ id=msg.GetId(), placeholders=[ ++ tclib.Placeholder('USERNAME', '%s', 'Joi')]) ++ ++ c.AddTranslation(msg_fr, 'fr') ++ factory.FindCliqueAndAddTranslation(msg_de, 'de') ++ ++ # sort() sorts lists in-place and does not return them ++ for lang in ('en', 'fr', 'de'): ++ self.failUnless(lang in c.clique) ++ ++ self.failUnless(c.MessageForLanguage('fr').GetRealContent() == ++ msg_fr.GetRealContent()) ++ ++ try: ++ c.MessageForLanguage('zh-CN', False) ++ self.fail('Should have gotten exception') ++ except: ++ pass ++ ++ self.failUnless(c.MessageForLanguage('zh-CN', True) != None) ++ ++ rex = re.compile('fr|de|bingo') ++ self.failUnless(len(c.AllMessagesThatMatch(rex, False)) == 2) ++ self.failUnless( ++ c.AllMessagesThatMatch(rex, True)[pseudo.PSEUDO_LANG] is not None) ++ ++ def testBestClique(self): ++ factory = clique.UberClique() ++ factory.MakeClique(tclib.Message(text='Alfur', description='alfaholl')) ++ factory.MakeClique(tclib.Message(text='Alfur', description='')) ++ factory.MakeClique(tclib.Message(text='Vaettur', description='')) ++ factory.MakeClique(tclib.Message(text='Vaettur', description='')) ++ factory.MakeClique(tclib.Message(text='Troll', description='')) ++ factory.MakeClique(tclib.Message(text='Gryla', description='ID: IDS_GRYLA')) ++ factory.MakeClique(tclib.Message(text='Gryla', description='vondakerling')) ++ factory.MakeClique(tclib.Message(text='Leppaludi', description='ID: IDS_LL')) ++ factory.MakeClique(tclib.Message(text='Leppaludi', description='')) ++ ++ count_best_cliques = 0 ++ for c in factory.BestCliquePerId(): ++ count_best_cliques += 1 ++ msg = c.GetMessage() ++ text = msg.GetRealContent() ++ description = msg.GetDescription() ++ if text == 'Alfur': ++ self.failUnless(description == 'alfaholl') ++ elif text == 'Gryla': ++ self.failUnless(description == 'vondakerling') ++ elif text == 'Leppaludi': ++ self.failUnless(description == 'ID: IDS_LL') ++ self.failUnless(count_best_cliques == 5) ++ ++ def testAllInUberClique(self): ++ resources = grd_reader.Parse( ++ StringIO(u''' ++ ++ ++ ++ ++ Hello %sJoi, how are you doing today? ++ ++ ++ ++ ++ ++ ++ ++'''), util.PathFromRoot('.')) ++ resources.SetOutputLanguage('en') ++ resources.RunGatherers() ++ content_list = [] ++ for clique_list in resources.UberClique().cliques_.values(): ++ for clique in clique_list: ++ content_list.append(clique.GetMessage().GetRealContent()) ++ self.failUnless('Hello %s, how are you doing today?' in content_list) ++ self.failUnless('Jack "Black" Daniels' in content_list) ++ self.failUnless('Hello!' in content_list) ++ ++ def testCorrectExceptionIfWrongEncodingOnResourceFile(self): ++ '''This doesn't really belong in this unittest file, but what the heck.''' ++ resources = grd_reader.Parse( ++ StringIO(u''' ++ ++ ++ ++ ++ ++ ++'''), util.PathFromRoot('.')) ++ self.assertRaises(exception.SectionNotFound, resources.RunGatherers) ++ ++ def testSemiIdenticalCliques(self): ++ messages = [ ++ tclib.Message(text='Hello USERNAME', ++ placeholders=[tclib.Placeholder('USERNAME', '$1', 'Joi')]), ++ tclib.Message(text='Hello USERNAME', ++ placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi')]), ++ ] ++ self.failUnless(messages[0].GetId() == messages[1].GetId()) ++ ++ # Both of the above would share a translation. ++ translation = tclib.Translation(id=messages[0].GetId(), ++ text='Bonjour USERNAME', ++ placeholders=[tclib.Placeholder( ++ 'USERNAME', '$1', 'Joi')]) ++ ++ factory = clique.UberClique() ++ cliques = [factory.MakeClique(msg) for msg in messages] ++ ++ for clq in cliques: ++ clq.AddTranslation(translation, 'fr') ++ ++ self.failUnless(cliques[0].MessageForLanguage('fr').GetRealContent() == ++ 'Bonjour $1') ++ self.failUnless(cliques[1].MessageForLanguage('fr').GetRealContent() == ++ 'Bonjour %s') ++ ++ def testMissingTranslations(self): ++ messages = [ tclib.Message(text='Hello'), tclib.Message(text='Goodbye') ] ++ factory = clique.UberClique() ++ cliques = [factory.MakeClique(msg) for msg in messages] ++ ++ cliques[1].MessageForLanguage('fr', False, True) ++ ++ self.failUnless(not factory.HasMissingTranslations()) ++ ++ cliques[0].MessageForLanguage('de', False, False) ++ ++ self.failUnless(factory.HasMissingTranslations()) ++ ++ report = factory.MissingTranslationsReport() ++ self.failUnless(report.count('WARNING') == 1) ++ self.failUnless(report.count('8053599568341804890 "Goodbye" fr') == 1) ++ self.failUnless(report.count('ERROR') == 1) ++ self.failUnless(report.count('800120468867715734 "Hello" de') == 1) ++ ++ def testCustomTypes(self): ++ factory = clique.UberClique() ++ message = tclib.Message(text='Bingo bongo') ++ c = factory.MakeClique(message) ++ try: ++ c.SetCustomType(DummyCustomType()) ++ self.fail() ++ except: ++ pass # expected case - 'Bingo bongo' does not start with 'jjj' ++ ++ message = tclib.Message(text='jjjBingo bongo') ++ c = factory.MakeClique(message) ++ c.SetCustomType(util.NewClassInstance( ++ 'grit.clique_unittest.DummyCustomType', clique.CustomType)) ++ translation = tclib.Translation(id=message.GetId(), text='Bilingo bolongo') ++ c.AddTranslation(translation, 'fr') ++ self.failUnless(c.MessageForLanguage('fr').GetRealContent().startswith('jjj')) ++ ++ def testWhitespaceMessagesAreNontranslateable(self): ++ factory = clique.UberClique() ++ ++ message = tclib.Message(text=' \t') ++ c = factory.MakeClique(message, translateable=True) ++ self.failIf(c.IsTranslateable()) ++ ++ message = tclib.Message(text='\n \n ') ++ c = factory.MakeClique(message, translateable=True) ++ self.failIf(c.IsTranslateable()) ++ ++ message = tclib.Message(text='\n hello') ++ c = factory.MakeClique(message, translateable=True) ++ self.failUnless(c.IsTranslateable()) ++ ++ def testEachCliqueKeptSorted(self): ++ factory = clique.UberClique() ++ msg_a = tclib.Message(text='hello', description='a') ++ msg_b = tclib.Message(text='hello', description='b') ++ msg_c = tclib.Message(text='hello', description='c') ++ # Insert out of order ++ clique_b = factory.MakeClique(msg_b, translateable=True) ++ clique_a = factory.MakeClique(msg_a, translateable=True) ++ clique_c = factory.MakeClique(msg_c, translateable=True) ++ clique_list = factory.cliques_[clique_a.GetId()] ++ self.failUnless(len(clique_list) == 3) ++ self.failUnless(clique_list[0] == clique_a) ++ self.failUnless(clique_list[1] == clique_b) ++ self.failUnless(clique_list[2] == clique_c) ++ ++ def testBestCliqueSortIsStable(self): ++ factory = clique.UberClique() ++ text = 'hello' ++ msg_no_description = tclib.Message(text=text) ++ msg_id_description_a = tclib.Message(text=text, description='ID: a') ++ msg_id_description_b = tclib.Message(text=text, description='ID: b') ++ msg_description_x = tclib.Message(text=text, description='x') ++ msg_description_y = tclib.Message(text=text, description='y') ++ clique_id = msg_no_description.GetId() ++ ++ # Insert in an order that tests all outcomes. ++ clique_no_description = factory.MakeClique(msg_no_description, ++ translateable=True) ++ self.failUnless(factory.BestClique(clique_id) == clique_no_description) ++ clique_id_description_b = factory.MakeClique(msg_id_description_b, ++ translateable=True) ++ self.failUnless(factory.BestClique(clique_id) == clique_id_description_b) ++ clique_id_description_a = factory.MakeClique(msg_id_description_a, ++ translateable=True) ++ self.failUnless(factory.BestClique(clique_id) == clique_id_description_a) ++ clique_description_y = factory.MakeClique(msg_description_y, ++ translateable=True) ++ self.failUnless(factory.BestClique(clique_id) == clique_description_y) ++ clique_description_x = factory.MakeClique(msg_description_x, ++ translateable=True) ++ self.failUnless(factory.BestClique(clique_id) == clique_description_x) ++ ++ ++class DummyCustomType(clique.CustomType): ++ def Validate(self, message): ++ return message.GetRealContent().startswith('jjj') ++ def ValidateAndModify(self, lang, translation): ++ is_ok = self.Validate(translation) ++ self.ModifyEachTextPart(lang, translation) ++ def ModifyTextPart(self, lang, text): ++ return 'jjj%s' % text + -+ // Utility method for subclasses to check if this class is within an -+ // implementation (.cc, .cpp, .mm) file. -+ bool InImplementationFile(clang::SourceLocation location); + -+ private: -+ void BuildBannedLists(); ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/constants.py b/tools/grit/grit/constants.py +new file mode 100644 +index 0000000000..8229c94b09 +--- /dev/null ++++ b/tools/grit/grit/constants.py +@@ -0,0 +1,23 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+ void CheckTag(clang::TagDecl*); ++'''Constant definitions for GRIT. ++''' + -+ // Filtered versions of tags that are only called with things defined in -+ // chrome header files. -+ virtual void CheckChromeClass(clang::SourceLocation record_location, -+ clang::CXXRecordDecl* record) = 0; ++from __future__ import print_function + -+ // Utility methods used for filtering out non-chrome classes (and ones we -+ // deliberately ignore) in HandleTagDeclDefinition(). -+ std::string GetNamespaceImpl(const clang::DeclContext* context, -+ const std::string& candidate); -+ bool InBannedDirectory(clang::SourceLocation loc); -+ bool IsIgnoredType(const std::string& base_name); ++# This is the Icelandic noun meaning "grit" and is used to check that our ++# input files are in the correct encoding. The middle character gets encoded ++# as two bytes in UTF-8, so this is sufficient to detect incorrect encoding. ++ENCODING_CHECK = u'm\u00f6l' + -+ // Attempts to determine the filename for the given SourceLocation. -+ // Returns false if the filename could not be determined. -+ bool GetFilename(clang::SourceLocation loc, std::string* filename); ++# A special language, translations into which are always "TTTTTT". ++CONSTANT_LANGUAGE = 'x_constant' + -+ clang::CompilerInstance& instance_; -+ clang::DiagnosticsEngine& diagnostic_; ++FAKE_BIDI = 'fake-bidi' + -+ // List of banned namespaces. -+ std::vector banned_namespaces_; ++# Magic number added to the header of resources brotli compressed by grit. Used ++# to easily identify resources as being brotli compressed. See ++# ui/base/resource/resource_bundle.h for decompression usage. ++BROTLI_CONST = b'\x1e\x9b' +diff --git a/tools/grit/grit/exception.py b/tools/grit/grit/exception.py +new file mode 100644 +index 0000000000..2a363fb077 +--- /dev/null ++++ b/tools/grit/grit/exception.py +@@ -0,0 +1,139 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+ // List of banned directories. -+ std::vector banned_directories_; ++'''Exception types for GRIT. ++''' + -+ // List of types that we don't check. -+ std::set ignored_record_names_; ++from __future__ import print_function + -+ // List of decls to check once the current top-level decl is parsed. -+ std::vector pending_class_decls_; -+}; ++class Base(Exception): ++ '''A base exception that uses the class's docstring in addition to any ++ user-provided message as the body of the Base. ++ ''' ++ def __init__(self, msg=''): ++ if len(msg): ++ if self.__doc__: ++ msg = self.__doc__ + ': ' + msg ++ else: ++ msg = self.__doc__ ++ super(Base, self).__init__(msg) + -+#endif // TOOLS_CLANG_PLUGINS_CHROMECLASSTESTER_H_ -diff --git a/tools/clang/plugins/FindBadConstructs.cpp b/tools/clang/plugins/FindBadConstructs.cpp -new file mode 100644 -index 0000000000..b79a64dbd1 ---- /dev/null -+++ b/tools/clang/plugins/FindBadConstructs.cpp -@@ -0,0 +1,435 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. + -+// This file defines a bunch of recurring problems in the Chromium C++ code. -+// -+// Checks that are implemented: -+// - Constructors/Destructors should not be inlined if they are of a complex -+// class type. -+// - Missing "virtual" keywords on methods that should be virtual. -+// - Non-annotated overriding virtual methods. -+// - Virtual methods with nonempty implementations in their headers. -+// - Classes that derive from base::RefCounted / base::RefCountedThreadSafe -+// should have protected or private destructors. ++class Parsing(Base): ++ '''An error occurred parsing a GRD or XTB file.''' ++ pass + -+#include "clang/Frontend/FrontendPluginRegistry.h" -+#include "clang/AST/ASTConsumer.h" -+#include "clang/AST/AST.h" -+#include "clang/AST/CXXInheritance.h" -+#include "clang/AST/TypeLoc.h" -+#include "clang/Basic/SourceManager.h" -+#include "clang/Frontend/CompilerInstance.h" -+#include "llvm/Support/raw_ostream.h" + -+#include "ChromeClassTester.h" ++class UnknownElement(Parsing): ++ '''An unknown node type was encountered.''' ++ pass + -+using namespace clang; + -+namespace { ++class MissingElement(Parsing): ++ '''An expected element was missing.''' ++ pass + -+bool TypeHasNonTrivialDtor(const Type* type) { -+ if (const CXXRecordDecl* cxx_r = type->getCXXRecordDeclForPointerType()) -+ return cxx_r->hasTrivialDestructor(); + -+ return false; -+} ++class UnexpectedChild(Parsing): ++ '''An unexpected child element was encountered (on a leaf node).''' ++ pass + -+// Returns the underlying Type for |type| by expanding typedefs and removing -+// any namespace qualifiers. -+const Type* UnwrapType(const Type* type) { -+ if (const ElaboratedType* elaborated = dyn_cast(type)) -+ return UnwrapType(elaborated->getNamedType().getTypePtr()); -+ if (const TypedefType* typedefed = dyn_cast(type)) -+ return UnwrapType(typedefed->desugar().getTypePtr()); -+ return type; -+} -+ -+// Searches for constructs that we know we don't want in the Chromium code base. -+class FindBadConstructsConsumer : public ChromeClassTester { -+ public: -+ FindBadConstructsConsumer(CompilerInstance& instance, -+ bool check_refcounted_dtors, -+ bool check_virtuals_in_implementations) -+ : ChromeClassTester(instance), -+ check_refcounted_dtors_(check_refcounted_dtors), -+ check_virtuals_in_implementations_(check_virtuals_in_implementations) { -+ } + -+ virtual void CheckChromeClass(SourceLocation record_location, -+ CXXRecordDecl* record) { -+ bool implementation_file = InImplementationFile(record_location); ++class UnexpectedAttribute(Parsing): ++ '''The attribute was not expected''' ++ pass + -+ if (!implementation_file) { -+ // Only check for "heavy" constructors/destructors in header files; -+ // within implementation files, there is no performance cost. -+ CheckCtorDtorWeight(record_location, record); -+ } + -+ if (!implementation_file || check_virtuals_in_implementations_) { -+ bool warn_on_inline_bodies = !implementation_file; ++class UnexpectedContent(Parsing): ++ '''This element should not have content''' ++ pass + -+ // Check that all virtual methods are marked accordingly with both -+ // virtual and OVERRIDE. -+ CheckVirtualMethods(record_location, record, warn_on_inline_bodies); -+ } ++class MissingMandatoryAttribute(Parsing): ++ '''This element is missing a mandatory attribute''' ++ pass + -+ if (check_refcounted_dtors_) -+ CheckRefCountedDtors(record_location, record); -+ } + -+ private: -+ bool check_refcounted_dtors_; -+ bool check_virtuals_in_implementations_; -+ -+ // Returns true if |base| specifies one of the Chromium reference counted -+ // classes (base::RefCounted / base::RefCountedThreadSafe). |user_data| is -+ // ignored. -+ static bool IsRefCountedCallback(const CXXBaseSpecifier* base, -+ CXXBasePath& path, -+ void* user_data) { -+ FindBadConstructsConsumer* self = -+ static_cast(user_data); -+ -+ const TemplateSpecializationType* base_type = -+ dyn_cast( -+ UnwrapType(base->getType().getTypePtr())); -+ if (!base_type) { -+ // Base-most definition is not a template, so this cannot derive from -+ // base::RefCounted. However, it may still be possible to use with a -+ // scoped_refptr<> and support ref-counting, so this is not a perfect -+ // guarantee of safety. -+ return false; -+ } ++class MutuallyExclusiveMandatoryAttribute(Parsing): ++ '''This element has 2 mutually exclusive mandatory attributes''' ++ pass + -+ TemplateName name = base_type->getTemplateName(); -+ if (TemplateDecl* decl = name.getAsTemplateDecl()) { -+ std::string base_name = decl->getNameAsString(); + -+ // Check for both base::RefCounted and base::RefCountedThreadSafe. -+ if (base_name.compare(0, 10, "RefCounted") == 0 && -+ self->GetNamespace(decl) == "base") { -+ return true; -+ } -+ } -+ return false; -+ } ++class DuplicateKey(Parsing): ++ '''A duplicate key attribute was found.''' ++ pass + -+ // Prints errors if the destructor of a RefCounted class is public. -+ void CheckRefCountedDtors(SourceLocation record_location, -+ CXXRecordDecl* record) { -+ // Skip anonymous structs. -+ if (record->getIdentifier() == NULL) -+ return; -+ -+ CXXBasePaths paths; -+ if (!record->lookupInBases( -+ &FindBadConstructsConsumer::IsRefCountedCallback, this, paths)) { -+ return; // Class does not derive from a ref-counted base class. -+ } + -+ if (!record->hasUserDeclaredDestructor()) { -+ emitWarning( -+ record_location, -+ "Classes that are ref-counted should have explicit " -+ "destructors that are protected or private."); -+ } else if (CXXDestructorDecl* dtor = record->getDestructor()) { -+ if (dtor->getAccess() == AS_public) { -+ emitWarning( -+ dtor->getInnerLocStart(), -+ "Classes that are ref-counted should not have " -+ "public destructors."); -+ } -+ } -+ } ++class TooManyExamples(Parsing): ++ '''Only one element is allowed for each element.''' ++ pass + -+ // Prints errors if the constructor/destructor weight is too heavy. -+ void CheckCtorDtorWeight(SourceLocation record_location, -+ CXXRecordDecl* record) { -+ // We don't handle anonymous structs. If this record doesn't have a -+ // name, it's of the form: -+ // -+ // struct { -+ // ... -+ // } name_; -+ if (record->getIdentifier() == NULL) -+ return; -+ -+ // Count the number of templated base classes as a feature of whether the -+ // destructor can be inlined. -+ int templated_base_classes = 0; -+ for (CXXRecordDecl::base_class_const_iterator it = record->bases_begin(); -+ it != record->bases_end(); ++it) { -+ if (it->getTypeSourceInfo()->getTypeLoc().getTypeLocClass() == -+ TypeLoc::TemplateSpecialization) { -+ ++templated_base_classes; -+ } -+ } + -+ // Count the number of trivial and non-trivial member variables. -+ int trivial_member = 0; -+ int non_trivial_member = 0; -+ int templated_non_trivial_member = 0; -+ for (RecordDecl::field_iterator it = record->field_begin(); -+ it != record->field_end(); ++it) { -+ CountType(it->getType().getTypePtr(), -+ &trivial_member, -+ &non_trivial_member, -+ &templated_non_trivial_member); -+ } ++class FileNotFound(Parsing): ++ '''The resource file was not found.''' ++ pass + -+ // Check to see if we need to ban inlined/synthesized constructors. Note -+ // that the cutoffs here are kind of arbitrary. Scores over 10 break. -+ int dtor_score = 0; -+ // Deriving from a templated base class shouldn't be enough to trigger -+ // the ctor warning, but if you do *anything* else, it should. -+ // -+ // TODO(erg): This is motivated by templated base classes that don't have -+ // any data members. Somehow detect when templated base classes have data -+ // members and treat them differently. -+ dtor_score += templated_base_classes * 9; -+ // Instantiating a template is an insta-hit. -+ dtor_score += templated_non_trivial_member * 10; -+ // The fourth normal class member should trigger the warning. -+ dtor_score += non_trivial_member * 3; -+ -+ int ctor_score = dtor_score; -+ // You should be able to have 9 ints before we warn you. -+ ctor_score += trivial_member; -+ -+ if (ctor_score >= 10) { -+ if (!record->hasUserDeclaredConstructor()) { -+ emitWarning(record_location, -+ "Complex class/struct needs an explicit out-of-line " -+ "constructor."); -+ } else { -+ // Iterate across all the constructors in this file and yell if we -+ // find one that tries to be inline. -+ for (CXXRecordDecl::ctor_iterator it = record->ctor_begin(); -+ it != record->ctor_end(); ++it) { -+ if (it->hasInlineBody()) { -+ if (it->isCopyConstructor() && -+ !record->hasUserDeclaredCopyConstructor()) { -+ emitWarning(record_location, -+ "Complex class/struct needs an explicit out-of-line " -+ "copy constructor."); -+ } else { -+ emitWarning(it->getInnerLocStart(), -+ "Complex constructor has an inlined body."); -+ } -+ } -+ } -+ } -+ } + -+ // The destructor side is equivalent except that we don't check for -+ // trivial members; 20 ints don't need a destructor. -+ if (dtor_score >= 10 && !record->hasTrivialDestructor()) { -+ if (!record->hasUserDeclaredDestructor()) { -+ emitWarning( -+ record_location, -+ "Complex class/struct needs an explicit out-of-line " -+ "destructor."); -+ } else if (CXXDestructorDecl* dtor = record->getDestructor()) { -+ if (dtor->hasInlineBody()) { -+ emitWarning(dtor->getInnerLocStart(), -+ "Complex destructor has an inline body."); -+ } -+ } -+ } -+ } ++class InvalidMessage(Base): ++ '''The specified message failed validation.''' ++ pass + -+ void CheckVirtualMethod(const CXXMethodDecl* method, -+ bool warn_on_inline_bodies) { -+ if (!method->isVirtual()) -+ return; + -+ if (!method->isVirtualAsWritten()) { -+ SourceLocation loc = method->getTypeSpecStartLoc(); -+ if (isa(method)) -+ loc = method->getInnerLocStart(); -+ emitWarning(loc, "Overriding method must have \"virtual\" keyword."); -+ } ++class InvalidTranslation(Base): ++ '''Attempt to add an invalid translation to a clique.''' ++ pass + -+ // Virtual methods should not have inline definitions beyond "{}". This -+ // only matters for header files. -+ if (warn_on_inline_bodies && method->hasBody() && -+ method->hasInlineBody()) { -+ if (CompoundStmt* cs = dyn_cast(method->getBody())) { -+ if (cs->size()) { -+ emitWarning( -+ cs->getLBracLoc(), -+ "virtual methods with non-empty bodies shouldn't be " -+ "declared inline."); -+ } -+ } -+ } -+ } + -+ bool InTestingNamespace(const Decl* record) { -+ return GetNamespace(record).find("testing") != std::string::npos; -+ } ++class NoSuchTranslation(Base): ++ '''Requested translation not available''' ++ pass + -+ bool IsMethodInBannedNamespace(const CXXMethodDecl* method) { -+ if (InBannedNamespace(method)) -+ return true; -+ for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods(); -+ i != method->end_overridden_methods(); -+ ++i) { -+ const CXXMethodDecl* overridden = *i; -+ if (IsMethodInBannedNamespace(overridden)) -+ return true; -+ } + -+ return false; -+ } ++class NotReady(Base): ++ '''Attempt to use an object before it is ready, or attempt to translate \ ++an empty document.''' ++ pass + -+ void CheckOverriddenMethod(const CXXMethodDecl* method) { -+ if (!method->size_overridden_methods() || method->getAttr()) -+ return; + -+ if (isa(method) || method->isPure()) -+ return; ++class MismatchingPlaceholders(Base): ++ '''Placeholders do not match.''' ++ pass + -+ if (IsMethodInBannedNamespace(method)) -+ return; + -+ SourceLocation loc = method->getTypeSpecStartLoc(); -+ emitWarning(loc, "Overriding method must be marked with OVERRIDE."); -+ } ++class InvalidPlaceholderName(Base): ++ '''Placeholder name can only contain A-Z, a-z, 0-9 and underscore.''' ++ pass + -+ // Makes sure there is a "virtual" keyword on virtual methods. -+ // -+ // Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a -+ // trick to get around that. If a class has member variables whose types are -+ // in the "testing" namespace (which is how gmock works behind the scenes), -+ // there's a really high chance we won't care about these errors -+ void CheckVirtualMethods(SourceLocation record_location, -+ CXXRecordDecl* record, -+ bool warn_on_inline_bodies) { -+ for (CXXRecordDecl::field_iterator it = record->field_begin(); -+ it != record->field_end(); ++it) { -+ CXXRecordDecl* record_type = -+ it->getTypeSourceInfo()->getTypeLoc().getTypePtr()-> -+ getAsCXXRecordDecl(); -+ if (record_type) { -+ if (InTestingNamespace(record_type)) { -+ return; -+ } -+ } -+ } + -+ for (CXXRecordDecl::method_iterator it = record->method_begin(); -+ it != record->method_end(); ++it) { -+ if (it->isCopyAssignmentOperator() || isa(*it)) { -+ // Ignore constructors and assignment operators. -+ } else if (isa(*it) && -+ !record->hasUserDeclaredDestructor()) { -+ // Ignore non-user-declared destructors. -+ } else { -+ CheckVirtualMethod(*it, warn_on_inline_bodies); -+ CheckOverriddenMethod(*it); -+ } -+ } -+ } ++class BlockTagInTranslateableChunk(Base): ++ '''A block tag was encountered where it wasn't expected.''' ++ pass + -+ void CountType(const Type* type, -+ int* trivial_member, -+ int* non_trivial_member, -+ int* templated_non_trivial_member) { -+ switch (type->getTypeClass()) { -+ case Type::Record: { -+ // Simplifying; the whole class isn't trivial if the dtor is, but -+ // we use this as a signal about complexity. -+ if (TypeHasNonTrivialDtor(type)) -+ (*trivial_member)++; -+ else -+ (*non_trivial_member)++; -+ break; -+ } -+ case Type::TemplateSpecialization: { -+ TemplateName name = -+ dyn_cast(type)->getTemplateName(); -+ bool whitelisted_template = false; -+ -+ // HACK: I'm at a loss about how to get the syntax checker to get -+ // whether a template is exterened or not. For the first pass here, -+ // just do retarded string comparisons. -+ if (TemplateDecl* decl = name.getAsTemplateDecl()) { -+ std::string base_name = decl->getNameAsString(); -+ if (base_name == "basic_string") -+ whitelisted_template = true; -+ } + -+ if (whitelisted_template) -+ (*non_trivial_member)++; -+ else -+ (*templated_non_trivial_member)++; -+ break; -+ } -+ case Type::Elaborated: { -+ CountType( -+ dyn_cast(type)->getNamedType().getTypePtr(), -+ trivial_member, non_trivial_member, templated_non_trivial_member); -+ break; -+ } -+ case Type::Typedef: { -+ while (const TypedefType* TT = dyn_cast(type)) { -+ type = TT->getDecl()->getUnderlyingType().getTypePtr(); -+ } -+ CountType(type, trivial_member, non_trivial_member, -+ templated_non_trivial_member); -+ break; -+ } -+ default: { -+ // Stupid assumption: anything we see that isn't the above is one of -+ // the 20 integer types. -+ (*trivial_member)++; -+ break; -+ } -+ } -+ } -+}; ++class SectionNotFound(Base): ++ '''The section you requested was not found in the RC file. Make \ ++sure the section ID is correct (matches the section's ID in the RC file). \ ++Also note that you may need to specify the RC file's encoding (using the \ ++encoding="" attribute) if it is not in the default Windows-1252 encoding. \ ++''' ++ pass + -+class FindBadConstructsAction : public PluginASTAction { -+ public: -+ FindBadConstructsAction() -+ : check_refcounted_dtors_(true), -+ check_virtuals_in_implementations_(true) { -+ } + -+ protected: -+ // Overridden from PluginASTAction: -+ virtual ASTConsumer* CreateASTConsumer(CompilerInstance& instance, -+ llvm::StringRef ref) { -+ return new FindBadConstructsConsumer( -+ instance, check_refcounted_dtors_, check_virtuals_in_implementations_); -+ } ++class IdRangeOverlap(Base): ++ '''ID range overlap.''' ++ pass + -+ virtual bool ParseArgs(const CompilerInstance& instance, -+ const std::vector& args) { -+ bool parsed = true; + -+ for (size_t i = 0; i < args.size() && parsed; ++i) { -+ if (args[i] == "skip-refcounted-dtors") { -+ check_refcounted_dtors_ = false; -+ } else if (args[i] == "skip-virtuals-in-implementations") { -+ check_virtuals_in_implementations_ = false; -+ } else { -+ parsed = false; -+ llvm::errs() << "Unknown argument: " << args[i] << "\n"; -+ } -+ } ++class ReservedHeaderCollision(Base): ++ '''Resource included with first 3 bytes matching reserved header.''' ++ pass + -+ return parsed; -+ } + -+ private: -+ bool check_refcounted_dtors_; -+ bool check_virtuals_in_implementations_; -+}; ++class PlaceholderNotInsidePhNode(Base): ++ '''Placeholder formatters should be inside element.''' ++ pass + -+} // namespace + -+static FrontendPluginRegistry::Add -+X("find-bad-constructs", "Finds bad C++ constructs"); -diff --git a/tools/clang/plugins/Makefile b/tools/clang/plugins/Makefile ++class InvalidCharactersInsidePhNode(Base): ++ '''Invalid characters found inside element.''' ++ pass +diff --git a/tools/grit/grit/extern/BogoFP.py b/tools/grit/grit/extern/BogoFP.py new file mode 100644 -index 0000000000..0cfec71159 +index 0000000000..fc90145833 --- /dev/null -+++ b/tools/clang/plugins/Makefile -@@ -0,0 +1,19 @@ -+# This file requires the clang build system, at least for now. So to use this -+# Makefile, you should execute the following commands to copy this directory -+# into a clang checkout: -+# -+# cp -R third_party/llvm/tools/clang/tools/chrome-plugin -+# cd third_party/llvm/tools/clang/tools/chrome-plugin -+# make ++++ b/tools/grit/grit/extern/BogoFP.py +@@ -0,0 +1,22 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+CLANG_LEVEL := ../.. -+LIBRARYNAME = FindBadConstructs ++"""Bogus fingerprint implementation, do not use for production, ++provided only as an example. + -+LINK_LIBS_IN_SHARED = 0 -+SHARED_LIBRARY = 1 ++Usage: ++ grit.py -h grit.extern.BogoFP xmb /tmp/foo ++""" + -+include $(CLANG_LEVEL)/Makefile ++from __future__ import print_function + -+ifeq ($(OS),Darwin) -+ LDFLAGS=-Wl,-undefined,dynamic_lookup -+endif -diff --git a/tools/clang/plugins/OWNERS b/tools/clang/plugins/OWNERS -new file mode 100644 -index 0000000000..4733a4f06b ---- /dev/null -+++ b/tools/clang/plugins/OWNERS -@@ -0,0 +1 @@ -+erg@chromium.org -diff --git a/tools/clang/plugins/README.chromium b/tools/clang/plugins/README.chromium -new file mode 100644 -index 0000000000..a2ce0ff557 ---- /dev/null -+++ b/tools/clang/plugins/README.chromium -@@ -0,0 +1,4 @@ -+Documentation for this code is: ++import grit.extern.FP + -+- http://code.google.com/p/chromium/wiki/Clang -+- http://code.google.com/p/chromium/wiki/WritingClangPlugins -diff --git a/tools/clang/plugins/tests/base_refcounted.cpp b/tools/clang/plugins/tests/base_refcounted.cpp ++ ++def UnsignedFingerPrint(str, encoding='utf-8'): ++ """Generate a fingerprint not intended for production from str (it ++ reduces the precision of the production fingerprint by one bit). ++ """ ++ return (0xFFFFF7FFFFFFFFFF & ++ grit.extern.FP._UnsignedFingerPrintImpl(str, encoding)) +diff --git a/tools/grit/grit/extern/FP.py b/tools/grit/grit/extern/FP.py new file mode 100644 -index 0000000000..364a3e888c +index 0000000000..f4ec4d943f --- /dev/null -+++ b/tools/clang/plugins/tests/base_refcounted.cpp ++++ b/tools/grit/grit/extern/FP.py @@ -0,0 +1,72 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+#include "base_refcounted.h" ++from __future__ import print_function + -+#include ++try: ++ import hashlib ++ _new_md5 = hashlib.md5 ++except ImportError: ++ import md5 ++ _new_md5 = md5.new + -+namespace { + -+// Unsafe; should error. -+class AnonymousDerivedProtectedToPublicInImpl -+ : public ProtectedRefCountedDtorInHeader { -+ public: -+ AnonymousDerivedProtectedToPublicInImpl() {} -+ ~AnonymousDerivedProtectedToPublicInImpl() {} -+}; ++"""64-bit fingerprint support for strings. + -+} // namespace ++Usage: ++ from extern import FP ++ print('Fingerprint is %ld' % FP.FingerPrint('Hello world!')) ++""" + -+// Unsafe; should error. -+class PublicRefCountedDtorInImpl -+ : public base::RefCounted { -+ public: -+ PublicRefCountedDtorInImpl() {} -+ ~PublicRefCountedDtorInImpl() {} + -+ private: -+ friend class base::RefCounted; -+}; ++def _UnsignedFingerPrintImpl(str, encoding='utf-8'): ++ """Generate a 64-bit fingerprint by taking the first half of the md5 ++ of the string. ++ """ ++ hex128 = _new_md5(str.encode(encoding)).hexdigest() ++ int64 = int(hex128[:16], 16) ++ return int64 + -+class Foo { -+ public: -+ class BarInterface { -+ protected: -+ virtual ~BarInterface() {} -+ }; + -+ typedef base::RefCounted RefCountedBar; -+ typedef RefCountedBar AnotherTypedef; -+}; ++def UnsignedFingerPrint(str, encoding='utf-8'): ++ """Generate a 64-bit fingerprint. + -+class Baz { -+ public: -+ typedef typename Foo::AnotherTypedef MyLocalTypedef; -+}; ++ The default implementation uses _UnsignedFingerPrintImpl, which ++ takes the first half of the md5 of the string, but the ++ implementation may be switched using SetUnsignedFingerPrintImpl. ++ """ ++ return _UnsignedFingerPrintImpl(str, encoding) + -+// Unsafe; should error. -+class UnsafeTypedefChainInImpl : public Baz::MyLocalTypedef { -+ public: -+ UnsafeTypedefChainInImpl() {} -+ ~UnsafeTypedefChainInImpl() {} -+}; + -+int main() { -+ PublicRefCountedDtorInHeader bad; -+ PublicRefCountedDtorInImpl also_bad; ++def FingerPrint(str, encoding='utf-8'): ++ fp = UnsignedFingerPrint(str, encoding=encoding) ++ # interpret fingerprint as signed longs ++ if fp & 0x8000000000000000: ++ fp = -((~fp & 0xFFFFFFFFFFFFFFFF) + 1) ++ return fp + -+ ProtectedRefCountedDtorInHeader* protected_ok = NULL; -+ PrivateRefCountedDtorInHeader* private_ok = NULL; + -+ DerivedProtectedToPublicInHeader still_bad; -+ PublicRefCountedThreadSafeDtorInHeader another_bad_variation; -+ AnonymousDerivedProtectedToPublicInImpl and_this_is_bad_too; -+ ImplicitDerivedProtectedToPublicInHeader bad_yet_again; -+ UnsafeTypedefChainInImpl and_again_this_is_bad; ++def UseUnsignedFingerPrintFromModule(module_name): ++ """Imports module_name and replaces UnsignedFingerPrint in the ++ current module with the function of the same name from the imported ++ module. + -+ WebKitPublicDtorInHeader ignored; -+ WebKitDerivedPublicDtorInHeader still_ignored; ++ Returns the function object previously known as ++ grit.extern.FP.UnsignedFingerPrint. ++ """ ++ hash_module = __import__(module_name, fromlist=[module_name]) ++ return SetUnsignedFingerPrint(hash_module.UnsignedFingerPrint) + -+ return 0; -+} -diff --git a/tools/clang/plugins/tests/base_refcounted.h b/tools/clang/plugins/tests/base_refcounted.h ++ ++def SetUnsignedFingerPrint(function_object): ++ """Sets grit.extern.FP.UnsignedFingerPrint to point to ++ function_object. ++ ++ Returns the function object previously known as ++ grit.extern.FP.UnsignedFingerPrint. ++ """ ++ global UnsignedFingerPrint ++ original_function_object = UnsignedFingerPrint ++ UnsignedFingerPrint = function_object ++ return original_function_object +diff --git a/tools/grit/grit/extern/__init__.py b/tools/grit/grit/extern/__init__.py +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tools/grit/grit/extern/tclib.py b/tools/grit/grit/extern/tclib.py new file mode 100644 -index 0000000000..1e53215997 +index 0000000000..9952a87c11 --- /dev/null -+++ b/tools/clang/plugins/tests/base_refcounted.h -@@ -0,0 +1,121 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++++ b/tools/grit/grit/extern/tclib.py +@@ -0,0 +1,503 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+#ifndef BASE_REFCOUNTED_H_ -+#define BASE_REFCOUNTED_H_ ++# The tclib module contains tools for aggregating, verifying, and storing ++# messages destined for the Translation Console, as well as for reading ++# translations back and outputting them in some desired format. ++# ++# This has been stripped down to include only the functionality needed by grit ++# for creating Windows .rc and .h files. These are the only parts needed by ++# the Chrome build process. + -+namespace base { ++from __future__ import print_function + -+template -+class RefCounted { -+ public: -+ RefCounted() {} -+ ~RefCounted() {} -+}; ++from grit.extern import FP + -+template -+class RefCountedThreadSafe { -+ public: -+ RefCountedThreadSafe() {} -+ ~RefCountedThreadSafe() {} -+}; ++# This module assumes that within a bundle no two messages can have the ++# same id unless they're identical. + -+} // namespace base ++# The basic classes defined here for external use are Message and Translation, ++# where the former is used for English messages and the latter for ++# translations. These classes have a lot of common functionality, as expressed ++# by the common parent class BaseMessage. Perhaps the most important ++# distinction is that translated text is stored in UTF-8, whereas original text ++# is stored in whatever encoding the client uses (presumably Latin-1). + -+// Ignore classes whose inheritance tree ends in WebKit's RefCounted base -+// class. Though prone to error, this pattern is very prevalent in WebKit -+// code, so do not issue any warnings. -+namespace WebKit { ++# -------------------- ++# The public interface ++# -------------------- + -+template -+class RefCounted { -+ public: -+ RefCounted() {} -+ ~RefCounted() {} -+}; ++# Generate message id from message text and meaning string (optional), ++# both in utf-8 encoding ++# ++def GenerateMessageId(message, meaning=''): ++ fp = FP.FingerPrint(message) ++ if meaning: ++ # combine the fingerprints of message and meaning ++ fp2 = FP.FingerPrint(meaning) ++ if fp < 0: ++ fp = fp2 + (fp << 1) + 1 ++ else: ++ fp = fp2 + (fp << 1) ++ # To avoid negative ids we strip the high-order bit ++ return str(fp & 0x7fffffffffffffff) ++ ++# ------------------------------------------------------------------------- ++# The MessageTranslationError class is used to signal tclib-specific errors. ++ ++ ++class MessageTranslationError(Exception): ++ ++ def __init__(self, args = ''): ++ self.args = args ++ ++ ++# ----------------------------------------------------------- ++# The Placeholder class represents a placeholder in a message. ++ ++class Placeholder(object): ++ # String representation ++ def __str__(self): ++ return '%s, "%s", "%s"' % \ ++ (self.__presentation, self.__original, self.__example) ++ ++ # Getters ++ def GetOriginal(self): ++ return self.__original ++ ++ def GetPresentation(self): ++ return self.__presentation ++ ++ def GetExample(self): ++ return self.__example ++ ++ def __eq__(self, other): ++ return self.EqualTo(other, strict=1, ignore_trailing_spaces=0) ++ ++ # Equality test ++ # ++ # ignore_trailing_spaces: TC is using varchar to store the ++ # phrwr fields, as a result of that, the trailing spaces ++ # are removed by MySQL when the strings are stored into TC:-( ++ # ignore_trailing_spaces parameter is used to ignore ++ # trailing spaces during equivalence comparison. ++ # ++ def EqualTo(self, other, strict = 1, ignore_trailing_spaces = 1): ++ if type(other) is not Placeholder: ++ return 0 ++ if StringEquals(self.__presentation, other.__presentation, ++ ignore_trailing_spaces): ++ if not strict or (StringEquals(self.__original, other.__original, ++ ignore_trailing_spaces) and ++ StringEquals(self.__example, other.__example, ++ ignore_trailing_spaces)): ++ return 1 ++ return 0 + -+} // namespace WebKit + -+// Unsafe; should error. -+class PublicRefCountedDtorInHeader -+ : public base::RefCounted { -+ public: -+ PublicRefCountedDtorInHeader() {} -+ ~PublicRefCountedDtorInHeader() {} ++# ----------------------------------------------------------------- ++# BaseMessage is the common parent class of Message and Translation. ++# It is not meant for direct use. ++ ++class BaseMessage(object): ++ # Three types of message construction is supported. If the message text is a ++ # simple string with no dynamic content, you can pass it to the constructor ++ # as the "text" parameter. Otherwise, you can omit "text" and assemble the ++ # message step by step using AppendText() and AppendPlaceholder(). Or, as an ++ # alternative, you can give the constructor the "presentable" version of the ++ # message and a list of placeholders; it will then parse the presentation and ++ # build the message accordingly. For example: ++ # Message(text = "There are NUM_BUGS bugs in your code", ++ # placeholders = [Placeholder("NUM_BUGS", "%d", "33")], ++ # description = "Bla bla bla") ++ def __eq__(self, other): ++ # "source encoding" is nonsense, so ignore it ++ return _ObjectEquals(self, other, ['_BaseMessage__source_encoding']) ++ ++ def GetName(self): ++ return self.__name ++ ++ def GetSourceEncoding(self): ++ return self.__source_encoding ++ ++ # Append a placeholder to the message ++ def AppendPlaceholder(self, placeholder): ++ if not isinstance(placeholder, Placeholder): ++ raise MessageTranslationError("Invalid message placeholder %s in " ++ "message %s" % (placeholder, self.GetId())) ++ # Are there other placeholders with the same presentation? ++ # If so, they need to be the same. ++ for other in self.GetPlaceholders(): ++ if placeholder.GetPresentation() == other.GetPresentation(): ++ if not placeholder.EqualTo(other): ++ raise MessageTranslationError( ++ "Conflicting declarations of %s within message" % ++ placeholder.GetPresentation()) ++ # update placeholder list ++ dup = 0 ++ for item in self.__content: ++ if isinstance(item, Placeholder) and placeholder.EqualTo(item): ++ dup = 1 ++ break ++ if not dup: ++ self.__placeholders.append(placeholder) ++ ++ # update content ++ self.__content.append(placeholder) ++ ++ # Strips leading and trailing whitespace, and returns a tuple ++ # containing the leading and trailing space that was removed. ++ def Strip(self): ++ leading = trailing = '' ++ if len(self.__content) > 0: ++ s0 = self.__content[0] ++ if not isinstance(s0, Placeholder): ++ s = s0.lstrip() ++ leading = s0[:-len(s)] ++ self.__content[0] = s ++ ++ s0 = self.__content[-1] ++ if not isinstance(s0, Placeholder): ++ s = s0.rstrip() ++ trailing = s0[len(s):] ++ self.__content[-1] = s ++ return leading, trailing ++ ++ # Return the id of this message ++ def GetId(self): ++ if self.__id is None: ++ return self.GenerateId() ++ return self.__id ++ ++ # Set the id of this message ++ def SetId(self, id): ++ if id is None: ++ self.__id = None ++ else: ++ self.__id = str(id) # Treat numerical ids as strings ++ ++ # Return content of this message as a list (internal use only) ++ def GetContent(self): ++ return self.__content ++ ++ # Return a human-readable version of this message ++ def GetPresentableContent(self): ++ presentable_content = "" ++ for item in self.__content: ++ if isinstance(item, Placeholder): ++ presentable_content += item.GetPresentation() ++ else: ++ presentable_content += item ++ ++ return presentable_content ++ ++ # Return a fragment of a message in escaped format ++ def EscapeFragment(self, fragment): ++ return fragment.replace('%', '%%') ++ ++ # Return the "original" version of this message, doing %-escaping ++ # properly. If source_msg is specified, the placeholder original ++ # information inside source_msg will be used instead. ++ def GetOriginalContent(self, source_msg = None): ++ original_content = "" ++ for item in self.__content: ++ if isinstance(item, Placeholder): ++ if source_msg: ++ ph = source_msg.GetPlaceholder(item.GetPresentation()) ++ if not ph: ++ raise MessageTranslationError( ++ "Placeholder %s doesn't exist in message: %s" % ++ (item.GetPresentation(), source_msg)) ++ original_content += ph.GetOriginal() ++ else: ++ original_content += item.GetOriginal() ++ else: ++ original_content += self.EscapeFragment(item) ++ return original_content ++ ++ # Return the example of this message ++ def GetExampleContent(self): ++ example_content = "" ++ for item in self.__content: ++ if isinstance(item, Placeholder): ++ example_content += item.GetExample() ++ else: ++ example_content += item ++ return example_content ++ ++ # Return a list of all unique placeholders in this message ++ def GetPlaceholders(self): ++ return self.__placeholders ++ ++ # Return a placeholder in this message ++ def GetPlaceholder(self, presentation): ++ for item in self.__content: ++ if (isinstance(item, Placeholder) and ++ item.GetPresentation() == presentation): ++ return item ++ return None ++ ++ # Return this message's description ++ def GetDescription(self): ++ return self.__description ++ ++ # Add a message source ++ def AddSource(self, source): ++ self.__sources.append(source) ++ ++ # Return this message's sources as a list ++ def GetSources(self): ++ return self.__sources ++ ++ # Return this message's sources as a string ++ def GetSourcesAsText(self, delimiter = "; "): ++ return delimiter.join(self.__sources) ++ ++ # Set the obsolete flag for a message (internal use only) ++ def SetObsolete(self): ++ self.__obsolete = 1 ++ ++ # Get the obsolete flag for a message (internal use only) ++ def IsObsolete(self): ++ return self.__obsolete ++ ++ # Get the sequence number (0 by default) ++ def GetSequenceNumber(self): ++ return self.__sequence_number ++ ++ # Set the sequence number ++ def SetSequenceNumber(self, number): ++ self.__sequence_number = number ++ ++ # Increment instance counter ++ def AddInstance(self): ++ self.__num_instances += 1 ++ ++ # Return instance count ++ def GetNumInstances(self): ++ return self.__num_instances ++ ++ def GetErrors(self, from_tc=0): ++ """ ++ Returns a description of the problem if the message is not ++ syntactically valid, or None if everything is fine. ++ ++ Args: ++ from_tc: indicates whether this message came from the TC. We let ++ the TC get away with some things we normally wouldn't allow for ++ historical reasons. ++ """ ++ # check that placeholders are unambiguous ++ pos = 0 ++ phs = {} ++ for item in self.__content: ++ if isinstance(item, Placeholder): ++ phs[pos] = item ++ pos += len(item.GetPresentation()) ++ else: ++ pos += len(item) ++ presentation = self.GetPresentableContent() ++ for ph in self.GetPlaceholders(): ++ for pos in FindOverlapping(presentation, ph.GetPresentation()): ++ # message contains the same text as a placeholder presentation ++ other_ph = phs.get(pos) ++ if ((not other_ph ++ and not IsSubstringInPlaceholder(pos, len(ph.GetPresentation()), phs)) ++ or ++ (other_ph and len(other_ph.GetPresentation()) < len(ph.GetPresentation()))): ++ return "message contains placeholder name '%s':\n%s" % ( ++ ph.GetPresentation(), presentation) ++ return None ++ ++ ++ def __CopyTo(self, other): ++ """ ++ Returns a copy of this BaseMessage. ++ """ ++ assert isinstance(other, self.__class__) or isinstance(self, other.__class__) ++ other.__source_encoding = self.__source_encoding ++ other.__content = self.__content[:] ++ other.__description = self.__description ++ other.__id = self.__id ++ other.__num_instances = self.__num_instances ++ other.__obsolete = self.__obsolete ++ other.__name = self.__name ++ other.__placeholders = self.__placeholders[:] ++ other.__sequence_number = self.__sequence_number ++ other.__sources = self.__sources[:] ++ ++ return other ++ ++ def HasText(self): ++ """Returns true iff this message has anything other than placeholders.""" ++ for item in self.__content: ++ if not isinstance(item, Placeholder): ++ return True ++ return False ++ ++# -------------------------------------------------------- ++# The Message class represents original (English) messages ++ ++class Message(BaseMessage): ++ # See BaseMessage constructor ++ def __init__(self, source_encoding, text=None, id=None, ++ description=None, meaning="", placeholders=None, ++ source=None, sequence_number=0, clone_from=None, ++ time_created=0, name=None, is_hidden = 0): ++ ++ if clone_from is not None: ++ BaseMessage.__init__(self, None, clone_from=clone_from) ++ self.__meaning = clone_from.__meaning ++ self.__time_created = clone_from.__time_created ++ self.__is_hidden = clone_from.__is_hidden ++ return ++ ++ BaseMessage.__init__(self, source_encoding, text, id, description, ++ placeholders, source, sequence_number, ++ name=name) ++ self.__meaning = meaning ++ self.__time_created = time_created ++ self.SetIsHidden(is_hidden) ++ ++ # String representation ++ def __str__(self): ++ s = 'source: %s, id: %s, content: "%s", meaning: "%s", ' \ ++ 'description: "%s"' % \ ++ (self.GetSourcesAsText(), self.GetId(), self.GetPresentableContent(), ++ self.__meaning, self.GetDescription()) ++ if self.GetName() is not None: ++ s += ', name: "%s"' % self.GetName() ++ placeholders = self.GetPlaceholders() ++ for i in range(len(placeholders)): ++ s += ", placeholder[%d]: %s" % (i, placeholders[i]) ++ return s ++ ++ # Strips leading and trailing whitespace, and returns a tuple ++ # containing the leading and trailing space that was removed. ++ def Strip(self): ++ leading = trailing = '' ++ content = self.GetContent() ++ if len(content) > 0: ++ s0 = content[0] ++ if not isinstance(s0, Placeholder): ++ s = s0.lstrip() ++ leading = s0[:-len(s)] ++ content[0] = s ++ ++ s0 = content[-1] ++ if not isinstance(s0, Placeholder): ++ s = s0.rstrip() ++ trailing = s0[len(s):] ++ content[-1] = s ++ return leading, trailing ++ ++ # Generate an id by hashing message content ++ def GenerateId(self): ++ self.SetId(GenerateMessageId(self.GetPresentableContent(), ++ self.__meaning)) ++ return self.GetId() ++ ++ def GetMeaning(self): ++ return self.__meaning ++ ++ def GetTimeCreated(self): ++ return self.__time_created ++ ++ # Equality operator ++ def EqualTo(self, other, strict = 1): ++ # Check id, meaning, content ++ if self.GetId() != other.GetId(): ++ return 0 ++ if self.__meaning != other.__meaning: ++ return 0 ++ if self.GetPresentableContent() != other.GetPresentableContent(): ++ return 0 ++ # Check descriptions if comparison is strict ++ if (strict and ++ self.GetDescription() is not None and ++ other.GetDescription() is not None and ++ self.GetDescription() != other.GetDescription()): ++ return 0 ++ # Check placeholders ++ ph1 = self.GetPlaceholders() ++ ph2 = other.GetPlaceholders() ++ if len(ph1) != len(ph2): ++ return 0 ++ for i in range(len(ph1)): ++ if not ph1[i].EqualTo(ph2[i], strict): ++ return 0 ++ ++ return 1 ++ ++ def Copy(self): ++ """ ++ Returns a copy of this Message. ++ """ ++ assert isinstance(self, Message) ++ return Message(None, clone_from=self) ++ ++ def SetIsHidden(self, is_hidden): ++ """Sets whether this message should be hidden. ++ ++ Args: ++ is_hidden : 0 or 1 - if the message should be hidden, 0 otherwise ++ """ ++ if is_hidden not in [0, 1]: ++ raise MessageTranslationError("is_hidden must be 0 or 1, got %s") ++ self.__is_hidden = is_hidden ++ ++ def IsHidden(self): ++ """Returns 1 if this message is hidden, and 0 otherwise.""" ++ return self.__is_hidden ++ ++# ---------------------------------------------------- ++# The Translation class represents translated messages ++ ++class Translation(BaseMessage): ++ # See BaseMessage constructor ++ def __init__(self, source_encoding, text=None, id=None, ++ description=None, placeholders=None, source=None, ++ sequence_number=0, clone_from=None, ignore_ph_errors=0, ++ name=None): ++ if clone_from is not None: ++ BaseMessage.__init__(self, None, clone_from=clone_from) ++ return ++ ++ BaseMessage.__init__(self, source_encoding, text, id, description, ++ placeholders, source, sequence_number, ++ ignore_ph_errors=ignore_ph_errors, name=name) ++ ++ # String representation ++ def __str__(self): ++ s = 'source: %s, id: %s, content: "%s", description: "%s"' % \ ++ (self.GetSourcesAsText(), self.GetId(), self.GetPresentableContent(), ++ self.GetDescription()); ++ placeholders = self.GetPlaceholders() ++ for i in range(len(placeholders)): ++ s += ", placeholder[%d]: %s" % (i, placeholders[i]) ++ return s ++ ++ # Equality operator ++ def EqualTo(self, other, strict=1): ++ # Check id and content ++ if self.GetId() != other.GetId(): ++ return 0 ++ if self.GetPresentableContent() != other.GetPresentableContent(): ++ return 0 ++ # Check placeholders ++ ph1 = self.GetPlaceholders() ++ ph2 = other.GetPlaceholders() ++ if len(ph1) != len(ph2): ++ return 0 ++ for i in range(len(ph1)): ++ if not ph1[i].EqualTo(ph2[i], strict): ++ return 0 ++ ++ return 1 ++ ++ def Copy(self): ++ """ ++ Returns a copy of this Translation. ++ """ ++ return Translation(None, clone_from=self) +diff --git a/tools/grit/grit/format/__init__.py b/tools/grit/grit/format/__init__.py +new file mode 100644 +index 0000000000..55d56b8cfd +--- /dev/null ++++ b/tools/grit/grit/format/__init__.py +@@ -0,0 +1,8 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+ private: -+ friend class base::RefCounted; -+}; ++'''Module grit.format ++''' + -+// Unsafe; should error. -+class PublicRefCountedThreadSafeDtorInHeader -+ : public base::RefCountedThreadSafe< -+ PublicRefCountedThreadSafeDtorInHeader> { -+ public: -+ PublicRefCountedThreadSafeDtorInHeader() {} -+ ~PublicRefCountedThreadSafeDtorInHeader() {} -+ -+ private: -+ friend class base::RefCountedThreadSafe< -+ PublicRefCountedThreadSafeDtorInHeader>; -+}; ++pass +diff --git a/tools/grit/grit/format/android_xml.py b/tools/grit/grit/format/android_xml.py +new file mode 100644 +index 0000000000..7eb288891f +--- /dev/null ++++ b/tools/grit/grit/format/android_xml.py +@@ -0,0 +1,212 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+// Safe; should not have errors. -+class ProtectedRefCountedDtorInHeader -+ : public base::RefCounted { -+ public: -+ ProtectedRefCountedDtorInHeader() {} ++"""Produces localized strings.xml files for Android. + -+ protected: -+ ~ProtectedRefCountedDtorInHeader() {} ++In cases where an "android" type output file is requested in a grd, the classes ++in android_xml will process the messages and translations to produce a valid ++strings.xml that is properly localized with the specified language. + -+ private: -+ friend class base::RefCounted; -+}; ++For example if the following output tag were to be included in a grd file ++ ++ ... ++ ++ ... ++ + -+// Safe; should not have errors. -+class PrivateRefCountedDtorInHeader -+ : public base::RefCounted { -+ public: -+ PrivateRefCountedDtorInHeader() {} ++for a grd file with the following messages: + -+ private: -+ ~PrivateRefCountedDtorInHeader() {} -+ friend class base::RefCounted; -+}; ++ Hello ++ world + -+// Unsafe; A grandchild class ends up exposing their parent and grandparent's -+// destructors. -+class DerivedProtectedToPublicInHeader -+ : public ProtectedRefCountedDtorInHeader { -+ public: -+ DerivedProtectedToPublicInHeader() {} -+ ~DerivedProtectedToPublicInHeader() {} -+}; ++and there existed an appropriate xtb file containing the Spanish translations, ++then the output would be: + -+// Unsafe; A grandchild ends up implicitly exposing their parent and -+// grantparent's destructors. -+class ImplicitDerivedProtectedToPublicInHeader -+ : public ProtectedRefCountedDtorInHeader { -+ public: -+ ImplicitDerivedProtectedToPublicInHeader() {} -+}; ++ ++ ++ "Hola" ++ "mundo" ++ + -+// Unsafe-but-ignored; should not have errors. -+class WebKitPublicDtorInHeader -+ : public WebKit::RefCounted { -+ public: -+ WebKitPublicDtorInHeader() {} -+ ~WebKitPublicDtorInHeader() {} -+}; ++which would be written to values-es/strings.xml and usable by the Android ++resource framework. + -+// Unsafe-but-ignored; should not have errors. -+class WebKitDerivedPublicDtorInHeader -+ : public WebKitPublicDtorInHeader { -+ public: -+ WebKitDerivedPublicDtorInHeader() {} -+ ~WebKitDerivedPublicDtorInHeader() {} -+}; ++Advanced usage ++-------------- + -+#endif // BASE_REFCOUNTED_H_ -diff --git a/tools/clang/plugins/tests/base_refcounted.txt b/tools/clang/plugins/tests/base_refcounted.txt -new file mode 100644 -index 0000000000..4626424177 ---- /dev/null -+++ b/tools/clang/plugins/tests/base_refcounted.txt -@@ -0,0 +1,23 @@ -+In file included from base_refcounted.cpp:5: -+./base_refcounted.h:45:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors. -+ ~PublicRefCountedDtorInHeader() {} -+ ^ -+./base_refcounted.h:57:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors. -+ ~PublicRefCountedThreadSafeDtorInHeader() {} -+ ^ -+./base_refcounted.h:94:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors. -+ ~DerivedProtectedToPublicInHeader() {} -+ ^ -+./base_refcounted.h:99:1: warning: [chromium-style] Classes that are ref-counted should have explicit destructors that are protected or private. -+class ImplicitDerivedProtectedToPublicInHeader -+^ -+base_refcounted.cpp:16:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors. -+ ~AnonymousDerivedProtectedToPublicInImpl() {} -+ ^ -+base_refcounted.cpp:26:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors. -+ ~PublicRefCountedDtorInImpl() {} -+ ^ -+base_refcounted.cpp:52:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors. -+ ~UnsafeTypedefChainInImpl() {} -+ ^ -+7 warnings generated. -diff --git a/tools/clang/plugins/tests/inline_copy_ctor.cpp b/tools/clang/plugins/tests/inline_copy_ctor.cpp -new file mode 100644 -index 0000000000..dcd90020c5 ---- /dev/null -+++ b/tools/clang/plugins/tests/inline_copy_ctor.cpp -@@ -0,0 +1,5 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++To process only certain messages in a grd file, tag each desired message by ++adding "android_java" to formatter_data. Then set the environmental variable ++ANDROID_JAVA_TAGGED_ONLY to "true" when building the grd file. For example: + -+#include "inline_copy_ctor.h" -diff --git a/tools/clang/plugins/tests/inline_copy_ctor.h b/tools/clang/plugins/tests/inline_copy_ctor.h -new file mode 100644 -index 0000000000..619a18392b ---- /dev/null -+++ b/tools/clang/plugins/tests/inline_copy_ctor.h -@@ -0,0 +1,12 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++ Hello + -+struct C { -+ C(); -+ ~C(); ++To generate Android plurals (aka "quantity strings"), use the ICU plural syntax ++in the grd file. This will automatically be transformed into a element ++in the output xml file. For example: + -+ static C foo() { return C(); } ++ ++ {NUM_CATS, plural, ++ =1 {1 cat} ++ other {# cats}} ++ + -+ int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p , q, r, s, t, u, v, w, x; -+}; -diff --git a/tools/clang/plugins/tests/inline_copy_ctor.txt b/tools/clang/plugins/tests/inline_copy_ctor.txt -new file mode 100644 -index 0000000000..bc4bd8911e ---- /dev/null -+++ b/tools/clang/plugins/tests/inline_copy_ctor.txt -@@ -0,0 +1,5 @@ -+In file included from inline_copy_ctor.cpp:5: -+./inline_copy_ctor.h:5:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line copy constructor. -+struct C { -+^ -+1 warning generated. -diff --git a/tools/clang/plugins/tests/inline_ctor.cpp b/tools/clang/plugins/tests/inline_ctor.cpp -new file mode 100644 -index 0000000000..6a751fb405 ---- /dev/null -+++ b/tools/clang/plugins/tests/inline_ctor.cpp -@@ -0,0 +1,25 @@ -+// Copyright (c) 2011 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++ will produce + -+#include "inline_ctor.h" ++ ++ 1 Katze ++ %d Katzen ++ ++""" + -+#include -+#include ++from __future__ import print_function + -+// We don't warn on classes that are in CPP files. -+class InlineInCPPOK { -+ public: -+ InlineInCPPOK() {} -+ ~InlineInCPPOK() {} ++import os ++import re ++import xml.sax.saxutils ++ ++from grit import lazy_re ++from grit.node import message ++ ++ ++# When this environmental variable has value "true", only tagged messages will ++# be outputted. ++_TAGGED_ONLY_ENV_VAR = 'ANDROID_JAVA_TAGGED_ONLY' ++_TAGGED_ONLY_DEFAULT = False ++ ++# In tagged-only mode, only messages with this tag will be ouputted. ++_EMIT_TAG = 'android_java' ++ ++_NAME_PATTERN = lazy_re.compile(r'IDS_(?P[A-Z0-9_]+)\Z') ++ ++# Most strings are output as a element. Note the double quotes ++# around the value to preserve whitespace. ++_STRING_TEMPLATE = u'"%s"\n' ++ ++# Some strings are output as a element. ++_PLURALS_TEMPLATE = '\n%s\n' ++_PLURALS_ITEM_TEMPLATE = ' %s\n' ++ ++# Matches e.g. "{HELLO, plural, HOW ARE YOU DOING}", while capturing ++# "HOW ARE YOU DOING" in . ++_PLURALS_PATTERN = lazy_re.compile(r'\{[A-Z_]+,\s*plural,(?P.*)\}$', ++ flags=re.S) ++ ++# Repeatedly matched against the capture in _PLURALS_PATTERN, ++# to match "{}". ++_PLURALS_ITEM_PATTERN = lazy_re.compile(r'(?P\S+?)\s*' ++ r'\{(?P.*?)\}') ++_PLURALS_QUANTITY_MAP = { ++ '=0': 'zero', ++ 'zero': 'zero', ++ '=1': 'one', ++ 'one': 'one', ++ '=2': 'two', ++ 'two': 'two', ++ 'few': 'few', ++ 'many': 'many', ++ 'other': 'other', ++} + -+ private: -+ std::vector one_; -+ std::vector two_; -+}; + -+int main() { -+ InlineInCPPOK one; -+ InlineCtorsArentOKInHeader two; -+ return 0; -+} -diff --git a/tools/clang/plugins/tests/inline_ctor.h b/tools/clang/plugins/tests/inline_ctor.h ++def Format(root, lang='en', output_dir='.'): ++ yield ('\n' ++ '\n') ++ ++ tagged_only = _TAGGED_ONLY_DEFAULT ++ if _TAGGED_ONLY_ENV_VAR in os.environ: ++ tagged_only = os.environ[_TAGGED_ONLY_ENV_VAR].lower() ++ if tagged_only == 'true': ++ tagged_only = True ++ elif tagged_only == 'false': ++ tagged_only = False ++ else: ++ raise Exception('env variable ANDROID_JAVA_TAGGED_ONLY must have value ' ++ 'true or false. Invalid value: %s' % tagged_only) ++ ++ for item in root.ActiveDescendants(): ++ with item: ++ if ShouldOutputNode(item, tagged_only): ++ yield _FormatMessage(item, lang) ++ ++ yield '\n' ++ ++ ++def ShouldOutputNode(node, tagged_only): ++ """Returns true if node should be outputted. ++ ++ Args: ++ node: a Node from the grd dom ++ tagged_only: true, if only tagged messages should be outputted ++ """ ++ return (isinstance(node, message.MessageNode) and ++ (not tagged_only or _EMIT_TAG in node.formatter_data)) ++ ++ ++def _FormatPluralMessage(message): ++ """Compiles ICU plural syntax to the body of an Android element. ++ ++ 1. In a .grd file, we can write a plural string like this: ++ ++ ++ {NUM_THINGS, plural, ++ =1 {1 thing} ++ other {# things}} ++ ++ ++ 2. The Android equivalent looks like this: ++ ++ ++ 1 thing ++ %d things ++ ++ ++ This method takes the body of (1) and converts it to the body of (2). ++ ++ If the message is *not* a plural string, this function returns `None`. ++ If the message includes quantities without an equivalent format in Android, ++ it raises an exception. ++ """ ++ ret = {} ++ plural_match = _PLURALS_PATTERN.match(message) ++ if not plural_match: ++ return None ++ body_in = plural_match.group('items').strip() ++ lines = [] ++ quantities_so_far = set() ++ for item_match in _PLURALS_ITEM_PATTERN.finditer(body_in): ++ quantity_in = item_match.group('quantity') ++ quantity_out = _PLURALS_QUANTITY_MAP.get(quantity_in) ++ value_in = item_match.group('value') ++ value_out = '"' + value_in.replace('#', '%d') + '"' ++ if quantity_out: ++ # only one line per quantity out (https://crbug.com/787488) ++ if quantity_out not in quantities_so_far: ++ quantities_so_far.add(quantity_out) ++ lines.append(_PLURALS_ITEM_TEMPLATE % (quantity_out, value_out)) ++ else: ++ raise Exception('Unsupported plural quantity for android ' ++ 'strings.xml: %s' % quantity_in) ++ return ''.join(lines) ++ ++ ++def _FormatMessage(item, lang): ++ """Writes out a single string as a element.""" ++ ++ mangled_name = item.GetTextualIds()[0] ++ match = _NAME_PATTERN.match(mangled_name) ++ if not match: ++ raise Exception('Unexpected resource name: %s' % mangled_name) ++ name = match.group('name').lower() ++ ++ value = item.ws_at_start + item.Translate(lang) + item.ws_at_end ++ # Replace < > & with < > & to ensure we generate valid XML and ++ # replace ' " with \' \" to conform to Android's string formatting rules. ++ value = xml.sax.saxutils.escape(value, {"'": "\\'", '"': '\\"'}) ++ ++ plurals = _FormatPluralMessage(value) ++ if plurals: ++ return _PLURALS_TEMPLATE % (name, plurals) ++ else: ++ return _STRING_TEMPLATE % (name, value) +diff --git a/tools/grit/grit/format/android_xml_unittest.py b/tools/grit/grit/format/android_xml_unittest.py new file mode 100644 -index 0000000000..d053b2f57d +index 0000000000..d9f476fddf --- /dev/null -+++ b/tools/clang/plugins/tests/inline_ctor.h -@@ -0,0 +1,21 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++++ b/tools/grit/grit/format/android_xml_unittest.py +@@ -0,0 +1,149 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+#ifndef INLINE_CTOR_H_ -+#define INLINE_CTOR_H_ ++"""Unittest for android_xml.py.""" + -+#include -+#include ++from __future__ import print_function + -+class InlineCtorsArentOKInHeader { -+ public: -+ InlineCtorsArentOKInHeader() {} -+ ~InlineCtorsArentOKInHeader() {} ++import os ++import sys ++import unittest + -+ private: -+ std::vector one_; -+ std::vector two_; -+}; ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++from six import StringIO ++ ++from grit import util ++from grit.format import android_xml ++from grit.node import message ++from grit.tool import build ++ ++ ++class AndroidXmlUnittest(unittest.TestCase): ++ ++ def testMessages(self): ++ root = util.ParseGrdForUnittest(r""" ++ ++ ++ Martha ++ ++ sat and wondered ++ ++ out loud, "Why don't I build a flying car?" ++ ++ ++ She gathered ++wood, charcoal, and ++a sledge hammer. ++ ++ ++ ''' How old fashioned -- she thought. ''' ++ ++ ++ I'll buy a %d200 nm laser at %sthe grocery store. ++ ++ ++ {NUM_THINGS, plural, ++ =1 {Maybe I'll get one laser.} ++ other {Maybe I'll get # lasers.}} ++ ++ ++ {NUM_MISSISSIPPIS, plural, ++ =1{OneMississippi}other{ManyMississippis}} ++ ++ ++ """) ++ ++ buf = StringIO() ++ build.RcBuilder.ProcessNode(root, DummyOutput('android', 'en'), buf) ++ output = buf.getvalue() ++ expected = r""" ++ ++ ++"Martha" ++"sat and wondered" ++"out loud, \"Why don\'t I build a flying car?\"" ++"She gathered ++wood, charcoal, and ++a sledge hammer." ++" How old fashioned -- she thought. " ++"I\'ll buy a %d nm laser at %s." ++ ++ "Maybe I\'ll get one laser." ++ "Maybe I\'ll get %d lasers." ++ ++ ++ "OneMississippi" ++ "ManyMississippis" ++ ++ ++""" ++ self.assertEqual(output.strip(), expected.strip()) ++ ++ ++ def testConflictingPlurals(self): ++ root = util.ParseGrdForUnittest(r""" ++ ++ ++ {NUM_THINGS, plural, ++ =1 {Maybe I'll get one laser.} ++ one {Maybe I'll get one laser.} ++ other {Maybe I'll get # lasers.}} ++ ++ ++ """) ++ ++ buf = StringIO() ++ build.RcBuilder.ProcessNode(root, DummyOutput('android', 'en'), buf) ++ output = buf.getvalue() ++ expected = r""" ++ ++ ++ ++ "Maybe I\'ll get one laser." ++ "Maybe I\'ll get %d lasers." ++ ++ ++""" ++ self.assertEqual(output.strip(), expected.strip()) + -+#endif // INLINE_CTOR_H_ -diff --git a/tools/clang/plugins/tests/inline_ctor.txt b/tools/clang/plugins/tests/inline_ctor.txt -new file mode 100644 -index 0000000000..caa0cb4e3b ---- /dev/null -+++ b/tools/clang/plugins/tests/inline_ctor.txt -@@ -0,0 +1,8 @@ -+In file included from inline_ctor.cpp:5: -+./inline_ctor.h:13:3: warning: [chromium-style] Complex constructor has an inlined body. -+ InlineCtorsArentOKInHeader() {} -+ ^ -+./inline_ctor.h:14:3: warning: [chromium-style] Complex destructor has an inline body. -+ ~InlineCtorsArentOKInHeader() {} -+ ^ -+2 warnings generated. -diff --git a/tools/clang/plugins/tests/missing_ctor.cpp b/tools/clang/plugins/tests/missing_ctor.cpp -new file mode 100644 -index 0000000000..8ee2fb2ac8 ---- /dev/null -+++ b/tools/clang/plugins/tests/missing_ctor.cpp -@@ -0,0 +1,23 @@ -+// Copyright (c) 2011 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. + -+#include "missing_ctor.h" ++ def testTaggedOnly(self): ++ root = util.ParseGrdForUnittest(r""" ++ ++ ++ Hello ++ ++ ++ world ++ ++ ++ """) + -+#include -+#include ++ msg_hello, msg_world = root.GetChildrenOfType(message.MessageNode) ++ self.assertTrue(android_xml.ShouldOutputNode(msg_hello, tagged_only=True)) ++ self.assertFalse(android_xml.ShouldOutputNode(msg_world, tagged_only=True)) ++ self.assertTrue(android_xml.ShouldOutputNode(msg_hello, tagged_only=False)) ++ self.assertTrue(android_xml.ShouldOutputNode(msg_world, tagged_only=False)) + -+// We don't warn on classes that use default ctors in cpp files. -+class MissingInCPPOK { -+ public: + -+ private: -+ std::vector one_; -+ std::vector two_; -+}; ++class DummyOutput(object): + -+int main() { -+ MissingInCPPOK one; -+ MissingCtorsArentOKInHeader two; -+ return 0; -+} -diff --git a/tools/clang/plugins/tests/missing_ctor.h b/tools/clang/plugins/tests/missing_ctor.h -new file mode 100644 -index 0000000000..1050457a1a ---- /dev/null -+++ b/tools/clang/plugins/tests/missing_ctor.h -@@ -0,0 +1,19 @@ -+// Copyright (c) 2011 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++ def __init__(self, type, language): ++ self.type = type ++ self.language = language + -+#ifndef MISSING_CTOR_H_ -+#define MISSING_CTOR_H_ ++ def GetType(self): ++ return self.type + -+#include -+#include ++ def GetLanguage(self): ++ return self.language + -+class MissingCtorsArentOKInHeader { -+ public: ++ def GetOutputFilename(self): ++ return 'hello.gif' + -+ private: -+ std::vector one_; -+ std::vector two_; -+}; ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/format/c_format.py b/tools/grit/grit/format/c_format.py +new file mode 100644 +index 0000000000..16809a9f70 +--- /dev/null ++++ b/tools/grit/grit/format/c_format.py +@@ -0,0 +1,95 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Formats as a .C file for compilation. ++""" ++ ++from __future__ import print_function + -+#endif // MISSING_CTOR_H_ -diff --git a/tools/clang/plugins/tests/missing_ctor.txt b/tools/clang/plugins/tests/missing_ctor.txt ++import codecs ++import os ++import re ++ ++import six ++ ++from grit import util ++ ++ ++def _FormatHeader(root, output_dir): ++ """Returns the required preamble for C files.""" ++ # Find the location of the resource header file, so that we can include ++ # it. ++ resource_header = 'resource.h' # fall back to this ++ for output in root.GetOutputFiles(): ++ if output.attrs['type'] == 'rc_header': ++ resource_header = os.path.abspath(output.GetOutputFilename()) ++ resource_header = util.MakeRelativePath(output_dir, resource_header) ++ return """// This file is automatically generated by GRIT. Do not edit. ++ ++#include "%s" ++ ++// All strings are UTF-8 ++""" % (resource_header) ++# end _FormatHeader() function ++ ++ ++def Format(root, lang='en', output_dir='.'): ++ """Outputs a C switch statement representing the string table.""" ++ from grit.node import message ++ assert isinstance(lang, six.string_types) ++ ++ yield _FormatHeader(root, output_dir) ++ ++ yield 'const char* GetString(int id) {\n switch (id) {' ++ ++ for item in root.ActiveDescendants(): ++ with item: ++ if isinstance(item, message.MessageNode): ++ yield _FormatMessage(item, lang) ++ ++ yield '\n default:\n return 0;\n }\n}\n' ++ ++ ++def _HexToOct(match): ++ "Return the octal form of the hex numbers" ++ hex = match.group("hex") ++ result = "" ++ while len(hex): ++ next_num = int(hex[2:4], 16) ++ result += "\\" + '%03o' % next_num ++ hex = hex[4:] ++ return match.group("escaped_backslashes") + result ++ ++ ++def _FormatMessage(item, lang): ++ """Format a single element.""" ++ ++ message = item.ws_at_start + item.Translate(lang) + item.ws_at_end ++ # Output message with non-ascii chars escaped as octal numbers C's grammar ++ # allows escaped hexadecimal numbers to be infinite, but octal is always of ++ # the form \OOO. Python 3 doesn't support string-escape, so we have to jump ++ # through some hoops here via codecs.escape_encode. ++ # This basically does: ++ # - message - the starting string ++ # - message.encode(...) - convert to bytes ++ # - codecs.escape_encode(...) - convert non-ASCII bytes to \x## escapes ++ # - (...).decode() - convert bytes back to a string ++ message = codecs.escape_encode(message.encode('utf-8'))[0].decode('utf-8') ++ # an escaped char is (\xHH)+ but only if the initial ++ # backslash is not escaped. ++ not_a_backslash = r"(^|[^\\])" # beginning of line or a non-backslash char ++ escaped_backslashes = not_a_backslash + r"(\\\\)*" ++ hex_digits = r"((\\x)[0-9a-f]{2})+" ++ two_digit_hex_num = re.compile( ++ r"(?P%s)(?P%s)" ++ % (escaped_backslashes, hex_digits)) ++ message = two_digit_hex_num.sub(_HexToOct, message) ++ # unescape \ (convert \\ back to \) ++ message = message.replace('\\\\', '\\') ++ message = message.replace('"', '\\"') ++ message = util.LINEBREAKS.sub(r'\\n', message) ++ ++ name_attr = item.GetTextualIds()[0] ++ ++ return '\n case %s:\n return "%s";' % (name_attr, message) +diff --git a/tools/grit/grit/format/c_format_unittest.py b/tools/grit/grit/format/c_format_unittest.py new file mode 100644 -index 0000000000..301449c4ac +index 0000000000..380120c42f --- /dev/null -+++ b/tools/clang/plugins/tests/missing_ctor.txt -@@ -0,0 +1,6 @@ -+In file included from missing_ctor.cpp:5: -+./missing_ctor.h:11:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor. -+class MissingCtorsArentOKInHeader { -+^ -+./missing_ctor.h:11:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line destructor. -+2 warnings generated. -diff --git a/tools/clang/plugins/tests/nested_class_inline_ctor.cpp b/tools/clang/plugins/tests/nested_class_inline_ctor.cpp ++++ b/tools/grit/grit/format/c_format_unittest.py +@@ -0,0 +1,81 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Unittest for c_format.py. ++""" ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++from six import StringIO ++ ++from grit import util ++from grit.tool import build ++ ++ ++class CFormatUnittest(unittest.TestCase): ++ ++ def testMessages(self): ++ root = util.ParseGrdForUnittest(u""" ++ ++ Do you want to play questions? ++ ++ "What's in a name, %sBrandon?" ++ ++ ++ Was that rhetoric? ++No. ++Statement. Two all. Game point. ++ ++ ++ \u00f5\\xc2\\xa4\\\u00a4\\\\xc3\\xb5\u4924 ++ ++ ++ """) ++ ++ buf = StringIO() ++ build.RcBuilder.ProcessNode(root, DummyOutput('c_format', 'en'), buf) ++ output = util.StripBlankLinesAndComments(buf.getvalue()) ++ self.assertEqual(u"""\ ++#include "resource.h" ++const char* GetString(int id) { ++ switch (id) { ++ case IDS_QUESTIONS: ++ return "Do you want to play questions?"; ++ case IDS_QUOTES: ++ return "\\"What\\'s in a name, %s?\\""; ++ case IDS_LINE_BREAKS: ++ return "Was that rhetoric?\\nNo.\\nStatement. Two all. Game point."; ++ case IDS_NON_ASCII: ++ return "\\303\\265\\xc2\\xa4\\\\302\\244\\\\xc3\\xb5\\344\\244\\244"; ++ default: ++ return 0; ++ } ++}""", output) ++ ++ ++class DummyOutput(object): ++ ++ def __init__(self, type, language): ++ self.type = type ++ self.language = language ++ ++ def GetType(self): ++ return self.type ++ ++ def GetLanguage(self): ++ return self.language ++ ++ def GetOutputFilename(self): ++ return 'hello.gif' ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/format/chrome_messages_json.py b/tools/grit/grit/format/chrome_messages_json.py new file mode 100644 -index 0000000000..aa90a95eb3 +index 0000000000..88ec1d914b --- /dev/null -+++ b/tools/clang/plugins/tests/nested_class_inline_ctor.cpp -@@ -0,0 +1,5 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++++ b/tools/grit/grit/format/chrome_messages_json.py +@@ -0,0 +1,59 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+#include "nested_class_inline_ctor.h" -diff --git a/tools/clang/plugins/tests/nested_class_inline_ctor.h b/tools/clang/plugins/tests/nested_class_inline_ctor.h ++"""Formats as a .json file that can be used to localize Google Chrome ++extensions.""" ++ ++from __future__ import print_function ++ ++from json import JSONEncoder ++ ++from grit import constants ++from grit.node import message ++ ++def Format(root, lang='en', output_dir='.'): ++ """Format the messages as JSON.""" ++ yield '{' ++ ++ encoder = JSONEncoder(ensure_ascii=False) ++ format = '"%s":{"message":%s%s}' ++ placeholder_format = '"%i":{"content":"$%i"}' ++ first = True ++ for child in root.ActiveDescendants(): ++ if isinstance(child, message.MessageNode): ++ id = child.attrs['name'] ++ if id.startswith('IDR_') or id.startswith('IDS_'): ++ id = id[4:] ++ ++ translation_missing = child.GetCliques()[0].clique.get(lang) is None; ++ if (child.ShouldFallbackToEnglish() and translation_missing and ++ lang != constants.FAKE_BIDI): ++ # Skip the string if it's not translated. Chrome will fallback ++ # to English automatically. ++ continue ++ ++ loc_message = encoder.encode(child.ws_at_start + child.Translate(lang) + ++ child.ws_at_end) ++ ++ # Replace $n place-holders with $n$ and add an appropriate "placeholders" ++ # entry. Note that chrome.i18n.getMessage only supports 9 placeholders: ++ # https://developer.chrome.com/extensions/i18n#method-getMessage ++ placeholders = '' ++ for i in range(1, 10): ++ if loc_message.find('$%d' % i) == -1: ++ break ++ loc_message = loc_message.replace('$%d' % i, '$%d$' % i) ++ if placeholders: ++ placeholders += ',' ++ placeholders += placeholder_format % (i, i) ++ ++ if not first: ++ yield ',' ++ first = False ++ ++ if placeholders: ++ placeholders = ',"placeholders":{%s}' % placeholders ++ yield format % (id, loc_message, placeholders) ++ ++ yield '}' +diff --git a/tools/grit/grit/format/chrome_messages_json_unittest.py b/tools/grit/grit/format/chrome_messages_json_unittest.py new file mode 100644 -index 0000000000..01cfea9232 +index 0000000000..a54e6bdc1c --- /dev/null -+++ b/tools/clang/plugins/tests/nested_class_inline_ctor.h -@@ -0,0 +1,22 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++++ b/tools/grit/grit/format/chrome_messages_json_unittest.py +@@ -0,0 +1,190 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Unittest for chrome_messages_json.py. ++""" ++ ++from __future__ import print_function + -+#ifndef NESTED_CLASS_INLINE_CTOR_H_ -+#define NESTED_CLASS_INLINE_CTOR_H_ ++import json ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++from six import StringIO ++ ++from grit import grd_reader ++from grit import util ++from grit.tool import build ++ ++class ChromeMessagesJsonFormatUnittest(unittest.TestCase): ++ ++ # The default unittest diff limit is too low for our unittests. ++ # Allow the framework to show the full diff output all the time. ++ maxDiff = None ++ ++ def testMessages(self): ++ root = util.ParseGrdForUnittest(u""" ++ ++ ++ Simple message. ++ ++ ++ element\u2019s \u201c%sname\u201d attribute ++ ++ ++ %1$d1 error, %2$d1 warning ++ ++ ++ $1atest$2b ++ ++ ++ ''' (%d2) ++ ++ ++ (%d2) ''' ++ ++ ++ ''' (%d2) ''' ++ ++ ++ A "double quoted" message. ++ ++ ++ \\ ++ ++ ++ """) ++ ++ buf = StringIO() ++ build.RcBuilder.ProcessNode(root, DummyOutput('chrome_messages_json', 'en'), ++ buf) ++ output = buf.getvalue() ++ test = u""" ++{ ++ "SIMPLE_MESSAGE": { ++ "message": "Simple message." ++ }, ++ "QUOTES": { ++ "message": "element\u2019s \u201c%s\u201d attribute" ++ }, ++ "PLACEHOLDERS": { ++ "message": "%1$d error, %2$d warning" ++ }, ++ "PLACEHOLDERS_SUBSTITUTED_BY_GETMESSAGE": { ++ "message": "$1$test$2$", ++ "placeholders": { ++ "1": { ++ "content": "$1" ++ }, ++ "2": { ++ "content": "$2" ++ } ++ } ++ }, ++ "STARTS_WITH_SPACE": { ++ "message": " (%d)" ++ }, ++ "ENDS_WITH_SPACE": { ++ "message": "(%d) " ++ }, ++ "SPACE_AT_BOTH_ENDS": { ++ "message": " (%d) " ++ }, ++ "DOUBLE_QUOTES": { ++ "message": "A \\"double quoted\\" message." ++ }, ++ "BACKSLASH": { ++ "message": "\\\\" ++ } ++} ++""" ++ self.assertEqual(json.loads(test), json.loads(output)) ++ ++ def testTranslations(self): ++ root = util.ParseGrdForUnittest(""" ++ ++ Hello! ++ Hello %s ++ Joi ++ ++ """) ++ ++ buf = StringIO() ++ build.RcBuilder.ProcessNode(root, DummyOutput('chrome_messages_json', 'fr'), ++ buf) ++ output = buf.getvalue() ++ test = u""" ++{ ++ "ID_HELLO": { ++ "message": "H\u00e9P\u00e9ll\u00f4P\u00f4!" ++ }, ++ "ID_HELLO_USER": { ++ "message": "H\u00e9P\u00e9ll\u00f4P\u00f4 %s" ++ } ++} ++""" ++ self.assertEqual(json.loads(test), json.loads(output)) ++ ++ def testSkipMissingTranslations(self): ++ grd = """ ++ ++ ++ ++ ++ ++ Hello not translated ++ ++ ++""" ++ root = grd_reader.Parse(StringIO(grd), dir=".") ++ ++ buf = StringIO() ++ build.RcBuilder.ProcessNode(root, DummyOutput('chrome_messages_json', 'fr'), ++ buf) ++ output = buf.getvalue() ++ test = u'{}' ++ self.assertEqual(test, output) ++ ++ def testVerifyMinification(self): ++ root = util.ParseGrdForUnittest(u""" ++ ++ ++ $1atest$2b ++ ++ ++ """) ++ ++ buf = StringIO() ++ build.RcBuilder.ProcessNode(root, DummyOutput('chrome_messages_json', 'en'), ++ buf) ++ output = buf.getvalue() ++ test = (u'{"IDS":{"message":"$1$test$2$","placeholders":' ++ u'{"1":{"content":"$1"},"2":{"content":"$2"}}}}') ++ self.assertEqual(test, output) ++ ++ ++class DummyOutput(object): ++ ++ def __init__(self, type, language): ++ self.type = type ++ self.language = language ++ ++ def GetType(self): ++ return self.type ++ ++ def GetLanguage(self): ++ return self.language ++ ++ def GetOutputFilename(self): ++ return 'hello.gif' + -+#include -+#include + -+// See crbug.com/136863. ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/format/data_pack.py b/tools/grit/grit/format/data_pack.py +new file mode 100644 +index 0000000000..f7128a4725 +--- /dev/null ++++ b/tools/grit/grit/format/data_pack.py +@@ -0,0 +1,321 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+class Foo { -+ class Bar { -+ Bar() {} -+ ~Bar() {} ++"""Support for formatting a data pack file used for platform agnostic resource ++files. ++""" + -+ std::vector a; -+ }; -+}; ++from __future__ import print_function + -+#endif // NESTED_CLASS_INLINE_CTOR_H_ -diff --git a/tools/clang/plugins/tests/nested_class_inline_ctor.txt b/tools/clang/plugins/tests/nested_class_inline_ctor.txt ++import collections ++import os ++import struct ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import six ++ ++from grit import util ++from grit.node import include ++from grit.node import message ++from grit.node import structure ++ ++ ++PACK_FILE_VERSION = 5 ++BINARY, UTF8, UTF16 = range(3) ++ ++ ++GrdInfoItem = collections.namedtuple('GrdInfoItem', ++ ['textual_id', 'id', 'path']) ++ ++ ++class WrongFileVersion(Exception): ++ pass ++ ++ ++class CorruptDataPack(Exception): ++ pass ++ ++ ++class DataPackSizes(object): ++ def __init__(self, header, id_table, alias_table, data): ++ self.header = header ++ self.id_table = id_table ++ self.alias_table = alias_table ++ self.data = data ++ ++ @property ++ def total(self): ++ return sum(v for v in self.__dict__.values()) ++ ++ def __iter__(self): ++ yield ('header', self.header) ++ yield ('id_table', self.id_table) ++ yield ('alias_table', self.alias_table) ++ yield ('data', self.data) ++ ++ def __eq__(self, other): ++ return self.__dict__ == other.__dict__ ++ ++ def __repr__(self): ++ return self.__class__.__name__ + repr(self.__dict__) ++ ++ ++class DataPackContents(object): ++ def __init__(self, resources, encoding, version, aliases, sizes): ++ # Map of resource_id -> str. ++ self.resources = resources ++ # Encoding (int). ++ self.encoding = encoding ++ # Version (int). ++ self.version = version ++ # Map of resource_id->canonical_resource_id ++ self.aliases = aliases ++ # DataPackSizes instance. ++ self.sizes = sizes ++ ++ ++def Format(root, lang='en', output_dir='.'): ++ """Writes out the data pack file format (platform agnostic resource file).""" ++ id_map = root.GetIdMap() ++ data = {} ++ root.info = [] ++ for node in root.ActiveDescendants(): ++ with node: ++ if isinstance(node, (include.IncludeNode, message.MessageNode, ++ structure.StructureNode)): ++ value = node.GetDataPackValue(lang, util.BINARY) ++ if value is not None: ++ resource_id = id_map[node.GetTextualIds()[0]] ++ data[resource_id] = value ++ root.info.append('{},{},{}'.format( ++ node.attrs.get('name'), resource_id, node.source)) ++ return WriteDataPackToString(data, UTF8) ++ ++ ++def ReadDataPack(input_file): ++ return ReadDataPackFromString(util.ReadFile(input_file, util.BINARY)) ++ ++ ++def ReadDataPackFromString(data): ++ """Reads a data pack file and returns a dictionary.""" ++ # Read the header. ++ version = struct.unpack('data in the data pack format.""" ++ ret = [] ++ ++ # Compute alias map. ++ resource_ids = sorted(resources) ++ # Use reversed() so that for duplicates lower IDs clobber higher ones. ++ id_by_data = {resources[k]: k for k in reversed(resource_ids)} ++ # Map of resource_id -> resource_id, where value < key. ++ alias_map = {k: id_by_data[v] for k, v in resources.items() ++ if id_by_data[v] != k} ++ ++ # Write file header. ++ resource_count = len(resources) - len(alias_map) ++ # Padding bytes added for alignment. ++ ret.append(struct.pack('data into output_file as a data pack.""" ++ content = WriteDataPackToString(resources, encoding) ++ with open(output_file, 'wb') as file: ++ file.write(content) ++ ++ ++def ReadGrdInfo(grd_file): ++ info_dict = {} ++ with open(grd_file + '.info', 'rt') as f: ++ for line in f: ++ item = GrdInfoItem._make(line.strip().split(',')) ++ info_dict[int(item.id)] = item ++ return info_dict ++ ++ ++def RePack(output_file, input_files, whitelist_file=None, ++ suppress_removed_key_output=False, ++ output_info_filepath=None): ++ """Write a new data pack file by combining input pack files. ++ ++ Args: ++ output_file: path to the new data pack file. ++ input_files: a list of paths to the data pack files to combine. ++ whitelist_file: path to the file that contains the list of resource IDs ++ that should be kept in the output file or None to include ++ all resources. ++ suppress_removed_key_output: allows the caller to suppress the output from ++ RePackFromDataPackStrings. ++ output_info_file: If not None, specify the output .info filepath. ++ ++ Raises: ++ KeyError: if there are duplicate keys or resource encoding is ++ inconsistent. ++ """ ++ input_data_packs = [ReadDataPack(filename) for filename in input_files] ++ input_info_files = [filename + '.info' for filename in input_files] ++ whitelist = None ++ if whitelist_file: ++ lines = util.ReadFile(whitelist_file, 'utf-8').strip().splitlines() ++ if not lines: ++ raise Exception('Whitelist file should not be empty') ++ whitelist = set(int(x) for x in lines) ++ inputs = [(p.resources, p.encoding) for p in input_data_packs] ++ resources, encoding = RePackFromDataPackStrings( ++ inputs, whitelist, suppress_removed_key_output) ++ WriteDataPack(resources, output_file, encoding) ++ if output_info_filepath is None: ++ output_info_filepath = output_file + '.info' ++ with open(output_info_filepath, 'w') as output_info_file: ++ for filename in input_info_files: ++ with open(filename, 'r') as info_file: ++ output_info_file.writelines(info_file.readlines()) ++ ++ ++def RePackFromDataPackStrings(inputs, whitelist, ++ suppress_removed_key_output=False): ++ """Combines all inputs into one. ++ ++ Args: ++ inputs: a list of (resources_by_id, encoding) tuples to be combined. ++ whitelist: a list of resource IDs that should be kept in the output string ++ or None to include all resources. ++ suppress_removed_key_output: Do not print removed keys. ++ ++ Returns: ++ Returns (resources_by_id, encoding). ++ ++ Raises: ++ KeyError: if there are duplicate keys or resource encoding is ++ inconsistent. ++ """ ++ resources = {} ++ encoding = None ++ for input_resources, input_encoding in inputs: ++ # Make sure we have no dups. ++ duplicate_keys = set(input_resources.keys()) & set(resources.keys()) ++ if duplicate_keys: ++ raise KeyError('Duplicate keys: ' + str(list(duplicate_keys))) ++ ++ # Make sure encoding is consistent. ++ if encoding in (None, BINARY): ++ encoding = input_encoding ++ elif input_encoding not in (BINARY, encoding): ++ raise KeyError('Inconsistent encodings: ' + str(encoding) + ++ ' vs ' + str(input_encoding)) ++ ++ if whitelist: ++ whitelisted_resources = dict([(key, input_resources[key]) ++ for key in input_resources.keys() ++ if key in whitelist]) ++ resources.update(whitelisted_resources) ++ removed_keys = [key for key in input_resources.keys() ++ if key not in whitelist] ++ if not suppress_removed_key_output: ++ for key in removed_keys: ++ print('RePackFromDataPackStrings Removed Key:', key) ++ else: ++ resources.update(input_resources) ++ ++ # Encoding is 0 for BINARY, 1 for UTF8 and 2 for UTF16 ++ if encoding is None: ++ encoding = BINARY ++ return resources, encoding ++ ++ ++def main(): ++ # Write a simple file. ++ data = {1: '', 4: 'this is id 4', 6: 'this is id 6', 10: ''} ++ WriteDataPack(data, 'datapack1.pak', UTF8) ++ data2 = {1000: 'test', 5: 'five'} ++ WriteDataPack(data2, 'datapack2.pak', UTF8) ++ print('wrote datapack1 and datapack2 to current directory.') ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/tools/grit/grit/format/data_pack_unittest.py b/tools/grit/grit/format/data_pack_unittest.py new file mode 100644 -index 0000000000..39bd6e1dce +index 0000000000..fcd7035473 --- /dev/null -+++ b/tools/clang/plugins/tests/nested_class_inline_ctor.txt -@@ -0,0 +1,8 @@ -+In file included from nested_class_inline_ctor.cpp:5: -+./nested_class_inline_ctor.h:15:5: warning: [chromium-style] Complex constructor has an inlined body. -+ Bar() {} -+ ^ -+./nested_class_inline_ctor.h:16:5: warning: [chromium-style] Complex destructor has an inline body. -+ ~Bar() {} -+ ^ -+2 warnings generated. -diff --git a/tools/clang/plugins/tests/overridden_methods.cpp b/tools/clang/plugins/tests/overridden_methods.cpp -new file mode 100644 -index 0000000000..f572a41733 ---- /dev/null -+++ b/tools/clang/plugins/tests/overridden_methods.cpp -@@ -0,0 +1,38 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. ++++ b/tools/grit/grit/format/data_pack_unittest.py +@@ -0,0 +1,102 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+#include "overridden_methods.h" ++'''Unit tests for grit.format.data_pack''' + -+// Fill in the implementations -+void DerivedClass::SomeMethod() {} -+void DerivedClass::SomeOtherMethod() {} -+void DerivedClass::WebKitModifiedSomething() {} ++from __future__ import print_function + -+class ImplementationInterimClass : public BaseClass { -+ public: -+ // Should not warn about pure virtual methods. -+ virtual void SomeMethod() = 0; -+}; ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++from grit.format import data_pack ++ ++ ++class FormatDataPackUnittest(unittest.TestCase): ++ def testReadDataPackV4(self): ++ expected_data = ( ++ b'\x04\x00\x00\x00' # header(version ++ b'\x04\x00\x00\x00' # no. entries, ++ b'\x01' # encoding) ++ b'\x01\x00\x27\x00\x00\x00' # index entry 1 ++ b'\x04\x00\x27\x00\x00\x00' # index entry 4 ++ b'\x06\x00\x33\x00\x00\x00' # index entry 6 ++ b'\x0a\x00\x3f\x00\x00\x00' # index entry 10 ++ b'\x00\x00\x3f\x00\x00\x00' # extra entry for the size of last ++ b'this is id 4this is id 6') # data ++ expected_data_pack = data_pack.DataPackContents( ++ { ++ 1: b'', ++ 4: b'this is id 4', ++ 6: b'this is id 6', ++ 10: b'', ++ }, data_pack.UTF8, 4, {}, data_pack.DataPackSizes(9, 30, 0, 24)) ++ loaded = data_pack.ReadDataPackFromString(expected_data) ++ self.assertDictEqual(expected_data_pack.__dict__, loaded.__dict__) ++ ++ def testReadWriteDataPackV5(self): ++ expected_data = ( ++ b'\x05\x00\x00\x00' # version ++ b'\x01\x00\x00\x00' # encoding & padding ++ b'\x03\x00' # resource_count ++ b'\x01\x00' # alias_count ++ b'\x01\x00\x28\x00\x00\x00' # index entry 1 ++ b'\x04\x00\x28\x00\x00\x00' # index entry 4 ++ b'\x06\x00\x34\x00\x00\x00' # index entry 6 ++ b'\x00\x00\x40\x00\x00\x00' # extra entry for the size of last ++ b'\x0a\x00\x01\x00' # alias table ++ b'this is id 4this is id 6') # data ++ input_resources = { ++ 1: b'', ++ 4: b'this is id 4', ++ 6: b'this is id 6', ++ 10: b'this is id 4', ++ } ++ data = data_pack.WriteDataPackToString(input_resources, data_pack.UTF8) ++ self.assertEquals(data, expected_data) ++ ++ expected_data_pack = data_pack.DataPackContents({ ++ 1: b'', ++ 4: input_resources[4], ++ 6: input_resources[6], ++ 10: input_resources[4], ++ }, data_pack.UTF8, 5, {10: 4}, data_pack.DataPackSizes(12, 24, 4, 24)) ++ loaded = data_pack.ReadDataPackFromString(expected_data) ++ self.assertDictEqual(expected_data_pack.__dict__, loaded.__dict__) ++ ++ def testRePackUnittest(self): ++ expected_with_whitelist = { ++ 1: 'Never gonna', 10: 'give you up', 20: 'Never gonna let', ++ 30: 'you down', 40: 'Never', 50: 'gonna run around and', ++ 60: 'desert you'} ++ expected_without_whitelist = { ++ 1: 'Never gonna', 10: 'give you up', 20: 'Never gonna let', 65: 'Close', ++ 30: 'you down', 40: 'Never', 50: 'gonna run around and', 4: 'click', ++ 60: 'desert you', 6: 'chirr', 32: 'oops, try again', 70: 'Awww, snap!'} ++ inputs = [{1: 'Never gonna', 4: 'click', 6: 'chirr', 10: 'give you up'}, ++ {20: 'Never gonna let', 30: 'you down', 32: 'oops, try again'}, ++ {40: 'Never', 50: 'gonna run around and', 60: 'desert you'}, ++ {65: 'Close', 70: 'Awww, snap!'}] ++ whitelist = [1, 10, 20, 30, 40, 50, 60] ++ inputs = [(i, data_pack.UTF8) for i in inputs] ++ ++ # RePack using whitelist ++ output, _ = data_pack.RePackFromDataPackStrings( ++ inputs, whitelist, suppress_removed_key_output=True) ++ self.assertDictEqual(expected_with_whitelist, output, ++ 'Incorrect resource output') ++ ++ # RePack a None whitelist ++ output, _ = data_pack.RePackFromDataPackStrings( ++ inputs, None, suppress_removed_key_output=True) ++ self.assertDictEqual(expected_without_whitelist, output, ++ 'Incorrect resource output') + -+class ImplementationDerivedClass : public ImplementationInterimClass, -+ public webkit_glue::WebKitObserverImpl { -+ public: -+ // Should not warn about destructors. -+ virtual ~ImplementationDerivedClass() {} -+ // Should warn. -+ virtual void SomeMethod(); -+ // Should not warn if marked as override. -+ virtual void SomeOtherMethod() override; -+ // Should not warn for inline implementations in implementation files. -+ virtual void SomeInlineMethod() {} -+ // Should not warn if overriding a method whose origin is WebKit. -+ virtual void WebKitModifiedSomething(); -+ // Should warn if overridden method isn't pure. -+ virtual void SomeNonPureBaseMethod() {} -+}; + -+int main() { -+ DerivedClass something; -+ ImplementationDerivedClass something_else; -+} -diff --git a/tools/clang/plugins/tests/overridden_methods.h b/tools/clang/plugins/tests/overridden_methods.h ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/format/gen_predetermined_ids.py b/tools/grit/grit/format/gen_predetermined_ids.py new file mode 100644 -index 0000000000..150c79913f +index 0000000000..9b2aa7b1a5 --- /dev/null -+++ b/tools/clang/plugins/tests/overridden_methods.h -@@ -0,0 +1,54 @@ -+// Copyright (c) 2011 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#ifndef OVERRIDDEN_METHODS_H_ -+#define OVERRIDDEN_METHODS_H_ -+ -+// Should warn about overriding of methods. -+class BaseClass { -+ public: -+ virtual ~BaseClass() {} -+ virtual void SomeMethod() = 0; -+ virtual void SomeOtherMethod() = 0; -+ virtual void SomeInlineMethod() = 0; -+ virtual void SomeNonPureBaseMethod() {} -+}; ++++ b/tools/grit/grit/format/gen_predetermined_ids.py +@@ -0,0 +1,144 @@ ++#!/usr/bin/env python ++# Copyright 2017 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. + -+class InterimClass : public BaseClass { -+ // Should not warn about pure virtual methods. -+ virtual void SomeMethod() = 0; -+}; ++""" ++A tool to generate a predetermined resource ids file that can be used as an ++input to grit via the -p option. This is meant to be run manually every once in ++a while and its output checked in. See tools/gritsettings/README.md for details. ++""" + -+namespace WebKit { -+class WebKitObserver { -+ public: -+ virtual void WebKitModifiedSomething() {}; -+}; -+} // namespace WebKit ++from __future__ import print_function + -+namespace webkit_glue { -+class WebKitObserverImpl : WebKit::WebKitObserver { -+ public: -+ virtual void WebKitModifiedSomething() {}; -+}; -+} // namespace webkit_glue -+ -+class DerivedClass : public InterimClass, -+ public webkit_glue::WebKitObserverImpl { -+ public: -+ // Should not warn about destructors. -+ virtual ~DerivedClass() {} -+ // Should warn. -+ virtual void SomeMethod(); -+ // Should not warn if marked as override. -+ virtual void SomeOtherMethod() override; -+ // Should warn for inline implementations. -+ virtual void SomeInlineMethod() {} -+ // Should not warn if overriding a method whose origin is WebKit. -+ virtual void WebKitModifiedSomething(); -+ // Should warn if overridden method isn't pure. -+ virtual void SomeNonPureBaseMethod() {} -+}; ++import os ++import re ++import sys + -+#endif // OVERRIDDEN_METHODS_H_ -diff --git a/tools/clang/plugins/tests/overridden_methods.txt b/tools/clang/plugins/tests/overridden_methods.txt -new file mode 100644 -index 0000000000..7553ade70e ---- /dev/null -+++ b/tools/clang/plugins/tests/overridden_methods.txt -@@ -0,0 +1,20 @@ -+In file included from overridden_methods.cpp:5: -+./overridden_methods.h:43:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE. -+ virtual void SomeMethod(); -+ ^ -+./overridden_methods.h:47:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE. -+ virtual void SomeInlineMethod() {} -+ ^ -+./overridden_methods.h:51:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE. -+ virtual void SomeNonPureBaseMethod() {} -+ ^ -+overridden_methods.cpp:24:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE. -+ virtual void SomeMethod(); -+ ^ -+overridden_methods.cpp:28:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE. -+ virtual void SomeInlineMethod() {} -+ ^ -+overridden_methods.cpp:32:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE. -+ virtual void SomeNonPureBaseMethod() {} -+ ^ -+6 warnings generated. -diff --git a/tools/clang/plugins/tests/test.sh b/tools/clang/plugins/tests/test.sh -new file mode 100755 -index 0000000000..262ebbba29 ---- /dev/null -+++ b/tools/clang/plugins/tests/test.sh -@@ -0,0 +1,72 @@ -+#!/bin/bash -+# -+# Copyright (c) 2011 The Chromium Authors. All rights reserved. ++# Regular expression for parsing the #define macro format. Matches both the ++# version of the macro with whitelist support and the one without. For example, ++# Without generate whitelist flag: ++# #define IDS_FOO_MESSAGE 1234 ++# With generate whitelist flag: ++# #define IDS_FOO_MESSAGE (::ui::WhitelistedResource<1234>(), 1234) ++RESOURCE_EXTRACT_REGEX = re.compile(r'^#define (\S*).* (\d+)\)?$', re.MULTILINE) ++ ++ORDERED_RESOURCE_IDS_REGEX = re.compile(r'^Resource=(\d*)$', re.MULTILINE) ++ ++ ++def _GetResourceNameIdPairsIter(string_to_scan): ++ """Gets an iterator of the resource name and id pairs of the given string. ++ ++ Scans the input string for lines of the form "#define NAME ID" and returns ++ an iterator over all matching (NAME, ID) pairs. ++ ++ Args: ++ string_to_scan: The input string to scan. ++ ++ Yields: ++ A tuple of name and id. ++ """ ++ for match in RESOURCE_EXTRACT_REGEX.finditer(string_to_scan): ++ yield match.group(1, 2) ++ ++ ++def _ReadOrderedResourceIds(path): ++ """Reads ordered resource ids from the given file. ++ ++ The resources are expected to be of the format produced by running Chrome ++ with --print-resource-ids command line. ++ ++ Args: ++ path: File path to read resource ids from. ++ ++ Returns: ++ An array of ordered resource ids. ++ """ ++ ordered_resource_ids = [] ++ with open(path, "r") as f: ++ for match in ORDERED_RESOURCE_IDS_REGEX.finditer(f.read()): ++ ordered_resource_ids.append(int(match.group(1))) ++ return ordered_resource_ids ++ ++ ++def GenerateResourceMapping(original_resources, ordered_resource_ids): ++ """Generates a resource mapping from the ordered ids and the original mapping. ++ ++ The returned dict will assign new ids to ordered_resource_ids numerically ++ increasing from 101. ++ ++ Args: ++ original_resources: A dict of original resource ids to resource names. ++ ordered_resource_ids: An array of ordered resource ids. ++ ++ Returns: ++ A dict of resource ids to resource names. ++ """ ++ output_resource_map = {} ++ # 101 is used as the starting value since other parts of GRIT require it to be ++ # the minimum (e.g. rc_header.py) based on Windows resource numbering. ++ next_id = 101 ++ for original_id in ordered_resource_ids: ++ resource_name = original_resources[original_id] ++ output_resource_map[next_id] = resource_name ++ next_id += 1 ++ return output_resource_map ++ ++ ++def ReadResourceIdsFromFile(file, original_resources): ++ """Reads resource ids from a GRIT-produced header file. ++ ++ Args: ++ file: File to a GRIT-produced header file to read from. ++ original_resources: Dict of resource ids to resource names to add to. ++ """ ++ for resource_name, resource_id in _GetResourceNameIdPairsIter(file.read()): ++ original_resources[int(resource_id)] = resource_name ++ ++ ++def _ReadOriginalResourceIds(out_dir): ++ """Reads resource ids from GRIT header files in the specified directory. ++ ++ Args: ++ out_dir: A Chrome build output directory (e.g. out/gn) to scan. ++ ++ Returns: ++ A dict of resource ids to resource names. ++ """ ++ original_resources = {} ++ for root, dirnames, filenames in os.walk(out_dir + '/gen'): ++ for filename in filenames: ++ if filename.endswith(('_resources.h', '_settings.h', '_strings.h')): ++ with open(os.path.join(root, filename), "r") as f: ++ ReadResourceIdsFromFile(f, original_resources) ++ return original_resources ++ ++ ++def _GeneratePredeterminedIdsFile(ordered_resources_file, out_dir): ++ """Generates a predetermined ids file. ++ ++ Args: ++ ordered_resources_file: File path to read ordered resource ids from. ++ out_dir: A Chrome build output directory (e.g. out/gn) to scan. ++ ++ Returns: ++ A dict of resource ids to resource names. ++ """ ++ original_resources = _ReadOriginalResourceIds(out_dir) ++ ordered_resource_ids = _ReadOrderedResourceIds(ordered_resources_file) ++ output_resource_map = GenerateResourceMapping(original_resources, ++ ordered_resource_ids) ++ for res_id in sorted(output_resource_map.keys()): ++ print(output_resource_map[res_id], res_id) ++ ++ ++def main(argv): ++ if len(argv) != 2: ++ print("usage: gen_predetermined_ids.py ") ++ sys.exit(1) ++ ordered_resources_file, out_dir = argv[0], argv[1] ++ _GeneratePredeterminedIdsFile(ordered_resources_file, out_dir) ++ ++ ++if '__main__' == __name__: ++ main(sys.argv[1:]) +diff --git a/tools/grit/grit/format/gen_predetermined_ids_unittest.py b/tools/grit/grit/format/gen_predetermined_ids_unittest.py +new file mode 100644 +index 0000000000..bd0331adb4 +--- /dev/null ++++ b/tools/grit/grit/format/gen_predetermined_ids_unittest.py +@@ -0,0 +1,46 @@ ++#!/usr/bin/env python ++# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. -+# -+# Hacky, primitive testing: This runs the style plugin for a set of input files -+# and compares the output with golden result files. -+ -+E_BADARGS=65 -+E_FAILEDTEST=1 -+ -+failed_any_test= -+ -+# Prints usage information. -+usage() { -+ echo "Usage: $(basename "${0}")" \ -+ "" -+ echo "" -+ echo " Runs all the libFindBadConstructs unit tests" -+ echo "" -+} -+ -+# Runs a single test case. -+do_testcase() { -+ local output="$("${CLANG_DIR}"/bin/clang -c -Wno-c++11-extensions \ -+ -Xclang -load -Xclang "${CLANG_DIR}"/lib/libFindBadConstructs.${LIB} \ -+ -Xclang -plugin -Xclang find-bad-constructs ${1} 2>&1)" -+ local diffout="$(echo "${output}" | diff - "${2}")" -+ if [ "${diffout}" = "" ]; then -+ echo "PASS: ${1}" -+ else -+ failed_any_test=yes -+ echo "FAIL: ${1}" -+ echo "Output of compiler:" -+ echo "${output}" -+ echo "Expected output:" -+ cat "${2}" -+ echo -+ fi -+} -+ -+# Validate input to the script. -+if [[ -z "${1}" ]]; then -+ usage -+ exit ${E_BADARGS} -+elif [[ ! -d "${1}" ]]; then -+ echo "${1} is not a directory." -+ usage -+ exit ${E_BADARGS} -+else -+ export CLANG_DIR="${PWD}/${1}" -+ echo "Using clang directory ${CLANG_DIR}..." -+ -+ # The golden files assume that the cwd is this directory. To make the script -+ # work no matter what the cwd is, explicitly cd to there. -+ cd "$(dirname "${0}")" -+ -+ if [ "$(uname -s)" = "Linux" ]; then -+ export LIB=so -+ elif [ "$(uname -s)" = "Darwin" ]; then -+ export LIB=dylib -+ fi -+fi -+ -+for input in *.cpp; do -+ do_testcase "${input}" "${input%cpp}txt" -+done -+ -+if [[ "${failed_any_test}" ]]; then -+ exit ${E_FAILEDTEST} -+fi -diff --git a/tools/clang/plugins/tests/virtual_methods.cpp b/tools/clang/plugins/tests/virtual_methods.cpp -new file mode 100644 -index 0000000000..a07cbe4875 ---- /dev/null -+++ b/tools/clang/plugins/tests/virtual_methods.cpp -@@ -0,0 +1,36 @@ -+// Copyright (c) 2012 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#include "virtual_methods.h" -+ -+// Shouldn't warn about method usage in the implementation file. -+class VirtualMethodsInImplementation { -+ public: -+ virtual void MethodIsAbstract() = 0; -+ virtual void MethodHasNoArguments(); -+ virtual void MethodHasEmptyDefaultImpl() {} -+ virtual bool ComplainAboutThis() { return true; } -+}; + -+// Stubs to fill in the abstract method -+class ConcreteVirtualMethodsInHeaders : public VirtualMethodsInHeaders { -+ public: -+ virtual void MethodIsAbstract() override {} -+}; ++'''Unit tests for the gen_predetermined_ids module.''' + -+class ConcreteVirtualMethodsInImplementation -+ : public VirtualMethodsInImplementation { -+ public: -+ virtual void MethodIsAbstract() override {} -+}; ++from __future__ import print_function + -+// Fill in the implementations -+void VirtualMethodsInHeaders::MethodHasNoArguments() {} -+void WarnOnMissingVirtual::MethodHasNoArguments() {} -+void VirtualMethodsInImplementation::MethodHasNoArguments() {} ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) + -+int main() { -+ ConcreteVirtualMethodsInHeaders one; -+ ConcreteVirtualMethodsInImplementation two; -+} -diff --git a/tools/clang/plugins/tests/virtual_methods.h b/tools/clang/plugins/tests/virtual_methods.h ++import unittest ++ ++from six import StringIO ++ ++from grit.format import gen_predetermined_ids ++ ++class GenPredeterminedIdsUnittest(unittest.TestCase): ++ def testGenerateResourceMapping(self): ++ original_resources = {200: 'A', 201: 'B', 300: 'C', 350: 'D', 370: 'E'} ++ ordered_resource_ids = [300, 201, 370] ++ mapping = gen_predetermined_ids.GenerateResourceMapping( ++ original_resources, ordered_resource_ids) ++ self.assertEqual({101: 'C', 102: 'B', 103: 'E'}, mapping) ++ ++ def testReadResourceIdsFromFile(self): ++ f = StringIO(''' ++// This file is automatically generated by GRIT. Do not edit. ++ ++#pragma once ++ ++#define IDS_BOOKMARKS_NO_ITEMS 12500 ++#define IDS_BOOKMARK_BAR_IMPORT_LINK (::ui::WhitelistedResource<12501>(), 12501) ++#define IDS_BOOKMARK_X (::ui::WhitelistedResource<12502>(), 12502) ++''') ++ resources = {} ++ gen_predetermined_ids.ReadResourceIdsFromFile(f, resources) ++ self.assertEqual({12500: 'IDS_BOOKMARKS_OPEN_ALL', ++ 12501: 'IDS_BOOKMARKS_OPEN_ALL_INCOGNITO', ++ 12502: 'IDS_BOOKMARK_X'}, resources) ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/format/gzip_string.py b/tools/grit/grit/format/gzip_string.py new file mode 100644 -index 0000000000..d9fbf96ed3 +index 0000000000..3cd17185c9 --- /dev/null -+++ b/tools/clang/plugins/tests/virtual_methods.h -@@ -0,0 +1,39 @@ -+// Copyright (c) 2011 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#ifndef VIRTUAL_METHODS_H_ -+#define VIRTUAL_METHODS_H_ -+ -+// Should warn about virtual method usage. -+class VirtualMethodsInHeaders { -+ public: -+ // Don't complain about these. -+ virtual void MethodIsAbstract() = 0; -+ virtual void MethodHasNoArguments(); -+ virtual void MethodHasEmptyDefaultImpl() {} -+ -+ // But complain about this: -+ virtual bool ComplainAboutThis() { return true; } -+}; ++++ b/tools/grit/grit/format/gzip_string.py +@@ -0,0 +1,46 @@ ++# Copyright (c) 2016 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++"""Provides gzip utilities for strings. ++""" + -+// Complain on missing 'virtual' keyword in overrides. -+class WarnOnMissingVirtual : public VirtualMethodsInHeaders { -+ public: -+ void MethodHasNoArguments() override; -+}; ++from __future__ import print_function + -+// Don't complain about things in a 'testing' namespace. -+namespace testing { -+struct TestStruct {}; -+} // namespace testing -+ -+class VirtualMethodsInHeadersTesting : public VirtualMethodsInHeaders { -+ public: -+ // Don't complain about no virtual testing methods. -+ void MethodHasNoArguments(); -+ private: -+ testing::TestStruct tester_; -+}; ++import gzip ++import io ++import subprocess + -+#endif // VIRTUAL_METHODS_H_ -diff --git a/tools/clang/plugins/tests/virtual_methods.txt b/tools/clang/plugins/tests/virtual_methods.txt ++ ++def GzipStringRsyncable(data): ++ # Make call to host system's gzip to get access to --rsyncable option. This ++ # option makes updates much smaller - if one line is changed in the resource, ++ # it won't have to push the entire compressed resource with the update. ++ # Instead, --rsyncable breaks the file into small chunks, so that one doesn't ++ # affect the other in compression, and then only that chunk will have to be ++ # updated. ++ gzip_proc = subprocess.Popen(['gzip', '--stdout', '--rsyncable', ++ '--best', '--no-name'], ++ stdin=subprocess.PIPE, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE) ++ data, stderr = gzip_proc.communicate(data) ++ if gzip_proc.returncode != 0: ++ raise subprocess.CalledProcessError(gzip_proc.returncode, 'gzip', ++ stderr) ++ return data ++ ++ ++def GzipString(data): ++ # Gzipping using Python's built in gzip: Windows doesn't ship with gzip, and ++ # OSX's gzip does not have an --rsyncable option built in. Although this is ++ # not preferable to --rsyncable, it is an option for the systems that do ++ # not have --rsyncable. If used over GzipStringRsyncable, the primary ++ # difference of this function's compression will be larger updates every time ++ # a compressed resource is changed. ++ gzip_output = io.BytesIO() ++ with gzip.GzipFile(mode='wb', compresslevel=9, fileobj=gzip_output, ++ mtime=0) as gzip_file: ++ gzip_file.write(data) ++ data = gzip_output.getvalue() ++ gzip_output.close() ++ return data +diff --git a/tools/grit/grit/format/gzip_string_unittest.py b/tools/grit/grit/format/gzip_string_unittest.py new file mode 100644 -index 0000000000..571d6d667d +index 0000000000..c0cfbe1837 --- /dev/null -+++ b/tools/clang/plugins/tests/virtual_methods.txt -@@ -0,0 +1,8 @@ -+In file included from virtual_methods.cpp:5: -+./virtual_methods.h:17:36: warning: [chromium-style] virtual methods with non-empty bodies shouldn't be declared inline. -+ virtual bool ComplainAboutThis() { return true; } -+ ^ -+./virtual_methods.h:23:3: warning: [chromium-style] Overriding method must have "virtual" keyword. -+ void MethodHasNoArguments() override; -+ ^ -+2 warnings generated. -diff --git a/tools/clang/scripts/package.sh b/tools/clang/scripts/package.sh -new file mode 100755 -index 0000000000..eb345810b9 ---- /dev/null -+++ b/tools/clang/scripts/package.sh -@@ -0,0 +1,87 @@ -+#!/bin/bash -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+# This script will check out llvm and clang, and then package the results up -+# to a tgz file. -+ -+THIS_DIR="$(dirname "${0}")" -+LLVM_DIR="${THIS_DIR}/../../../third_party/llvm" -+LLVM_BOOTSTRAP_DIR="${THIS_DIR}/../../../third_party/llvm-bootstrap" -+LLVM_BUILD_DIR="${THIS_DIR}/../../../third_party/llvm-build" -+LLVM_BIN_DIR="${LLVM_BUILD_DIR}/Release+Asserts/bin" -+LLVM_LIB_DIR="${LLVM_BUILD_DIR}/Release+Asserts/lib" -+ -+echo "Diff in llvm:" | tee buildlog.txt -+svn stat "${LLVM_DIR}" 2>&1 | tee -a buildlog.txt -+svn diff "${LLVM_DIR}" 2>&1 | tee -a buildlog.txt -+echo "Diff in llvm/tools/clang:" | tee -a buildlog.txt -+svn stat "${LLVM_DIR}/tools/clang" 2>&1 | tee -a buildlog.txt -+svn diff "${LLVM_DIR}/tools/clang" 2>&1 | tee -a buildlog.txt -+echo "Diff in llvm/projects/compiler-rt:" | tee -a buildlog.txt -+svn stat "${LLVM_DIR}/projects/compiler-rt" 2>&1 | tee -a buildlog.txt -+svn diff "${LLVM_DIR}/projects/compiler-rt" 2>&1 | tee -a buildlog.txt -+ -+echo "Starting build" | tee -a buildlog.txt -+ -+set -ex -+ -+# Do a clobber build. -+rm -rf "${LLVM_BOOTSTRAP_DIR}" -+rm -rf "${LLVM_BUILD_DIR}" -+"${THIS_DIR}"/update.sh --run-tests --bootstrap --force-local-build 2>&1 | \ -+ tee -a buildlog.txt -+ -+R=$("${LLVM_BIN_DIR}/clang" --version | \ -+ sed -ne 's/clang version .*(trunk \([0-9]*\))/\1/p') -+ -+PDIR=clang-$R -+rm -rf $PDIR -+mkdir $PDIR -+mkdir $PDIR/bin -+mkdir $PDIR/lib -+ -+# Copy buildlog over. -+cp buildlog.txt $PDIR/ -+ -+# Copy clang into pdir, symlink clang++ to it. -+cp "${LLVM_BIN_DIR}/clang" $PDIR/bin/ -+(cd $PDIR/bin && ln -sf clang clang++ && cd -) -+ -+# Copy plugins. Some of the dylibs are pretty big, so copy only the ones we -+# care about. -+if [ "$(uname -s)" = "Darwin" ]; then -+ cp "${LLVM_LIB_DIR}/libFindBadConstructs.dylib" $PDIR/lib -+else -+ cp "${LLVM_LIB_DIR}/libFindBadConstructs.so" $PDIR/lib -+fi -+ -+# Copy built-in headers (lib/clang/3.2/include). -+# libcompiler-rt puts all kinds of libraries there too, but we want only ASan. -+if [ "$(uname -s)" = "Darwin" ]; then -+ # Keep only Release+Asserts/lib/clang/3.2/lib/darwin/libclang_rt.asan_osx.a -+ find "${LLVM_LIB_DIR}/clang" -type f -path '*lib/darwin*' | grep -v asan | \ -+ xargs rm -+else -+ # Keep only -+ # Release+Asserts/lib/clang/3.2/lib/linux/libclang_rt.{asan,tsan}-x86_64.a -+ # TODO(thakis): Make sure the 32bit version of ASan runtime is kept too once -+ # that's built. TSan runtime exists only for 64 bits. -+ find "${LLVM_LIB_DIR}/clang" -type f -path '*lib/linux*' | \ -+ grep -v "asan\|tsan" | xargs rm -+fi -+ -+cp -R "${LLVM_LIB_DIR}/clang" $PDIR/lib -+ -+tar zcf $PDIR.tgz -C $PDIR bin lib buildlog.txt -+ -+if [ "$(uname -s)" = "Darwin" ]; then -+ PLATFORM=Mac -+else -+ PLATFORM=Linux_x64 -+fi -+ -+echo To upload, run: -+echo gsutil cp -a public-read $PDIR.tgz \ -+ gs://chromium-browser-clang/$PLATFORM/$PDIR.tgz -diff --git a/tools/clang/scripts/plugin_flags.sh b/tools/clang/scripts/plugin_flags.sh -new file mode 100755 -index 0000000000..217c5c3bd6 ---- /dev/null -+++ b/tools/clang/scripts/plugin_flags.sh -@@ -0,0 +1,24 @@ -+#!/bin/bash -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++++ b/tools/grit/grit/format/gzip_string_unittest.py +@@ -0,0 +1,65 @@ ++#!/usr/bin/env python ++# Copyright (c) 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + -+# This script returns the flags that should be used when GYP_DEFINES contains -+# clang_use_chrome_plugins. The flags are stored in a script so that they can -+# be changed on the bots without requiring a master restart. ++'''Unit tests for grit.format.gzip_string''' ++ ++from __future__ import print_function ++ ++import gzip ++import io ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++from grit.format import gzip_string ++ ++ ++class FormatGzipStringUnittest(unittest.TestCase): ++ ++ def testGzipStringRsyncable(self): ++ # Can only test the rsyncable version on platforms which support rsyncable, ++ # which at the moment is Linux. ++ if sys.platform == 'linux2': ++ header_begin = (b'\x1f\x8b') # gzip first two bytes ++ input = (b'TEST STRING STARTING NOW' ++ b'continuing' ++ b'' ++ b'') + -+THIS_ABS_DIR=$(cd $(dirname $0) && echo $PWD) -+CLANG_LIB_PATH=$THIS_ABS_DIR/../../../third_party/llvm-build/Release+Asserts/lib ++ compressed = gzip_string.GzipStringRsyncable(input) ++ self.failUnless(header_begin == compressed[:2]) + -+if uname -s | grep -q Darwin; then -+ LIBSUFFIX=dylib -+else -+ LIBSUFFIX=so -+fi ++ compressed_file = io.BytesIO() ++ compressed_file.write(compressed) ++ compressed_file.seek(0) + -+echo -Xclang -load -Xclang $CLANG_LIB_PATH/libFindBadConstructs.$LIBSUFFIX \ -+ -Xclang -add-plugin -Xclang find-bad-constructs \ -+ -Xclang -plugin-arg-find-bad-constructs \ -+ -Xclang skip-virtuals-in-implementations \ -+ -Xclang -plugin-arg-find-bad-constructs \ -+ -Xclang check-cc-directory -diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py -new file mode 100755 -index 0000000000..bdc781f715 ++ with gzip.GzipFile(mode='rb', fileobj=compressed_file) as f: ++ output = f.read() ++ self.failUnless(output == input) ++ ++ def testGzipString(self): ++ header_begin = b'\x1f\x8b' # gzip first two bytes ++ input = (b'TEST STRING STARTING NOW' ++ b'continuing' ++ b'' ++ b'') ++ ++ compressed = gzip_string.GzipString(input) ++ self.failUnless(header_begin == compressed[:2]) ++ ++ compressed_file = io.BytesIO() ++ compressed_file.write(compressed) ++ compressed_file.seek(0) ++ ++ with gzip.GzipFile(mode='rb', fileobj=compressed_file) as f: ++ output = f.read() ++ self.failUnless(output == input) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/format/html_inline.py b/tools/grit/grit/format/html_inline.py +new file mode 100644 +index 0000000000..da55216ea4 --- /dev/null -+++ b/tools/clang/scripts/update.py -@@ -0,0 +1,34 @@ ++++ b/tools/grit/grit/format/html_inline.py +@@ -0,0 +1,602 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + -+"""Windows can't run .sh files, so this is a small python wrapper around -+update.sh. ++"""Flattens a HTML file by inlining its external resources. ++ ++This is a small script that takes a HTML file, looks for src attributes ++and inlines the specified file, producing one HTML file with no external ++dependencies. It recursively inlines the included files. +""" + ++from __future__ import print_function ++ +import os -+import subprocess ++import re +import sys ++import base64 ++import mimetypes ++ ++from grit import lazy_re ++from grit import util ++from grit.format import minifier ++ ++# There is a python bug that makes mimetypes crash if the Windows ++# registry contains non-Latin keys ( http://bugs.python.org/issue9291 ++# ). Initing manually and blocking external mime-type databases will ++# prevent that bug and if we add svg manually, it will still give us ++# the data we need. ++mimetypes.init([]) ++mimetypes.add_type('image/svg+xml', '.svg') ++ ++# webm video type is not always available if mimetype package is outdated. ++mimetypes.add_type('video/webm', '.webm') ++ ++DIST_DEFAULT = 'chromium' ++DIST_ENV_VAR = 'CHROMIUM_BUILD' ++DIST_SUBSTR = '%DISTRIBUTION%' ++ ++# Matches beginning of an "if" block. ++_BEGIN_IF_BLOCK = lazy_re.compile( ++ r']*?expr=("(?P[^">]*)"|\'(?P[^\'>]*)\')[^>]*?>') ++ ++# Matches ending of an "if" block. ++_END_IF_BLOCK = lazy_re.compile(r'') ++ ++# Used by DoInline to replace various links with inline content. ++_STYLESHEET_RE = lazy_re.compile( ++ r']+?href="(?P[^"]*)".*?>(\s*)?', ++ re.DOTALL) ++_INCLUDE_RE = lazy_re.compile( ++ r'(?P\/\/ )?]+?' ++ r'src=("(?P[^">]*)"|\'(?P[^\'>]*)\').*?>(\s*)?', ++ re.DOTALL) ++_SRC_RE = lazy_re.compile( ++ r'<(?!script)(?:[^>]+?\s)src="(?!\[\[|{{)(?P[^"\']*)"', ++ re.MULTILINE) ++# This re matches ']*?\s)srcset="(?!\[\[|{{|\$i18n{)' ++ r'(?P[^"\']*)"', ++ re.MULTILINE) ++# This re is for splitting srcset value string into "image candidate strings". ++# Notes: ++# - HTML 5.2 states that URL cannot start or end with comma. ++# - the "descriptor" is either "width descriptor" or "pixel density descriptor". ++# The first one consists of "valid non-negative integer + letter 'x'", ++# the second one is formed of "positive valid floating-point number + ++# letter 'w'". As a reasonable compromise, we match a list of characters ++# that form both of them. ++# Matches for example "img2.png 2x" or "img9.png 11E-2w". ++_SRCSET_ENTRY_RE = lazy_re.compile( ++ r'\s*(?P[^,\s]\S+[^,\s])' ++ r'(?:\s+(?P[\deE.-]+[wx]))?\s*' ++ r'(?P,|$)', ++ re.MULTILINE) ++_ICON_RE = lazy_re.compile( ++ r']+?\s)?' ++ r'href=(?P")(?P[^"\']*)\1', ++ re.MULTILINE) ++ ++ ++def GetDistribution(): ++ """Helper function that gets the distribution we are building. ++ ++ Returns: ++ string ++ """ ++ distribution = DIST_DEFAULT ++ if DIST_ENV_VAR in os.environ: ++ distribution = os.environ[DIST_ENV_VAR] ++ if len(distribution) > 1 and distribution[0] == '_': ++ distribution = distribution[1:].lower() ++ return distribution ++ ++def ConvertFileToDataURL(filename, base_path, distribution, inlined_files, ++ names_only): ++ """Convert filename to inlined data URI. ++ ++ Takes a filename from ether "src" or "srcset", and attempts to read the file ++ at 'filename'. Returns data URI as string with given file inlined. ++ If it finds DIST_SUBSTR string in file name, replaces it with distribution. ++ If filename contains ':', it is considered URL and not translated. ++ ++ Args: ++ filename: filename string from ether src or srcset attributes. ++ base_path: path that to look for files in ++ distribution: string that should replace DIST_SUBSTR ++ inlined_files: The name of the opened file is appended to this list. ++ names_only: If true, the function will not read the file but just return "". ++ It will still add the filename to |inlined_files|. ++ ++ Returns: ++ string ++ """ ++ if filename.find(':') != -1: ++ # filename is probably a URL, which we don't want to bother inlining ++ return filename ++ ++ filename = filename.replace(DIST_SUBSTR , distribution) ++ filepath = os.path.normpath(os.path.join(base_path, filename)) ++ inlined_files.add(filepath) ++ ++ if names_only: ++ return "" ++ ++ mimetype = mimetypes.guess_type(filename)[0] ++ if mimetype is None: ++ raise Exception('%s is of an an unknown type and ' ++ 'cannot be stored in a data url.' % filename) ++ inline_data = base64.standard_b64encode(util.ReadFile(filepath, util.BINARY)) ++ return 'data:%s;base64,%s' % (mimetype, inline_data.decode('utf-8')) ++ ++ ++def SrcInlineAsDataURL( ++ src_match, base_path, distribution, inlined_files, names_only=False, ++ filename_expansion_function=None): ++ """regex replace function. ++ ++ Takes a regex match for src="filename", attempts to read the file ++ at 'filename' and returns the src attribute with the file inlined ++ as a data URI. If it finds DIST_SUBSTR string in file name, replaces ++ it with distribution. ++ ++ Args: ++ src_match: regex match object with 'filename' named capturing group ++ base_path: path that to look for files in ++ distribution: string that should replace DIST_SUBSTR ++ inlined_files: The name of the opened file is appended to this list. ++ names_only: If true, the function will not read the file but just return "". ++ It will still add the filename to |inlined_files|. ++ ++ Returns: ++ string ++ """ ++ filename = src_match.group('filename') ++ if filename_expansion_function: ++ filename = filename_expansion_function(filename) ++ ++ data_url = ConvertFileToDataURL(filename, base_path, distribution, ++ inlined_files, names_only) ++ ++ if not data_url: ++ return data_url ++ ++ prefix = src_match.string[src_match.start():src_match.start('filename')] ++ suffix = src_match.string[src_match.end('filename'):src_match.end()] ++ return prefix + data_url + suffix ++ ++def SrcsetInlineAsDataURL( ++ srcset_match, base_path, distribution, inlined_files, names_only=False, ++ filename_expansion_function=None): ++ """regex replace function to inline files in srcset="..." attributes ++ ++ Takes a regex match for srcset="filename 1x, filename 2x, ...", attempts to ++ read the files referenced by filenames and returns the srcset attribute with ++ the files inlined as a data URI. If it finds DIST_SUBSTR string in file name, ++ replaces it with distribution. ++ ++ Args: ++ srcset_match: regex match object with 'srcset' named capturing group ++ base_path: path that to look for files in ++ distribution: string that should replace DIST_SUBSTR ++ inlined_files: The name of the opened file is appended to this list. ++ names_only: If true, the function will not read the file but just return "". ++ It will still add the filename to |inlined_files|. ++ ++ Returns: ++ string ++ """ ++ srcset = srcset_match.group('srcset') ++ ++ if not srcset: ++ return srcset_match.group(0) ++ ++ # HTML 5.2 defines srcset as a list of "image candidate strings". ++ # Each of them consists of URL and descriptor. ++ # _SRCSET_ENTRY_RE splits srcset into a list of URLs, descriptors and ++ # commas. ++ # The descriptor part will be None if that optional regex didn't match ++ parts = _SRCSET_ENTRY_RE.split(srcset) ++ ++ if not parts: ++ return srcset_match.group(0) ++ ++ # List of image candidate strings that will form new srcset="..." ++ new_candidates = [] ++ ++ # When iterating over split srcset we fill this parts of a single image ++ # candidate string: [url, descriptor] ++ candidate = []; ++ ++ # Each entry should consist of some text before the entry, the url, ++ # the descriptor or None if the entry has no descriptor, a comma separator or ++ # the end of the line, and finally some text after the entry (which is the ++ # same as the text before the next entry). ++ for i in range(0, len(parts) - 1, 4): ++ before, url, descriptor, separator, after = parts[i:i+5] ++ ++ # There must be a comma-separated next entry or this must be the last entry. ++ assert separator == "," or (separator == "" and i == len(parts) - 5), ( ++ "Bad srcset format in {}".format(srcset_match.group(0))) ++ # Both before and after the entry must be empty ++ assert before == after == "", ( ++ "Bad srcset format in {}".format(srcset_match.group(0))) ++ ++ if filename_expansion_function: ++ filename = filename_expansion_function(url) ++ else: ++ filename = url ++ ++ data_url = ConvertFileToDataURL(filename, base_path, distribution, ++ inlined_files, names_only) ++ ++ # This is not "names_only" mode ++ if data_url: ++ candidate = [data_url] ++ if descriptor: ++ candidate.append(descriptor) ++ ++ new_candidates.append(" ".join(candidate)) ++ ++ prefix = srcset_match.string[srcset_match.start(): ++ srcset_match.start('srcset')] ++ suffix = srcset_match.string[srcset_match.end('srcset'):srcset_match.end()] ++ return prefix + ','.join(new_candidates) + suffix ++ ++class InlinedData: ++ """Helper class holding the results from DoInline(). ++ ++ Holds the inlined data and the set of filenames of all the inlined ++ files. ++ """ ++ def __init__(self, inlined_data, inlined_files): ++ self.inlined_data = inlined_data ++ self.inlined_files = inlined_files ++ ++def DoInline( ++ input_filename, grd_node, allow_external_script=False, ++ preprocess_only=False, names_only=False, strip_whitespace=False, ++ rewrite_function=None, filename_expansion_function=None): ++ """Helper function that inlines the resources in a specified file. ++ ++ Reads input_filename, finds all the src attributes and attempts to ++ inline the files they are referring to, then returns the result and ++ the set of inlined files. ++ ++ Args: ++ input_filename: name of file to read in ++ grd_node: html node from the grd file for this include tag ++ preprocess_only: Skip all HTML processing, only handle and . ++ names_only: |nil| will be returned for the inlined contents (faster). ++ strip_whitespace: remove whitespace and comments in the input files. ++ rewrite_function: function(filepath, text, distribution) which will be ++ called to rewrite html content before inlining images. ++ filename_expansion_function: function(filename) which will be called to ++ rewrite filenames before attempting to read them. ++ Returns: ++ a tuple of the inlined data as a string and the set of filenames ++ of all the inlined files ++ """ ++ if filename_expansion_function: ++ input_filename = filename_expansion_function(input_filename) ++ input_filepath = os.path.dirname(input_filename) ++ distribution = GetDistribution() ++ ++ # Keep track of all the files we inline. ++ inlined_files = set() ++ ++ def SrcReplace(src_match, filepath=input_filepath, ++ inlined_files=inlined_files): ++ """Helper function to provide SrcInlineAsDataURL with the base file path""" ++ return SrcInlineAsDataURL( ++ src_match, filepath, distribution, inlined_files, names_only=names_only, ++ filename_expansion_function=filename_expansion_function) ++ ++ def SrcsetReplace(srcset_match, filepath=input_filepath, ++ inlined_files=inlined_files): ++ """Helper function to provide SrcsetInlineAsDataURL with the base file ++ path. ++ """ ++ return SrcsetInlineAsDataURL( ++ srcset_match, filepath, distribution, inlined_files, ++ names_only=names_only, ++ filename_expansion_function=filename_expansion_function) ++ ++ def GetFilepath(src_match, base_path = input_filepath): ++ filename = [v for k, v in src_match.groupdict().items() ++ if k.startswith('file') and v][0] ++ ++ if filename.find(':') != -1: ++ # filename is probably a URL, which we don't want to bother inlining ++ return None ++ ++ filename = filename.replace('%DISTRIBUTION%', distribution) ++ if filename_expansion_function: ++ filename = filename_expansion_function(filename) ++ return os.path.normpath(os.path.join(base_path, filename)) ++ ++ def IsConditionSatisfied(src_match): ++ expr1 = src_match.group('expr1') or '' ++ expr2 = src_match.group('expr2') or '' ++ return grd_node is None or grd_node.EvaluateCondition(expr1 + expr2) ++ ++ def CheckConditionalElements(str): ++ """Helper function to conditionally inline inner elements""" ++ while True: ++ begin_if = _BEGIN_IF_BLOCK.search(str) ++ if begin_if is None: ++ if _END_IF_BLOCK.search(str) is not None: ++ raise Exception('Unmatched ') ++ return str ++ ++ condition_satisfied = IsConditionSatisfied(begin_if) ++ leading = str[0:begin_if.start()] ++ content_start = begin_if.end() ++ ++ # Find matching "if" block end. ++ count = 1 ++ pos = begin_if.end() ++ while True: ++ end_if = _END_IF_BLOCK.search(str, pos) ++ if end_if is None: ++ raise Exception('Unmatched ') ++ ++ next_if = _BEGIN_IF_BLOCK.search(str, pos) ++ if next_if is None or next_if.start() >= end_if.end(): ++ count = count - 1 ++ if count == 0: ++ break ++ pos = end_if.end() ++ else: ++ count = count + 1 ++ pos = next_if.end() ++ ++ content = str[content_start:end_if.start()] ++ trailing = str[end_if.end():] ++ ++ if condition_satisfied: ++ str = leading + CheckConditionalElements(content) + trailing ++ else: ++ str = leading + trailing ++ ++ def InlineFileContents(src_match, ++ pattern, ++ inlined_files=inlined_files, ++ strip_whitespace=False): ++ """Helper function to inline external files of various types""" ++ filepath = GetFilepath(src_match) ++ if filepath is None: ++ return src_match.group(0) ++ inlined_files.add(filepath) ++ ++ if names_only: ++ inlined_files.update(GetResourceFilenames( ++ filepath, ++ grd_node, ++ allow_external_script, ++ rewrite_function, ++ filename_expansion_function=filename_expansion_function)) ++ return "" ++ # To recursively save inlined files, we need InlinedData instance returned ++ # by DoInline. ++ inlined_data_inst=DoInline(filepath, grd_node, ++ allow_external_script=allow_external_script, ++ preprocess_only=preprocess_only, ++ strip_whitespace=strip_whitespace, ++ filename_expansion_function=filename_expansion_function) ++ ++ inlined_files.update(inlined_data_inst.inlined_files) ++ ++ return pattern % inlined_data_inst.inlined_data; ++ ++ ++ def InlineIncludeFiles(src_match): ++ """Helper function to directly inline generic external files (without ++ wrapping them with any kind of tags). ++ """ ++ return InlineFileContents(src_match, '%s') ++ ++ def InlineScript(match): ++ """Helper function to inline external script files""" ++ attrs = (match.group('attrs1') + match.group('attrs2')).strip() ++ if attrs: ++ attrs = ' ' + attrs ++ return InlineFileContents(match, '%s', ++ strip_whitespace=True) ++ ++ def InlineCSSText(text, css_filepath): ++ """Helper function that inlines external resources in CSS text""" ++ filepath = os.path.dirname(css_filepath) ++ # Allow custom modifications before inlining images. ++ if rewrite_function: ++ text = rewrite_function(filepath, text, distribution) ++ text = InlineCSSImages(text, filepath) ++ return InlineCSSImports(text, filepath) ++ ++ def InlineCSSFile(src_match, pattern, base_path=input_filepath): ++ """Helper function to inline external CSS files. ++ ++ Args: ++ src_match: A regular expression match with a named group named "filename". ++ pattern: The pattern to replace with the contents of the CSS file. ++ base_path: The base path to use for resolving the CSS file. ++ ++ Returns: ++ The text that should replace the reference to the CSS file. ++ """ ++ filepath = GetFilepath(src_match, base_path) ++ if filepath is None: ++ return src_match.group(0) ++ ++ # Even if names_only is set, the CSS file needs to be opened, because it ++ # can link to images that need to be added to the file set. ++ inlined_files.add(filepath) ++ ++ # Inline stylesheets included in this css file. ++ text = _INCLUDE_RE.sub(InlineIncludeFiles, util.ReadFile(filepath, 'utf-8')) ++ # When resolving CSS files we need to pass in the path so that relative URLs ++ # can be resolved. ++ ++ return pattern % InlineCSSText(text, filepath) ++ ++ def GetUrlRegexString(postfix=''): ++ """Helper function that returns a string for a regex that matches url('') ++ but not url([[ ]]) or url({{ }}). Appends |postfix| to group names. ++ """ ++ url_re = (r'url\((?!\[\[|{{)(?P"|\'|)(?P[^"\'()]*)' ++ r'(?P=q%s)\)') ++ return url_re % (postfix, postfix, postfix) ++ ++ def InlineCSSImages(text, filepath=input_filepath): ++ """Helper function that inlines external images in CSS backgrounds.""" ++ # Replace contents of url() for css attributes: content, background, ++ # or *-image. ++ property_re = r'(content|background|[\w-]*-image):[^;]*' ++ # Replace group names to prevent duplicates when forming value_re. ++ image_set_value_re = (r'image-set\(([ ]*' + GetUrlRegexString('2') + ++ r'[ ]*[0-9.]*x[ ]*(,[ ]*)?)+\)') ++ value_re = '(%s|%s)' % (GetUrlRegexString(), image_set_value_re) ++ css_re = property_re + value_re ++ return re.sub(css_re, lambda m: InlineCSSUrls(m, filepath), text) ++ ++ def InlineCSSUrls(src_match, filepath=input_filepath): ++ """Helper function that inlines each url on a CSS image rule match.""" ++ # Replace contents of url() references in matches. ++ return re.sub(GetUrlRegexString(), ++ lambda m: SrcReplace(m, filepath), ++ src_match.group(0)) ++ ++ def InlineCSSImports(text, filepath=input_filepath): ++ """Helper function that inlines CSS files included via the @import ++ directive. ++ """ ++ return re.sub(r'@import\s+' + GetUrlRegexString() + r';', ++ lambda m: InlineCSSFile(m, '%s', filepath), ++ text) ++ ++ ++ flat_text = util.ReadFile(input_filename, 'utf-8') ++ ++ # Check conditional elements, remove unsatisfied ones from the file. We do ++ # this twice. The first pass is so that we don't even bother calling ++ # InlineScript, InlineCSSFile and InlineIncludeFiles on text we're eventually ++ # going to throw out anyway. ++ flat_text = CheckConditionalElements(flat_text) ++ ++ flat_text = _INCLUDE_RE.sub(InlineIncludeFiles, flat_text) ++ ++ if not preprocess_only: ++ if strip_whitespace: ++ flat_text = minifier.Minify(flat_text.encode('utf-8'), ++ input_filename).decode('utf-8') ++ ++ if not allow_external_script: ++ # We need to inline css and js before we inline images so that image ++ # references gets inlined in the css and js ++ flat_text = re.sub(r'', ++ InlineScript, ++ flat_text) ++ ++ flat_text = _STYLESHEET_RE.sub( ++ lambda m: InlineCSSFile(m, ''), ++ flat_text) ++ ++ # Check conditional elements, second pass. This catches conditionals in any ++ # of the text we just inlined. ++ flat_text = CheckConditionalElements(flat_text) ++ ++ # Allow custom modifications before inlining images. ++ if rewrite_function: ++ flat_text = rewrite_function(input_filepath, flat_text, distribution) ++ ++ if not preprocess_only: ++ flat_text = _SRC_RE.sub(SrcReplace, flat_text) ++ flat_text = _SRCSET_RE.sub(SrcsetReplace, flat_text) ++ ++ # TODO(arv): Only do this inside ++ ++ ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(util.normpath(filename))) ++ ++ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ ++ tmp_dir.CleanUp() ++ ++ def testInlineIgnoresPolymerBindings(self): ++ '''Tests that polymer bindings are ignored when inlining. ++ ''' ++ ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ++ ++ ++
++
++
++
++ ++ ++ ''', ++ ++ 'test.css': ''' ++ .image { ++ background: url('test.png'); ++ background-image: url([[ignoreMe]]); ++ background-image: image-set(url({{alsoMe}}), 1x); ++ background-image: image-set( ++ url({{ignore}}) 1x, ++ url('test.png') 2x); ++ } ++ ''', ++ ++ 'test.png': 'PNG DATA' ++ } ++ ++ expected_inlined = ''' ++ ++ ++ ++ ++ ++ ++ ++ ++
++
++
++
++ ++ ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(util.normpath(filename))) ++ ++ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ ++ tmp_dir.CleanUp() ++ ++ def testInlineCSSWithIncludeDirective(self): ++ '''Tests that include directive in external css files also inlined''' ++ ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ''', ++ ++ 'foo.css': '''''', ++ ++ 'style.css': ''' ++ ++ blink { ++ display: none; ++ } ++ ''', ++ 'style2.css': '''h1 {}''', ++ } ++ ++ expected_inlined = ''' ++ ++ ++ ++ ++ ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ tmp_dir.CleanUp() ++ ++ def testCssIncludedFileNames(self): ++ '''Tests that all included files from css are returned''' ++ ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ''', ++ ++ 'test.css': ''' ++ ++ ''', ++ ++ 'test2.css': ''' ++ ++ .image { ++ background: url('test.png'); ++ } ++ ''', ++ ++ 'test3.css': '''h1 {}''', ++ ++ 'test.png': 'PNG DATA' ++ } ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ resources = html_inline.GetResourceFilenames(tmp_dir.GetPath('index.html'), ++ None) ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ tmp_dir.CleanUp() ++ ++ def testInlineCSSLinks(self): ++ '''Tests that only CSS files referenced via relative URLs are inlined.''' ++ ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ++ ''', ++ ++ 'foo.css': ''' ++ @import url(chrome://resources/blurp.css); ++ blink { ++ display: none; ++ } ++ ''', ++ } ++ ++ expected_inlined = ''' ++ ++ ++ ++ ++ ++ ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ tmp_dir.CleanUp() ++ ++ def testFilenameVariableExpansion(self): ++ '''Tests that variables are expanded in filenames before inlining.''' ++ ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ''', ++ 'style1.css': '''h1 {}''', ++ 'tmpl1.html': '''

''', ++ 'script1.js': '''console.log('hello');''', ++ 'img1.png': '''abc''', ++ } ++ ++ expected_inlined = ''' ++ ++ ++ ++ ++ ++

++ ++ ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ def replacer(var, repl): ++ return lambda filename: filename.replace('[%s]' % var, repl) ++ ++ # Test normal inlining. ++ result = html_inline.DoInline( ++ tmp_dir.GetPath('index.html'), ++ None, ++ filename_expansion_function=replacer('WHICH', '1')) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ ++ # Test names-only inlining. ++ result = html_inline.DoInline( ++ tmp_dir.GetPath('index.html'), ++ None, ++ names_only=True, ++ filename_expansion_function=replacer('WHICH', '1')) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ tmp_dir.CleanUp() ++ ++ def testWithCloseTags(self): ++ '''Tests that close tags are removed.''' ++ ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''', ++ 'style1.css': '''h1 {}''', ++ 'style2.css': '''h2 {}''', ++ 'tmpl1.html': '''

''', ++ 'tmpl2.html': '''

''', ++ 'script1.js': '''console.log('hello');''', ++ 'img1.png': '''abc''', ++ } ++ ++ expected_inlined = ''' ++ ++ ++ ++ ++ ++ ++ ++

++

++

++ ++ ++ ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ # Test normal inlining. ++ result = html_inline.DoInline( ++ tmp_dir.GetPath('index.html'), ++ None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ tmp_dir.CleanUp() ++ ++ def testCommentedJsInclude(self): ++ '''Tests that works inside a comment.''' ++ ++ files = { ++ 'include.js': '// ', ++ 'other.js': '// Copyright somebody\nalert(1);', ++ } ++ ++ expected_inlined = '// Copyright somebody\nalert(1);' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ result = html_inline.DoInline(tmp_dir.GetPath('include.js'), None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('include.js')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ tmp_dir.CleanUp() ++ ++ def testCommentedJsIf(self): ++ '''Tests that works inside a comment.''' ++ ++ files = { ++ 'if.js': ''' ++ // ++ yep(); ++ // ++ ++ // ++ nope(); ++ // ++ ''', ++ } ++ ++ expected_inlined = ''' ++ // ++ yep(); ++ // ++ ++ // ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ class FakeGrdNode(object): ++ def EvaluateCondition(self, cond): ++ return eval(cond) ++ ++ result = html_inline.DoInline(tmp_dir.GetPath('if.js'), FakeGrdNode()) ++ resources = result.inlined_files ++ ++ resources.add(tmp_dir.GetPath('if.js')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ tmp_dir.CleanUp() ++ ++ def testImgSrcset(self): ++ '''Tests that img srcset="" attributes are converted.''' ++ ++ # Note that there is no space before "img10.png" and that ++ # "img11.png" has no descriptor. ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''', ++ 'img1.png': '''a1''', ++ 'img2.png': '''a2''', ++ 'img3.png': '''a3''', ++ 'img4.png': '''a4''', ++ 'img5.png': '''a5''', ++ 'img6.png': '''a6''', ++ 'img7.png': '''a7''', ++ 'img8.png': '''a8''', ++ 'img9.png': '''a9''', ++ 'img10.png': '''a10''', ++ 'img11.png': '''a11''', ++ } ++ ++ expected_inlined = ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ # Test normal inlining. ++ result = html_inline.DoInline( ++ tmp_dir.GetPath('index.html'), ++ None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ tmp_dir.CleanUp() ++ ++ def testImgSrcsetIgnoresI18n(self): ++ '''Tests that $i18n{...} strings are ignored when inlining. ++ ''' ++ ++ src_html = ''' ++ ++ ++ ++ ++ ++ ++ ''' ++ ++ files = { ++ 'index.html': src_html, ++ } ++ ++ expected_inlined = src_html ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(util.normpath(filename))) ++ ++ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ tmp_dir.CleanUp() ++ ++ def testSourceSrcset(self): ++ '''Tests that source srcset="" attributes are converted.''' ++ ++ # Note that there is no space before "img10.png" and that ++ # "img11.png" has no descriptor. ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ++ ++ ''', ++ 'img1.png': '''a1''', ++ 'img2.png': '''a2''', ++ 'img3.png': '''a3''', ++ 'img4.png': '''a4''', ++ 'img5.png': '''a5''', ++ 'img6.png': '''a6''', ++ 'img7.png': '''a7''', ++ 'img8.png': '''a8''', ++ 'img9.png': '''a9''', ++ 'img10.png': '''a10''', ++ 'img11.png': '''a11''', ++ } ++ ++ expected_inlined = ''' ++ ++ ++ ++ ++ ++ ++ ++ ''' ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ # Test normal inlining. ++ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ self.failUnlessEqual(expected_inlined, ++ util.FixLineEnd(result.inlined_data, '\n')) ++ tmp_dir.CleanUp() ++ ++ def testConditionalInclude(self): ++ '''Tests that output and dependency generation includes only files not'''\ ++ ''' blocked by macros.''' ++ ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''', ++ 'img1.png': '''a1''', ++ 'img2.png': '''a2''', ++ 'img3.png': '''a3''', ++ 'img4.png': '''a4''', ++ 'img5.png': '''a5''', ++ 'img6.png': '''a6''', ++ 'img7.png': '''a7''', ++ 'img8.png': '''a8''', ++ 'img9.png': '''a9''', ++ 'img10.png': '''a10''', ++ } ++ ++ expected_inlined = ''' ++ ++ ++ ++ ++ ++ ''' ++ ++ expected_files = [ ++ 'index.html', ++ 'img1.png', ++ 'img2.png', ++ 'img3.png', ++ 'img7.png', ++ 'img8.png', ++ 'img9.png', ++ 'img10.png' ++ ] ++ ++ source_resources = set() ++ tmp_dir = util.TempDir(files) ++ for filename in expected_files: ++ source_resources.add(tmp_dir.GetPath(filename)) ++ ++ class FakeGrdNode(object): ++ def EvaluateCondition(self, cond): ++ return eval(cond) ++ ++ # Test normal inlining. ++ result = html_inline.DoInline( ++ tmp_dir.GetPath('index.html'), ++ FakeGrdNode()) ++ resources = result.inlined_files ++ resources.add(tmp_dir.GetPath('index.html')) ++ self.failUnlessEqual(resources, source_resources) ++ ++ # ignore whitespace ++ expected_inlined = re.sub(r'\s+', ' ', expected_inlined) ++ actually_inlined = re.sub(r'\s+', ' ', ++ util.FixLineEnd(result.inlined_data, '\n')) ++ self.failUnlessEqual(expected_inlined, actually_inlined); ++ tmp_dir.CleanUp() ++ ++ def testPreprocessOnlyEvaluatesIncludeAndIf(self): ++ '''Tests that preprocess_only=true evaluates and only. ''' ++ ++ files = { ++ 'index.html': ''' ++ ++ ++ ++ ++ ++
++ ++
++ ++
++ ++ ++
++ ++
++    ++
++ ++
++
++ ''')) ++ html.Parse() ++ trans = html.Translate('en') ++ if (html.GetText() != trans): ++ self.fail() ++ ++ ++ def testHtmlToMessageWithBlockTags(self): ++ msg = tr_html.HtmlToMessage( ++ 'Hello

Howdiebingo', True) ++ result = msg.GetPresentableContent() ++ self.failUnless( ++ result == 'HelloBEGIN_PARAGRAPHHowdieBEGIN_BLOCKbingoEND_BLOCK') ++ ++ msg = tr_html.HtmlToMessage( ++ 'Hello

Howdie', True) ++ result = msg.GetPresentableContent() ++ self.failUnless( ++ result == 'HelloBEGIN_PARAGRAPHHowdieBEGIN_BLOCKbingoEND_BLOCK') ++ ++ ++ def testHtmlToMessageRegressions(self): ++ msg = tr_html.HtmlToMessage(' - ', True) ++ result = msg.GetPresentableContent() ++ self.failUnless(result == ' - ') ++ ++ ++ def testEscapeUnescaped(self): ++ text = '©  & "<hello>"' ++ unescaped = util.UnescapeHtml(text) ++ self.failUnless(unescaped == u'\u00a9\u00a0 & ""') ++ escaped_unescaped = util.EscapeHtml(unescaped, True) ++ self.failUnless(escaped_unescaped == ++ u'\u00a9\u00a0 & "<hello>"') ++ ++ def testRegressionCjkHtmlFile(self): ++ # TODO(joi) Fix this problem where unquoted attributes that ++ # have a value that is CJK characters causes the regular expression ++ # match never to return. (culprit is the _ELEMENT regexp( ++ if False: ++ html = self.HtmlFromFileWithManualCheck(util.PathFromRoot( ++ r'grit/testdata/ko_oem_enable_bug.html')) ++ self.failUnless(True) ++ ++ def testRegressionCpuHang(self): ++ # If this regression occurs, the unit test will never return ++ html = tr_html.TrHtml(StringIO( ++ '''''')) ++ html.Parse() ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/gather/txt.py b/tools/grit/grit/gather/txt.py +new file mode 100644 +index 0000000000..e5c10abc28 +--- /dev/null ++++ b/tools/grit/grit/gather/txt.py +@@ -0,0 +1,38 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Supports making amessage from a text file. ++''' ++ ++from __future__ import print_function ++ ++from grit.gather import interface ++from grit import tclib ++ ++ ++class TxtFile(interface.GathererBase): ++ '''A text file gatherer. Very simple, all text from the file becomes a ++ single clique. ++ ''' ++ ++ def Parse(self): ++ self.text_ = self._LoadInputFile() ++ self.clique_ = self.uberclique.MakeClique(tclib.Message(text=self.text_)) ++ ++ def GetText(self): ++ '''Returns the text of what is being gathered.''' ++ return self.text_ ++ ++ def GetTextualIds(self): ++ return [self.extkey] ++ ++ def GetCliques(self): ++ '''Returns the MessageClique objects for all translateable portions.''' ++ return [self.clique_] ++ ++ def Translate(self, lang, pseudo_if_not_available=True, ++ skeleton_gatherer=None, fallback_to_english=False): ++ return self.clique_.MessageForLanguage(lang, ++ pseudo_if_not_available, ++ fallback_to_english).GetRealContent() +diff --git a/tools/grit/grit/gather/txt_unittest.py b/tools/grit/grit/gather/txt_unittest.py +new file mode 100644 +index 0000000000..abb9ed98d7 +--- /dev/null ++++ b/tools/grit/grit/gather/txt_unittest.py +@@ -0,0 +1,35 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for TxtFile gatherer''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++ ++import unittest ++ ++from six import StringIO ++ ++from grit.gather import txt ++ ++ ++class TxtUnittest(unittest.TestCase): ++ def testGather(self): ++ input = StringIO('Hello there\nHow are you?') ++ gatherer = txt.TxtFile(input) ++ gatherer.Parse() ++ self.failUnless(gatherer.GetText() == input.getvalue()) ++ self.failUnless(len(gatherer.GetCliques()) == 1) ++ self.failUnless(gatherer.GetCliques()[0].GetMessage().GetRealContent() == ++ input.getvalue()) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/grd_reader.py b/tools/grit/grit/grd_reader.py +new file mode 100644 +index 0000000000..b7bb782977 +--- /dev/null ++++ b/tools/grit/grit/grd_reader.py +@@ -0,0 +1,238 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Class for reading GRD files into memory, without processing them. ++''' ++ ++from __future__ import print_function ++ ++import os.path ++import sys ++import xml.sax ++import xml.sax.handler ++ ++import six ++ ++from grit import exception ++from grit import util ++from grit.node import mapping ++from grit.node import misc ++ ++ ++class StopParsingException(Exception): ++ '''An exception used to stop parsing.''' ++ pass ++ ++ ++class GrdContentHandler(xml.sax.handler.ContentHandler): ++ def __init__(self, stop_after, debug, dir, defines, tags_to_ignore, ++ target_platform, source): ++ # Invariant of data: ++ # 'root' is the root of the parse tree being created, or None if we haven't ++ # parsed out any elements. ++ # 'stack' is the a stack of elements that we push new nodes onto and ++ # pop from when they finish parsing, or [] if we are not currently parsing. ++ # 'stack[-1]' is the top of the stack. ++ self.root = None ++ self.stack = [] ++ self.stop_after = stop_after ++ self.debug = debug ++ self.dir = dir ++ self.defines = defines ++ self.tags_to_ignore = tags_to_ignore or set() ++ self.ignore_depth = 0 ++ self.target_platform = target_platform ++ self.source = source ++ ++ def startElement(self, name, attrs): ++ if self.ignore_depth or name in self.tags_to_ignore: ++ if self.debug and self.ignore_depth == 0: ++ print("Ignoring element %s and its children" % name) ++ self.ignore_depth += 1 ++ return ++ ++ if self.debug: ++ attr_list = ' '.join('%s="%s"' % kv for kv in attrs.items()) ++ print("Starting parsing of element %s with attributes %r" % ++ (name, attr_list or '(none)')) ++ ++ typeattr = attrs.get('type') ++ node = mapping.ElementToClass(name, typeattr)() ++ node.source = self.source ++ ++ if self.stack: ++ self.stack[-1].AddChild(node) ++ node.StartParsing(name, self.stack[-1]) ++ else: ++ assert self.root is None ++ self.root = node ++ if isinstance(self.root, misc.GritNode): ++ if self.target_platform: ++ self.root.SetTargetPlatform(self.target_platform) ++ node.StartParsing(name, None) ++ if self.defines: ++ node.SetDefines(self.defines) ++ self.stack.append(node) ++ ++ for attr, attrval in attrs.items(): ++ node.HandleAttribute(attr, attrval) ++ ++ def endElement(self, name): ++ if self.ignore_depth: ++ self.ignore_depth -= 1 ++ return ++ ++ if name == 'part': ++ partnode = self.stack[-1] ++ partnode.started_inclusion = True ++ # Add the contents of the sub-grd file as children of the node. ++ partname = os.path.join(self.dir, partnode.GetInputPath()) ++ # Check the GRDP file exists. ++ if not os.path.exists(partname): ++ raise exception.FileNotFound(partname) ++ # Exceptions propagate to the handler in grd_reader.Parse(). ++ oldsource = self.source ++ try: ++ self.source = partname ++ xml.sax.parse(partname, GrdPartContentHandler(self)) ++ finally: ++ self.source = oldsource ++ ++ if self.debug: ++ print("End parsing of element %s" % name) ++ self.stack.pop().EndParsing() ++ ++ if name == self.stop_after: ++ raise StopParsingException() ++ ++ def characters(self, content): ++ if self.ignore_depth == 0: ++ if self.stack[-1]: ++ self.stack[-1].AppendContent(content) ++ ++ def ignorableWhitespace(self, whitespace): ++ # TODO(joi): This is not supported by expat. Should use a different XML ++ # parser? ++ pass ++ ++ ++class GrdPartContentHandler(xml.sax.handler.ContentHandler): ++ def __init__(self, parent): ++ self.parent = parent ++ self.depth = 0 ++ ++ def startElement(self, name, attrs): ++ if self.depth: ++ self.parent.startElement(name, attrs) ++ else: ++ if name != 'grit-part': ++ raise exception.MissingElement("root tag must be ") ++ if attrs: ++ raise exception.UnexpectedAttribute( ++ " tag must not have attributes") ++ self.depth += 1 ++ ++ def endElement(self, name): ++ self.depth -= 1 ++ if self.depth: ++ self.parent.endElement(name) ++ ++ def characters(self, content): ++ self.parent.characters(content) ++ ++ def ignorableWhitespace(self, whitespace): ++ self.parent.ignorableWhitespace(whitespace) ++ ++ ++def Parse(filename_or_stream, dir=None, stop_after=None, first_ids_file=None, ++ debug=False, defines=None, tags_to_ignore=None, target_platform=None, ++ predetermined_ids_file=None): ++ '''Parses a GRD file into a tree of nodes (from grit.node). ++ ++ If filename_or_stream is a stream, 'dir' should point to the directory ++ notionally containing the stream (this feature is only used in unit tests). ++ ++ If 'stop_after' is provided, the parsing will stop once the first node ++ with this name has been fully parsed (including all its contents). ++ ++ If 'debug' is true, lots of information about the parsing events will be ++ printed out during parsing of the file. ++ ++ If 'first_ids_file' is non-empty, it is used to override the setting for the ++ first_ids_file attribute of the root node. Note that the first_ids_file ++ parameter should be relative to the cwd, even though the first_ids_file ++ attribute of the node is relative to the grd file. ++ ++ If 'target_platform' is set, this is used to determine the target ++ platform of builds, instead of using |sys.platform|. ++ ++ Args: ++ filename_or_stream: './bla.xml' ++ dir: None (if filename_or_stream is a filename) or '.' ++ stop_after: 'inputs' ++ first_ids_file: 'GRIT_DIR/../gritsettings/resource_ids' ++ debug: False ++ defines: dictionary of defines, like {'chromeos': '1'} ++ target_platform: None or the value that would be returned by sys.platform ++ on your target platform. ++ predetermined_ids_file: File path to a file containing a pre-determined ++ mapping from resource names to resource ids which will be used to assign ++ resource ids to those resources. ++ ++ Return: ++ Subclass of grit.node.base.Node ++ ++ Throws: ++ grit.exception.Parsing ++ ''' ++ ++ if isinstance(filename_or_stream, six.string_types): ++ source = filename_or_stream ++ if dir is None: ++ dir = util.dirname(filename_or_stream) ++ else: ++ source = None ++ ++ handler = GrdContentHandler(stop_after=stop_after, debug=debug, dir=dir, ++ defines=defines, tags_to_ignore=tags_to_ignore, ++ target_platform=target_platform, source=source) ++ try: ++ xml.sax.parse(filename_or_stream, handler) ++ except StopParsingException: ++ assert stop_after ++ pass ++ except: ++ if not debug: ++ print("parse exception: run GRIT with the -x flag to debug .grd problems") ++ raise ++ ++ if handler.root.name != 'grit': ++ raise exception.MissingElement("root tag must be ") ++ ++ if hasattr(handler.root, 'SetOwnDir'): ++ # Fix up the base_dir so it is relative to the input file. ++ assert dir is not None ++ handler.root.SetOwnDir(dir) ++ ++ if isinstance(handler.root, misc.GritNode): ++ handler.root.SetPredeterminedIdsFile(predetermined_ids_file) ++ if first_ids_file: ++ # Make the path to the first_ids_file relative to the grd file, ++ # unless it begins with GRIT_DIR. ++ GRIT_DIR_PREFIX = 'GRIT_DIR' ++ if not (first_ids_file.startswith(GRIT_DIR_PREFIX) ++ and first_ids_file[len(GRIT_DIR_PREFIX)] in ['/', '\\']): ++ rel_dir = os.path.relpath(os.getcwd(), dir) ++ first_ids_file = util.normpath(os.path.join(rel_dir, first_ids_file)) ++ handler.root.attrs['first_ids_file'] = first_ids_file ++ # Assign first ids to the nodes that don't have them. ++ handler.root.AssignFirstIds(filename_or_stream, defines) ++ ++ return handler.root ++ ++ ++if __name__ == '__main__': ++ util.ChangeStdoutEncoding() ++ print(six.text_type(Parse(sys.argv[1]))) +diff --git a/tools/grit/grit/grd_reader_unittest.py b/tools/grit/grit/grd_reader_unittest.py +new file mode 100644 +index 0000000000..920a92f9c0 +--- /dev/null ++++ b/tools/grit/grit/grd_reader_unittest.py +@@ -0,0 +1,346 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grd_reader package''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) ++ ++import unittest ++ ++import six ++from six import StringIO ++ ++from grit import exception ++from grit import grd_reader ++from grit import util ++from grit.node import empty ++from grit.node import message ++ ++ ++class GrdReaderUnittest(unittest.TestCase): ++ def testParsingAndXmlOutput(self): ++ input = u''' ++ ++ ++ ++ ++ ++ ++ ++ ++ Hello %sJoi, how are you doing today? ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++''' ++ pseudo_file = StringIO(input) ++ tree = grd_reader.Parse(pseudo_file, '.') ++ output = six.text_type(tree) ++ expected_output = input.replace(u' base_dir="."', u'') ++ self.assertEqual(expected_output, output) ++ self.failUnless(tree.GetNodeById('IDS_GREETING')) ++ ++ ++ def testStopAfter(self): ++ input = u''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++''' ++ pseudo_file = StringIO(input) ++ tree = grd_reader.Parse(pseudo_file, '.', stop_after='outputs') ++ # only an child ++ self.failUnless(len(tree.children) == 1) ++ self.failUnless(tree.children[0].name == 'outputs') ++ ++ def testLongLinesWithComments(self): ++ input = u''' ++ ++ ++ ++ ++ This is a very long line with no linebreaks yes yes it stretches on and on and on! ++ ++ ++ ++''' ++ pseudo_file = StringIO(input) ++ tree = grd_reader.Parse(pseudo_file, '.') ++ ++ greeting = tree.GetNodeById('IDS_GREETING') ++ self.failUnless(greeting.GetCliques()[0].GetMessage().GetRealContent() == ++ 'This is a very long line with no linebreaks yes yes it ' ++ 'stretches on and on and on!') ++ ++ def doTestAssignFirstIds(self, first_ids_path): ++ input = u''' ++ ++ ++ ++ ++ test ++ ++ ++ ++''' % first_ids_path ++ pseudo_file = StringIO(input) ++ grit_root_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), ++ '..') ++ fake_input_path = os.path.join( ++ grit_root_dir, "grit/testdata/chrome/app/generated_resources.grd") ++ root = grd_reader.Parse(pseudo_file, os.path.split(fake_input_path)[0]) ++ root.AssignFirstIds(fake_input_path, {}) ++ messages_node = root.children[0].children[0] ++ self.failUnless(isinstance(messages_node, empty.MessagesNode)) ++ self.failUnless(messages_node.attrs["first_id"] != ++ empty.MessagesNode().DefaultAttributes()["first_id"]) ++ ++ def testAssignFirstIds(self): ++ self.doTestAssignFirstIds("../../tools/grit/resource_ids") ++ ++ def testAssignFirstIdsUseGritDir(self): ++ self.doTestAssignFirstIds("GRIT_DIR/grit/testdata/tools/grit/resource_ids") ++ ++ def testAssignFirstIdsMultipleMessages(self): ++ """If there are multiple messages sections, the resource_ids file ++ needs to list multiple first_id values.""" ++ input = u''' ++ ++ ++ ++ ++ test ++ ++ ++ ++ ++ test2 ++ ++ ++ ++''' ++ pseudo_file = StringIO(input) ++ grit_root_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), ++ '..') ++ fake_input_path = os.path.join(grit_root_dir, "grit/testdata/test.grd") ++ ++ root = grd_reader.Parse(pseudo_file, os.path.split(fake_input_path)[0]) ++ root.AssignFirstIds(fake_input_path, {}) ++ messages_node = root.children[0].children[0] ++ self.assertTrue(isinstance(messages_node, empty.MessagesNode)) ++ self.assertEqual('100', messages_node.attrs["first_id"]) ++ messages_node = root.children[0].children[1] ++ self.assertTrue(isinstance(messages_node, empty.MessagesNode)) ++ self.assertEqual('10000', messages_node.attrs["first_id"]) ++ ++ def testUseNameForIdAndPpIfdef(self): ++ input = u''' ++ ++ ++ ++ ++ ++ Hello! ++ ++ ++ ++ ++''' ++ pseudo_file = StringIO(input) ++ root = grd_reader.Parse(pseudo_file, '.', defines={'hello': '1'}) ++ ++ # Check if the ID is set to the name. In the past, there was a bug ++ # that caused the ID to be a generated number. ++ hello = root.GetNodeById('IDS_HELLO') ++ self.failUnless(hello.GetCliques()[0].GetId() == 'IDS_HELLO') ++ ++ def testUseNameForIdWithIfElse(self): ++ input = u''' ++ ++ ++ ++ ++ ++ ++ Hello! ++ ++ ++ ++ ++ Yellow! ++ ++ ++ ++ ++ ++''' ++ pseudo_file = StringIO(input) ++ root = grd_reader.Parse(pseudo_file, '.', defines={'hello': '1'}) ++ ++ # Check if the ID is set to the name. In the past, there was a bug ++ # that caused the ID to be a generated number. ++ hello = root.GetNodeById('IDS_HELLO') ++ self.failUnless(hello.GetCliques()[0].GetId() == 'IDS_HELLO') ++ ++ def testPartInclusionAndCorrectSource(self): ++ arbitrary_path_grd = u'''\ ++ ++ test5 ++ ''' ++ tmp_dir = util.TempDir({'arbitrary_path.grp': arbitrary_path_grd}) ++ arbitrary_path_grd_file = tmp_dir.GetPath('arbitrary_path.grp') ++ top_grd = u'''\ ++ ++ ++ ++ ++ test ++ ++ ++ ++ ++ ++ ''' % arbitrary_path_grd_file ++ sub_grd = u'''\ ++ ++ test2 ++ ++ test3 ++ ''' ++ subsub_grd = u'''\ ++ ++ test4 ++ ''' ++ expected_output = u'''\ ++ ++ ++ ++ ++ test ++ ++ ++ ++ test2 ++ ++ ++ ++ test4 ++ ++ ++ ++ test3 ++ ++ ++ ++ ++ test5 ++ ++ ++ ++ ++ ''' % arbitrary_path_grd_file ++ ++ with util.TempDir({'sub.grp': sub_grd, ++ 'subsub.grp': subsub_grd}) as tmp_sub_dir: ++ output = grd_reader.Parse(StringIO(top_grd), ++ tmp_sub_dir.GetPath()) ++ correct_sources = { ++ 'IDS_TEST': None, ++ 'IDS_TEST2': tmp_sub_dir.GetPath('sub.grp'), ++ 'IDS_TEST3': tmp_sub_dir.GetPath('sub.grp'), ++ 'IDS_TEST4': tmp_sub_dir.GetPath('subsub.grp'), ++ 'IDS_TEST5': arbitrary_path_grd_file, ++ } ++ ++ for node in output.ActiveDescendants(): ++ with node: ++ if isinstance(node, message.MessageNode): ++ self.assertEqual(correct_sources[node.attrs.get('name')], node.source) ++ self.assertEqual(expected_output.split(), output.FormatXml().split()) ++ tmp_dir.CleanUp() ++ ++ def testPartInclusionFailure(self): ++ template = u''' ++ ++ ++ %s ++ ++ ''' ++ ++ part_failures = [ ++ (exception.UnexpectedContent, u'fnord'), ++ (exception.UnexpectedChild, ++ u''), ++ (exception.FileNotFound, u''), ++ ] ++ for raises, data in part_failures: ++ data = StringIO(template % data) ++ self.assertRaises(raises, grd_reader.Parse, data, '.') ++ ++ gritpart_failures = [ ++ (exception.UnexpectedAttribute, u''), ++ (exception.MissingElement, u''), ++ ] ++ for raises, data in gritpart_failures: ++ top_grd = StringIO(template % u'') ++ with util.TempDir({'bad.grp': data}) as temp_dir: ++ self.assertRaises(raises, grd_reader.Parse, top_grd, temp_dir.GetPath()) ++ ++ def testEarlyEnoughPlatformSpecification(self): ++ # This is a regression test for issue ++ # https://code.google.com/p/grit-i18n/issues/detail?id=23 ++ grd_text = u''' ++ ++ ++ ++ ++ foo ++ ++ ++ ++ boo ++ ++ ++ ++ ''' % sys.platform ++ with util.TempDir({}) as temp_dir: ++ grd_reader.Parse(StringIO(grd_text), temp_dir.GetPath(), ++ target_platform='android') ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/grit-todo.xml b/tools/grit/grit/grit-todo.xml +new file mode 100644 +index 0000000000..b8c20fdfad +--- /dev/null ++++ b/tools/grit/grit/grit-todo.xml +@@ -0,0 +1,62 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tools/grit/grit/grit_runner.py b/tools/grit/grit/grit_runner.py +new file mode 100644 +index 0000000000..26aa0d58c4 +--- /dev/null ++++ b/tools/grit/grit/grit_runner.py +@@ -0,0 +1,334 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Command processor for GRIT. This is the script you invoke to run the various ++GRIT tools. ++""" ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) ++ ++import getopt ++ ++from grit import util ++ ++import grit.extern.FP ++ ++# Tool info factories; these import only within each factory to avoid ++# importing most of the GRIT code until required. ++def ToolFactoryBuild(): ++ import grit.tool.build ++ return grit.tool.build.RcBuilder() ++ ++def ToolFactoryBuildInfo(): ++ import grit.tool.buildinfo ++ return grit.tool.buildinfo.DetermineBuildInfo() ++ ++def ToolFactoryCount(): ++ import grit.tool.count ++ return grit.tool.count.CountMessage() ++ ++def ToolFactoryDiffStructures(): ++ import grit.tool.diff_structures ++ return grit.tool.diff_structures.DiffStructures() ++ ++def ToolFactoryMenuTranslationsFromParts(): ++ import grit.tool.menu_from_parts ++ return grit.tool.menu_from_parts.MenuTranslationsFromParts() ++ ++def ToolFactoryNewGrd(): ++ import grit.tool.newgrd ++ return grit.tool.newgrd.NewGrd() ++ ++def ToolFactoryResizeDialog(): ++ import grit.tool.resize ++ return grit.tool.resize.ResizeDialog() ++ ++def ToolFactoryRc2Grd(): ++ import grit.tool.rc2grd ++ return grit.tool.rc2grd.Rc2Grd() ++ ++def ToolFactoryTest(): ++ import grit.tool.test ++ return grit.tool.test.TestTool() ++ ++def ToolFactoryTranslationToTc(): ++ import grit.tool.transl2tc ++ return grit.tool.transl2tc.TranslationToTc() ++ ++def ToolFactoryUnit(): ++ import grit.tool.unit ++ return grit.tool.unit.UnitTestTool() ++ ++ ++def ToolFactoryUpdateResourceIds(): ++ import grit.tool.update_resource_ids ++ return grit.tool.update_resource_ids.UpdateResourceIds() ++ ++ ++def ToolFactoryXmb(): ++ import grit.tool.xmb ++ return grit.tool.xmb.OutputXmb() ++ ++def ToolAndroid2Grd(): ++ import grit.tool.android2grd ++ return grit.tool.android2grd.Android2Grd() ++ ++# Keys for the following map ++_FACTORY = 1 ++_REQUIRES_INPUT = 2 ++_HIDDEN = 3 # optional key - presence indicates tool is hidden ++ ++# Maps tool names to the tool's module. Done as a list of (key, value) tuples ++# instead of a map to preserve ordering. ++_TOOLS = [ ++ ['android2grd', { ++ _FACTORY: ToolAndroid2Grd, ++ _REQUIRES_INPUT: False ++ }], ++ ['build', { ++ _FACTORY: ToolFactoryBuild, ++ _REQUIRES_INPUT: True ++ }], ++ ['buildinfo', { ++ _FACTORY: ToolFactoryBuildInfo, ++ _REQUIRES_INPUT: True ++ }], ++ ['count', { ++ _FACTORY: ToolFactoryCount, ++ _REQUIRES_INPUT: True ++ }], ++ [ ++ 'menufromparts', ++ { ++ _FACTORY: ToolFactoryMenuTranslationsFromParts, ++ _REQUIRES_INPUT: True, ++ _HIDDEN: True ++ } ++ ], ++ ['newgrd', { ++ _FACTORY: ToolFactoryNewGrd, ++ _REQUIRES_INPUT: False ++ }], ++ ['rc2grd', { ++ _FACTORY: ToolFactoryRc2Grd, ++ _REQUIRES_INPUT: False ++ }], ++ ['resize', { ++ _FACTORY: ToolFactoryResizeDialog, ++ _REQUIRES_INPUT: True ++ }], ++ ['sdiff', { ++ _FACTORY: ToolFactoryDiffStructures, ++ _REQUIRES_INPUT: False ++ }], ++ ['test', { ++ _FACTORY: ToolFactoryTest, ++ _REQUIRES_INPUT: True, ++ _HIDDEN: True ++ }], ++ [ ++ 'transl2tc', ++ { ++ _FACTORY: ToolFactoryTranslationToTc, ++ _REQUIRES_INPUT: False ++ } ++ ], ++ ['unit', { ++ _FACTORY: ToolFactoryUnit, ++ _REQUIRES_INPUT: False ++ }], ++ [ ++ 'update_resource_ids', ++ { ++ _FACTORY: ToolFactoryUpdateResourceIds, ++ _REQUIRES_INPUT: False ++ } ++ ], ++ ['xmb', { ++ _FACTORY: ToolFactoryXmb, ++ _REQUIRES_INPUT: True ++ }], ++] ++ ++ ++def PrintUsage(): ++ tool_list = '' ++ for (tool, info) in _TOOLS: ++ if not _HIDDEN in info: ++ tool_list += ' %-12s %s\n' % ( ++ tool, info[_FACTORY]().ShortDescription()) ++ ++ print("""GRIT - the Google Resource and Internationalization Tool ++ ++Usage: grit [GLOBALOPTIONS] TOOL [args to tool] ++ ++Global options: ++ ++ -i INPUT Specifies the INPUT file to use (a .grd file). If this is not ++ specified, GRIT will look for the environment variable GRIT_INPUT. ++ If it is not present either, GRIT will try to find an input file ++ named 'resource.grd' in the current working directory. ++ ++ -h MODULE Causes GRIT to use MODULE.UnsignedFingerPrint instead of ++ grit.extern.FP.UnsignedFingerprint. MODULE must be ++ available somewhere in the PYTHONPATH search path. ++ ++ -v Print more verbose runtime information. ++ ++ -x Print extremely verbose runtime information. Implies -v ++ ++ -p FNAME Specifies that GRIT should profile its execution and output the ++ results to the file FNAME. ++ ++Tools: ++ ++ TOOL can be one of the following: ++%s ++ For more information on how to use a particular tool, and the specific ++ arguments you can send to that tool, execute 'grit help TOOL' ++""" % (tool_list)) ++ ++ ++class Options(object): ++ """Option storage and parsing.""" ++ ++ def __init__(self): ++ self.hash = None ++ self.input = None ++ self.verbose = False ++ self.extra_verbose = False ++ self.output_stream = sys.stdout ++ self.profile_dest = None ++ ++ def ReadOptions(self, args): ++ """Reads options from the start of args and returns the remainder.""" ++ (opts, args) = getopt.getopt(args, 'vxi:p:h:', ('help',)) ++ for (key, val) in opts: ++ if key == '-h': self.hash = val ++ elif key == '-i': self.input = val ++ elif key == '-v': ++ self.verbose = True ++ util.verbose = True ++ elif key == '-x': ++ self.verbose = True ++ util.verbose = True ++ self.extra_verbose = True ++ util.extra_verbose = True ++ elif key == '-p': self.profile_dest = val ++ elif key == '--help': ++ PrintUsage() ++ sys.exit(0) ++ ++ if not self.input: ++ if 'GRIT_INPUT' in os.environ: ++ self.input = os.environ['GRIT_INPUT'] ++ else: ++ self.input = 'resource.grd' ++ ++ return args ++ ++ def __repr__(self): ++ return '(verbose: %d, input: %s)' % ( ++ self.verbose, self.input) ++ ++ ++def _GetToolInfo(tool): ++ """Returns the info map for the tool named 'tool' or None if there is no ++ such tool.""" ++ matches = [t for t in _TOOLS if t[0] == tool] ++ if not matches: ++ return None ++ else: ++ return matches[0][1] ++ ++ ++def Main(args=None): ++ """Parses arguments and does the appropriate thing.""" ++ util.ChangeStdoutEncoding() ++ ++ # Support for setuptools console wrappers. ++ if args is None: ++ args = sys.argv[1:] ++ ++ options = Options() ++ try: ++ args = options.ReadOptions(args) # args may be shorter after this ++ except getopt.GetoptError as e: ++ print("grit:", str(e)) ++ print("Try running 'grit help' for valid options.") ++ return 1 ++ if not args: ++ print("No tool provided. Try running 'grit help' for a list of tools.") ++ return 2 ++ ++ tool = args[0] ++ if tool == 'help': ++ if len(args) == 1: ++ PrintUsage() ++ return 0 ++ else: ++ tool = args[1] ++ if not _GetToolInfo(tool): ++ print("No such tool. Try running 'grit help' for a list of tools.") ++ return 2 ++ ++ print("Help for 'grit %s' (for general help, run 'grit help'):\n" % ++ (tool,)) ++ _GetToolInfo(tool)[_FACTORY]().ShowUsage() ++ return 0 ++ if not _GetToolInfo(tool): ++ print("No such tool. Try running 'grit help' for a list of tools.") ++ return 2 ++ ++ try: ++ if _GetToolInfo(tool)[_REQUIRES_INPUT]: ++ os.stat(options.input) ++ except OSError: ++ print('Input file %s not found.\n' ++ 'To specify a different input file:\n' ++ ' 1. Use the GRIT_INPUT environment variable.\n' ++ ' 2. Use the -i command-line option. This overrides ' ++ 'GRIT_INPUT.\n' ++ ' 3. Specify neither GRIT_INPUT or -i and GRIT will try to load ' ++ "'resource.grd'\n" ++ ' from the current directory.' % options.input) ++ return 2 ++ ++ if options.hash: ++ grit.extern.FP.UseUnsignedFingerPrintFromModule(options.hash) ++ ++ try: ++ toolobject = _GetToolInfo(tool)[_FACTORY]() ++ if options.profile_dest: ++ import hotshot ++ prof = hotshot.Profile(options.profile_dest) ++ return prof.runcall(toolobject.Run, options, args[1:]) ++ else: ++ return toolobject.Run(options, args[1:]) ++ except getopt.GetoptError as e: ++ print("grit: %s: %s" % (tool, str(e))) ++ print("Try running 'grit help %s' for valid options." % (tool,)) ++ return 1 ++ ++ ++if __name__ == '__main__': ++ sys.path.append( ++ os.path.join( ++ os.path.dirname( ++ os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), ++ 'diagnosis')) ++ try: ++ import crbug_1001171 ++ with crbug_1001171.DumpStateOnLookupError(): ++ sys.exit(Main(sys.argv[1:])) ++ except ImportError: ++ pass ++ ++ sys.exit(Main(sys.argv[1:])) +diff --git a/tools/grit/grit/grit_runner_unittest.py b/tools/grit/grit/grit_runner_unittest.py +new file mode 100644 +index 0000000000..1487001d81 +--- /dev/null ++++ b/tools/grit/grit/grit_runner_unittest.py +@@ -0,0 +1,42 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grit.py''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) ++ ++import unittest ++ ++from six import StringIO ++ ++from grit import util ++import grit.grit_runner ++ ++class OptionArgsUnittest(unittest.TestCase): ++ def setUp(self): ++ self.buf = StringIO() ++ self.old_stdout = sys.stdout ++ sys.stdout = self.buf ++ ++ def tearDown(self): ++ sys.stdout = self.old_stdout ++ ++ def testSimple(self): ++ grit.grit_runner.Main(['-i', ++ util.PathFromRoot('grit/testdata/simple-input.xml'), ++ 'test', 'bla', 'voff', 'ga']) ++ output = self.buf.getvalue() ++ self.failUnless(output.count("'test'") == 0) # tool name doesn't occur ++ self.failUnless(output.count('bla')) ++ self.failUnless(output.count('simple-input.xml')) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/lazy_re.py b/tools/grit/grit/lazy_re.py +new file mode 100644 +index 0000000000..5c461e87e7 +--- /dev/null ++++ b/tools/grit/grit/lazy_re.py +@@ -0,0 +1,46 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''In GRIT, we used to compile a lot of regular expressions at parse ++time. Since many of them never get used, we use lazy_re to compile ++them on demand the first time they are used, thus speeding up startup ++time in some cases. ++''' ++ ++from __future__ import print_function ++ ++import re ++ ++ ++class LazyRegexObject(object): ++ '''This object creates a RegexObject with the arguments passed in ++ its constructor, the first time any attribute except the several on ++ the class itself is accessed. This accomplishes lazy compilation of ++ the regular expression while maintaining a nearly-identical ++ interface. ++ ''' ++ ++ def __init__(self, *args, **kwargs): ++ self._stash_args = args ++ self._stash_kwargs = kwargs ++ self._lazy_re = None ++ ++ def _LazyInit(self): ++ if not self._lazy_re: ++ self._lazy_re = re.compile(*self._stash_args, **self._stash_kwargs) ++ ++ def __getattribute__(self, name): ++ if name in ('_LazyInit', '_lazy_re', '_stash_args', '_stash_kwargs'): ++ return object.__getattribute__(self, name) ++ else: ++ self._LazyInit() ++ return getattr(self._lazy_re, name) ++ ++ ++def compile(*args, **kwargs): ++ '''Creates a LazyRegexObject that, when invoked on, will compile a ++ re.RegexObject (via re.compile) with the same arguments passed to ++ this function, and delegate almost all of its methods to it. ++ ''' ++ return LazyRegexObject(*args, **kwargs) +diff --git a/tools/grit/grit/lazy_re_unittest.py b/tools/grit/grit/lazy_re_unittest.py +new file mode 100644 +index 0000000000..8488b454ee +--- /dev/null ++++ b/tools/grit/grit/lazy_re_unittest.py +@@ -0,0 +1,40 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit test for lazy_re. ++''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) ++ ++import re ++import unittest ++ ++from grit import lazy_re ++ ++ ++class LazyReUnittest(unittest.TestCase): ++ ++ def testCreatedOnlyOnDemand(self): ++ rex = lazy_re.compile('bingo') ++ self.assertEqual(None, rex._lazy_re) ++ self.assertTrue(rex.match('bingo')) ++ self.assertNotEqual(None, rex._lazy_re) ++ ++ def testJustKwargsWork(self): ++ rex = lazy_re.compile(flags=re.I, pattern='BiNgO') ++ self.assertTrue(rex.match('bingo')) ++ ++ def testPositionalAndKwargsWork(self): ++ rex = lazy_re.compile('BiNgO', flags=re.I) ++ self.assertTrue(rex.match('bingo')) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/node/__init__.py b/tools/grit/grit/node/__init__.py +new file mode 100644 +index 0000000000..2fc0d3360c +--- /dev/null ++++ b/tools/grit/grit/node/__init__.py +@@ -0,0 +1,8 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Package 'grit.node' ++''' ++ ++pass +diff --git a/tools/grit/grit/node/base.py b/tools/grit/grit/node/base.py +new file mode 100644 +index 0000000000..40859d301d +--- /dev/null ++++ b/tools/grit/grit/node/base.py +@@ -0,0 +1,670 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Base types for nodes in a GRIT resource tree. ++''' ++ ++from __future__ import print_function ++ ++import ast ++import os ++import struct ++import sys ++from xml.sax import saxutils ++ ++import six ++ ++from grit import constants ++from grit import clique ++from grit import exception ++from grit import util ++from grit.node import brotli_util ++import grit.format.gzip_string ++ ++ ++class Node(object): ++ '''An item in the tree that has children.''' ++ ++ # Valid content types that can be returned by _ContentType() ++ _CONTENT_TYPE_NONE = 0 # No CDATA content but may have children ++ _CONTENT_TYPE_CDATA = 1 # Only CDATA, no children. ++ _CONTENT_TYPE_MIXED = 2 # CDATA and children, possibly intermingled ++ ++ # Types of files to be compressed by default. ++ _COMPRESS_BY_DEFAULT_EXTENSIONS = ('.js', '.html', '.css', '.svg') ++ ++ # Default nodes to not whitelist skipped ++ _whitelist_marked_as_skip = False ++ ++ # A class-static cache to speed up EvaluateExpression(). ++ # Keys are expressions (e.g. 'is_ios and lang == "fr"'). Values are tuples ++ # (code, variables_in_expr) where code is the compiled expression and can be ++ # directly eval'd, and variables_in_expr is the list of variable and method ++ # names used in the expression (e.g. ['is_ios', 'lang']). ++ eval_expr_cache = {} ++ ++ def __init__(self): ++ self.children = [] # A list of child elements ++ self.mixed_content = [] # A list of u'' and/or child elements (this ++ # duplicates 'children' but ++ # is needed to preserve markup-type content). ++ self.name = u'' # The name of this element ++ self.attrs = {} # The set of attributes (keys to values) ++ self.parent = None # Our parent unless we are the root element. ++ self.uberclique = None # Allows overriding uberclique for parts of tree ++ self.source = None # File that this node was parsed from ++ ++ # This context handler allows you to write "with node:" and get a ++ # line identifying the offending node if an exception escapes from the body ++ # of the with statement. ++ def __enter__(self): ++ return self ++ ++ def __exit__(self, exc_type, exc_value, traceback): ++ if exc_type is not None: ++ print(u'Error processing node %s: %s' % (six.text_type(self), exc_value)) ++ ++ def __iter__(self): ++ '''A preorder iteration through the tree that this node is the root of.''' ++ return self.Preorder() ++ ++ def Preorder(self): ++ '''Generator that generates first this node, then the same generator for ++ any child nodes.''' ++ yield self ++ for child in self.children: ++ for iterchild in child.Preorder(): ++ yield iterchild ++ ++ def ActiveChildren(self): ++ '''Returns the children of this node that should be included in the current ++ configuration. Overridden by .''' ++ return [node for node in self.children if not node.WhitelistMarkedAsSkip()] ++ ++ def ActiveDescendants(self): ++ '''Yields the current node and all descendants that should be included in ++ the current configuration, in preorder.''' ++ yield self ++ for child in self.ActiveChildren(): ++ for descendant in child.ActiveDescendants(): ++ yield descendant ++ ++ def GetRoot(self): ++ '''Returns the root Node in the tree this Node belongs to.''' ++ curr = self ++ while curr.parent: ++ curr = curr.parent ++ return curr ++ ++ # TODO(joi) Use this (currently untested) optimization?: ++ #if hasattr(self, '_root'): ++ # return self._root ++ #curr = self ++ #while curr.parent and not hasattr(curr, '_root'): ++ # curr = curr.parent ++ #if curr.parent: ++ # self._root = curr._root ++ #else: ++ # self._root = curr ++ #return self._root ++ ++ def StartParsing(self, name, parent): ++ '''Called at the start of parsing. ++ ++ Args: ++ name: u'elementname' ++ parent: grit.node.base.Node or subclass or None ++ ''' ++ assert isinstance(name, six.string_types) ++ assert not parent or isinstance(parent, Node) ++ self.name = name ++ self.parent = parent ++ ++ def AddChild(self, child): ++ '''Adds a child to the list of children of this node, if it is a valid ++ child for the node.''' ++ assert isinstance(child, Node) ++ if (not self._IsValidChild(child) or ++ self._ContentType() == self._CONTENT_TYPE_CDATA): ++ explanation = 'invalid child %s for parent %s' % (str(child), self.name) ++ raise exception.UnexpectedChild(explanation) ++ self.children.append(child) ++ self.mixed_content.append(child) ++ ++ def RemoveChild(self, child_id): ++ '''Removes the first node that has a "name" attribute which ++ matches "child_id" in the list of immediate children of ++ this node. ++ ++ Args: ++ child_id: String identifying the child to be removed ++ ''' ++ index = 0 ++ # Safe not to copy since we only remove the first element found ++ for child in self.children: ++ name_attr = child.attrs['name'] ++ if name_attr == child_id: ++ self.children.pop(index) ++ self.mixed_content.pop(index) ++ break ++ index += 1 ++ ++ def AppendContent(self, content): ++ '''Appends a chunk of text as content of this node. ++ ++ Args: ++ content: u'hello' ++ ++ Return: ++ None ++ ''' ++ assert isinstance(content, six.string_types) ++ if self._ContentType() != self._CONTENT_TYPE_NONE: ++ self.mixed_content.append(content) ++ elif content.strip() != '': ++ raise exception.UnexpectedContent() ++ ++ def HandleAttribute(self, attrib, value): ++ '''Informs the node of an attribute that was parsed out of the GRD file ++ for it. ++ ++ Args: ++ attrib: 'name' ++ value: 'fooblat' ++ ++ Return: ++ None ++ ''' ++ assert isinstance(attrib, six.string_types) ++ assert isinstance(value, six.string_types) ++ if self._IsValidAttribute(attrib, value): ++ self.attrs[attrib] = value ++ else: ++ raise exception.UnexpectedAttribute(attrib) ++ ++ def EndParsing(self): ++ '''Called at the end of parsing.''' ++ ++ # TODO(joi) Rewrite this, it's extremely ugly! ++ if len(self.mixed_content): ++ if isinstance(self.mixed_content[0], six.string_types): ++ # Remove leading and trailing chunks of pure whitespace. ++ while (len(self.mixed_content) and ++ isinstance(self.mixed_content[0], six.string_types) and ++ self.mixed_content[0].strip() == ''): ++ self.mixed_content = self.mixed_content[1:] ++ # Strip leading and trailing whitespace from mixed content chunks ++ # at front and back. ++ if (len(self.mixed_content) and ++ isinstance(self.mixed_content[0], six.string_types)): ++ self.mixed_content[0] = self.mixed_content[0].lstrip() ++ # Remove leading and trailing ''' (used to demarcate whitespace) ++ if (len(self.mixed_content) and ++ isinstance(self.mixed_content[0], six.string_types)): ++ if self.mixed_content[0].startswith("'''"): ++ self.mixed_content[0] = self.mixed_content[0][3:] ++ if len(self.mixed_content): ++ if isinstance(self.mixed_content[-1], six.string_types): ++ # Same stuff all over again for the tail end. ++ while (len(self.mixed_content) and ++ isinstance(self.mixed_content[-1], six.string_types) and ++ self.mixed_content[-1].strip() == ''): ++ self.mixed_content = self.mixed_content[:-1] ++ if (len(self.mixed_content) and ++ isinstance(self.mixed_content[-1], six.string_types)): ++ self.mixed_content[-1] = self.mixed_content[-1].rstrip() ++ if (len(self.mixed_content) and ++ isinstance(self.mixed_content[-1], six.string_types)): ++ if self.mixed_content[-1].endswith("'''"): ++ self.mixed_content[-1] = self.mixed_content[-1][:-3] ++ ++ # Check that all mandatory attributes are there. ++ for node_mandatt in self.MandatoryAttributes(): ++ mandatt_list = [] ++ if node_mandatt.find('|') >= 0: ++ mandatt_list = node_mandatt.split('|') ++ else: ++ mandatt_list.append(node_mandatt) ++ ++ mandatt_option_found = False ++ for mandatt in mandatt_list: ++ assert mandatt not in self.DefaultAttributes() ++ if mandatt in self.attrs: ++ if not mandatt_option_found: ++ mandatt_option_found = True ++ else: ++ raise exception.MutuallyExclusiveMandatoryAttribute(mandatt) ++ ++ if not mandatt_option_found: ++ raise exception.MissingMandatoryAttribute(mandatt) ++ ++ # Add default attributes if not specified in input file. ++ for defattr in self.DefaultAttributes(): ++ if not defattr in self.attrs: ++ self.attrs[defattr] = self.DefaultAttributes()[defattr] ++ ++ def GetCdata(self): ++ '''Returns all CDATA of this element, concatenated into a single ++ string. Note that this ignores any elements embedded in CDATA.''' ++ return ''.join([c for c in self.mixed_content ++ if isinstance(c, six.string_types)]) ++ ++ def __str__(self): ++ '''Returns this node and all nodes below it as an XML document in a Unicode ++ string.''' ++ header = u'\n' ++ return header + self.FormatXml() ++ ++ # Some Python 2 glue. ++ __unicode__ = __str__ ++ ++ def FormatXml(self, indent = u'', one_line = False): ++ '''Returns this node and all nodes below it as an XML ++ element in a Unicode string. This differs from __unicode__ in that it does ++ not include the stuff at the top of the string. If one_line is true, ++ children and CDATA are layed out in a way that preserves internal ++ whitespace. ++ ''' ++ assert isinstance(indent, six.string_types) ++ ++ content_one_line = (one_line or ++ self._ContentType() == self._CONTENT_TYPE_MIXED) ++ inside_content = self.ContentsAsXml(indent, content_one_line) ++ ++ # Then the attributes for this node. ++ attribs = u'' ++ default_attribs = self.DefaultAttributes() ++ for attrib, value in sorted(self.attrs.items()): ++ # Only print an attribute if it is other than the default value. ++ if attrib not in default_attribs or value != default_attribs[attrib]: ++ attribs += u' %s=%s' % (attrib, saxutils.quoteattr(value)) ++ ++ # Finally build the XML for our node and return it ++ if len(inside_content) > 0: ++ if one_line: ++ return u'<%s%s>%s' % (self.name, attribs, inside_content, ++ self.name) ++ elif content_one_line: ++ return u'%s<%s%s>\n%s %s\n%s' % ( ++ indent, self.name, attribs, ++ indent, inside_content, ++ indent, self.name) ++ else: ++ return u'%s<%s%s>\n%s\n%s' % ( ++ indent, self.name, attribs, ++ inside_content, ++ indent, self.name) ++ else: ++ return u'%s<%s%s />' % (indent, self.name, attribs) ++ ++ def ContentsAsXml(self, indent, one_line): ++ '''Returns the contents of this node (CDATA and child elements) in XML ++ format. If 'one_line' is true, the content will be laid out on one line.''' ++ assert isinstance(indent, six.string_types) ++ ++ # Build the contents of the element. ++ inside_parts = [] ++ last_item = None ++ for mixed_item in self.mixed_content: ++ if isinstance(mixed_item, Node): ++ inside_parts.append(mixed_item.FormatXml(indent + u' ', one_line)) ++ if not one_line: ++ inside_parts.append(u'\n') ++ else: ++ message = mixed_item ++ # If this is the first item and it starts with whitespace, we add ++ # the ''' delimiter. ++ if not last_item and message.lstrip() != message: ++ message = u"'''" + message ++ inside_parts.append(util.EncodeCdata(message)) ++ last_item = mixed_item ++ ++ # If there are only child nodes and no cdata, there will be a spurious ++ # trailing \n ++ if len(inside_parts) and inside_parts[-1] == '\n': ++ inside_parts = inside_parts[:-1] ++ ++ # If the last item is a string (not a node) and ends with whitespace, ++ # we need to add the ''' delimiter. ++ if (isinstance(last_item, six.string_types) and ++ last_item.rstrip() != last_item): ++ inside_parts[-1] = inside_parts[-1] + u"'''" ++ ++ return u''.join(inside_parts) ++ ++ def SubstituteMessages(self, substituter): ++ '''Applies substitutions to all messages in the tree. ++ ++ Called as a final step of RunGatherers. ++ ++ Args: ++ substituter: a grit.util.Substituter object. ++ ''' ++ for child in self.children: ++ child.SubstituteMessages(substituter) ++ ++ def _IsValidChild(self, child): ++ '''Returns true if 'child' is a valid child of this node. ++ Overridden by subclasses.''' ++ return False ++ ++ def _IsValidAttribute(self, name, value): ++ '''Returns true if 'name' is the name of a valid attribute of this element ++ and 'value' is a valid value for that attribute. Overriden by ++ subclasses unless they have only mandatory attributes.''' ++ return (name in self.MandatoryAttributes() or ++ name in self.DefaultAttributes()) ++ ++ def _ContentType(self): ++ '''Returns the type of content this element can have. Overridden by ++ subclasses. The content type can be one of the _CONTENT_TYPE_XXX constants ++ above.''' ++ return self._CONTENT_TYPE_NONE ++ ++ def MandatoryAttributes(self): ++ '''Returns a list of attribute names that are mandatory (non-optional) ++ on the current element. One can specify a list of ++ "mutually exclusive mandatory" attributes by specifying them as one ++ element in the list, separated by a "|" character. ++ ''' ++ return [] ++ ++ def DefaultAttributes(self): ++ '''Returns a dictionary of attribute names that have defaults, mapped to ++ the default value. Overridden by subclasses.''' ++ return {} ++ ++ def GetCliques(self): ++ '''Returns all MessageClique objects belonging to this node. Overridden ++ by subclasses. ++ ++ Return: ++ [clique1, clique2] or [] ++ ''' ++ return [] ++ ++ def ToRealPath(self, path_from_basedir): ++ '''Returns a real path (which can be absolute or relative to the current ++ working directory), given a path that is relative to the base directory ++ set for the GRIT input file. ++ ++ Args: ++ path_from_basedir: '..' ++ ++ Return: ++ 'resource' ++ ''' ++ return util.normpath(os.path.join(self.GetRoot().GetBaseDir(), ++ os.path.expandvars(path_from_basedir))) ++ ++ def GetInputPath(self): ++ '''Returns a path, relative to the base directory set for the grd file, ++ that points to the file the node refers to. ++ ''' ++ # This implementation works for most nodes that have an input file. ++ return self.attrs['file'] ++ ++ def UberClique(self): ++ '''Returns the uberclique that should be used for messages originating in ++ a given node. If the node itself has its uberclique set, that is what we ++ use, otherwise we search upwards until we find one. If we do not find one ++ even at the root node, we set the root node's uberclique to a new ++ uberclique instance. ++ ''' ++ node = self ++ while not node.uberclique and node.parent: ++ node = node.parent ++ if not node.uberclique: ++ node.uberclique = clique.UberClique() ++ return node.uberclique ++ ++ def IsTranslateable(self): ++ '''Returns false if the node has contents that should not be translated, ++ otherwise returns false (even if the node has no contents). ++ ''' ++ if not 'translateable' in self.attrs: ++ return True ++ else: ++ return self.attrs['translateable'] == 'true' ++ ++ def IsAccessibilityWithNoUI(self): ++ '''Returns true if the node is marked as an accessibility label and the ++ message isn't shown in the UI. Otherwise returns false. This label is ++ used to determine if the text requires screenshots.''' ++ if not 'is_accessibility_with_no_ui' in self.attrs: ++ return False ++ else: ++ return self.attrs['is_accessibility_with_no_ui'] == 'true' ++ ++ def GetNodeById(self, id): ++ '''Returns the node in the subtree parented by this node that has a 'name' ++ attribute matching 'id'. Returns None if no such node is found. ++ ''' ++ for node in self: ++ if 'name' in node.attrs and node.attrs['name'] == id: ++ return node ++ return None ++ ++ def GetChildrenOfType(self, type): ++ '''Returns a list of all subnodes (recursing to all leaves) of this node ++ that are of the indicated type (or tuple of types). ++ ++ Args: ++ type: A type you could use with isinstance(). ++ ++ Return: ++ A list, possibly empty. ++ ''' ++ return [child for child in self if isinstance(child, type)] ++ ++ def GetTextualIds(self): ++ '''Returns a list of the textual ids of this node. ++ ''' ++ if 'name' in self.attrs: ++ return [self.attrs['name']] ++ return [] ++ ++ @classmethod ++ def EvaluateExpression(cls, expr, defs, target_platform, extra_variables={}): ++ '''Worker for EvaluateCondition (below) and conditions in XTB files.''' ++ if expr in cls.eval_expr_cache: ++ code, variables_in_expr = cls.eval_expr_cache[expr] ++ else: ++ # Get a list of all variable and method names used in the expression. ++ syntax_tree = ast.parse(expr, mode='eval') ++ variables_in_expr = [node.id for node in ast.walk(syntax_tree) if ++ isinstance(node, ast.Name) and node.id not in ('True', 'False')] ++ code = compile(syntax_tree, filename='', mode='eval') ++ cls.eval_expr_cache[expr] = code, variables_in_expr ++ ++ # Set values only for variables that are needed to eval the expression. ++ variable_map = {} ++ for name in variables_in_expr: ++ if name == 'os': ++ value = target_platform ++ elif name == 'defs': ++ value = defs ++ ++ elif name == 'is_linux': ++ value = target_platform.startswith('linux') ++ elif name == 'is_macosx': ++ value = target_platform == 'darwin' ++ elif name == 'is_win': ++ value = target_platform in ('cygwin', 'win32') ++ elif name == 'is_android': ++ value = target_platform == 'android' ++ elif name == 'is_ios': ++ value = target_platform == 'ios' ++ elif name == 'is_bsd': ++ value = 'bsd' in target_platform ++ elif name == 'is_posix': ++ value = (target_platform in ('darwin', 'linux2', 'linux3', 'sunos5', ++ 'android', 'ios') ++ or 'bsd' in target_platform) ++ ++ elif name == 'pp_ifdef': ++ def pp_ifdef(symbol): ++ return symbol in defs ++ value = pp_ifdef ++ elif name == 'pp_if': ++ def pp_if(symbol): ++ return defs.get(symbol, False) ++ value = pp_if ++ ++ elif name in defs: ++ value = defs[name] ++ elif name in extra_variables: ++ value = extra_variables[name] ++ else: ++ # Undefined variables default to False. ++ value = False ++ ++ variable_map[name] = value ++ ++ eval_result = eval(code, {}, variable_map) ++ assert isinstance(eval_result, bool) ++ return eval_result ++ ++ def EvaluateCondition(self, expr): ++ '''Returns true if and only if the Python expression 'expr' evaluates ++ to true. ++ ++ The expression is given a few local variables: ++ - 'lang' is the language currently being output ++ (the 'lang' attribute of the element). ++ - 'context' is the current output context ++ (the 'context' attribute of the element). ++ - 'defs' is a map of C preprocessor-style symbol names to their values. ++ - 'os' is the current platform (likely 'linux2', 'win32' or 'darwin'). ++ - 'pp_ifdef(symbol)' is a shorthand for "symbol in defs". ++ - 'pp_if(symbol)' is a shorthand for "symbol in defs and defs[symbol]". ++ - 'is_linux', 'is_macosx', 'is_win', 'is_posix' are true if 'os' ++ matches the given platform. ++ ''' ++ root = self.GetRoot() ++ lang = getattr(root, 'output_language', '') ++ context = getattr(root, 'output_context', '') ++ defs = getattr(root, 'defines', {}) ++ target_platform = getattr(root, 'target_platform', '') ++ extra_variables = { ++ 'lang': lang, ++ 'context': context, ++ } ++ return Node.EvaluateExpression( ++ expr, defs, target_platform, extra_variables) ++ ++ def OnlyTheseTranslations(self, languages): ++ '''Turns off loading of translations for languages not in the provided list. ++ ++ Attrs: ++ languages: ['fr', 'zh_cn'] ++ ''' ++ for node in self: ++ if (hasattr(node, 'IsTranslation') and ++ node.IsTranslation() and ++ node.GetLang() not in languages): ++ node.DisableLoading() ++ ++ def FindBooleanAttribute(self, attr, default, skip_self): ++ '''Searches all ancestors of the current node for the nearest enclosing ++ definition of the given boolean attribute. ++ ++ Args: ++ attr: 'fallback_to_english' ++ default: What to return if no node defines the attribute. ++ skip_self: Don't check the current node, only its parents. ++ ''' ++ p = self.parent if skip_self else self ++ while p: ++ value = p.attrs.get(attr, 'default').lower() ++ if value != 'default': ++ return (value == 'true') ++ p = p.parent ++ return default ++ ++ def PseudoIsAllowed(self): ++ '''Returns true if this node is allowed to use pseudo-translations. This ++ is true by default, unless this node is within a node that has ++ the allow_pseudo attribute set to false. ++ ''' ++ return self.FindBooleanAttribute('allow_pseudo', ++ default=True, skip_self=True) ++ ++ def ShouldFallbackToEnglish(self): ++ '''Returns true iff this node should fall back to English when ++ pseudotranslations are disabled and no translation is available for a ++ given message. ++ ''' ++ return self.FindBooleanAttribute('fallback_to_english', ++ default=False, skip_self=True) ++ ++ def WhitelistMarkedAsSkip(self): ++ '''Returns true if the node is marked to be skipped in the output by a ++ whitelist. ++ ''' ++ return self._whitelist_marked_as_skip ++ ++ def SetWhitelistMarkedAsSkip(self, mark_skipped): ++ '''Sets WhitelistMarkedAsSkip. ++ ''' ++ self._whitelist_marked_as_skip = mark_skipped ++ ++ def ExpandVariables(self): ++ '''Whether we need to expand variables on a given node.''' ++ return False ++ ++ def IsResourceMapSource(self): ++ '''Whether this node is a resource map source.''' ++ return False ++ ++ def CompressDataIfNeeded(self, data): ++ '''Compress data using the format specified in the compress attribute. ++ ++ Args: ++ data: The data to compressed. ++ Returns: ++ The data in gzipped or brotli compressed format. If the format is ++ unspecified then this returns the data uncompressed. ++ ''' ++ ++ compress = self.attrs.get('compress') ++ ++ # Compress JS, HTML, CSS and SVG files by default (gzip), unless |compress| ++ # is explicitly specified. ++ compress_by_default = (compress == 'default' ++ and self.attrs.get('file').endswith( ++ self._COMPRESS_BY_DEFAULT_EXTENSIONS)) ++ ++ if compress == 'gzip' or compress_by_default: ++ # We only use rsyncable compression on Linux. ++ # We exclude ChromeOS since ChromeOS bots are Linux based but do not have ++ # the --rsyncable option built in for gzip. See crbug.com/617950. ++ if sys.platform == 'linux2' and 'chromeos' not in self.GetRoot().defines: ++ return grit.format.gzip_string.GzipStringRsyncable(data) ++ return grit.format.gzip_string.GzipString(data) ++ ++ if compress == 'brotli': ++ # The length of the uncompressed data as 8 bytes little-endian. ++ size_bytes = struct.pack(" ') ++ ++ ph = message.PhNode() ++ ph.StartParsing(u'ph', None) ++ ph.HandleAttribute(u'name', u'USERNAME') ++ ph.AppendContent(u'$1') ++ ex = message.ExNode() ++ ex.StartParsing(u'ex', None) ++ ex.AppendContent(u'Joi') ++ ex.EndParsing() ++ ph.AddChild(ex) ++ ph.EndParsing() ++ ++ node.AddChild(ph) ++ node.EndParsing() ++ ++ non_indented_xml = node.FormatXml() ++ self.failUnless(non_indented_xml == u'\n Hello ' ++ u'<young> $1Joi' ++ u'\n') ++ ++ indented_xml = node.FormatXml(u' ') ++ self.failUnless(indented_xml == u' \n Hello ' ++ u'<young> $1Joi' ++ u'\n ') ++ ++ def testXmlFormatMixedContentWithLeadingWhitespace(self): ++ # Again test using the Message node type, because it is the only mixed ++ # content node. ++ node = message.MessageNode() ++ node.StartParsing(u'message', None) ++ node.HandleAttribute(u'name', u'name') ++ node.AppendContent(u"''' Hello ") ++ ++ ph = message.PhNode() ++ ph.StartParsing(u'ph', None) ++ ph.HandleAttribute(u'name', u'USERNAME') ++ ph.AppendContent(u'$1') ++ ex = message.ExNode() ++ ex.StartParsing(u'ex', None) ++ ex.AppendContent(u'Joi') ++ ex.EndParsing() ++ ph.AddChild(ex) ++ ph.EndParsing() ++ ++ node.AddChild(ph) ++ node.AppendContent(u" yessiree '''") ++ node.EndParsing() ++ ++ non_indented_xml = node.FormatXml() ++ self.failUnless(non_indented_xml == ++ u"\n ''' Hello" ++ u' <young> $1Joi' ++ u" yessiree '''\n") ++ ++ indented_xml = node.FormatXml(u' ') ++ self.failUnless(indented_xml == ++ u" \n ''' Hello" ++ u' <young> $1Joi' ++ u" yessiree '''\n ") ++ ++ self.failUnless(node.GetNodeById('name')) ++ ++ def testXmlFormatContentWithEntities(self): ++ '''Tests a bug where   would not be escaped correctly.''' ++ from grit import tclib ++ msg_node = message.MessageNode.Construct(None, tclib.Message( ++ text = 'BEGIN_BOLDHelloWHITESPACEthere!END_BOLD Bingo!', ++ placeholders = [ ++ tclib.Placeholder('BEGIN_BOLD', '', 'bla'), ++ tclib.Placeholder('WHITESPACE', ' ', 'bla'), ++ tclib.Placeholder('END_BOLD', '', 'bla')]), ++ 'BINGOBONGO') ++ xml = msg_node.FormatXml() ++ self.failUnless(xml.find(' ') == -1, 'should have no entities') ++ ++ def testIter(self): ++ # First build a little tree of message and ph nodes. ++ node = message.MessageNode() ++ node.StartParsing(u'message', None) ++ node.HandleAttribute(u'name', u'bla') ++ node.AppendContent(u" ''' two spaces ") ++ node.AppendContent(u' space before and after ') ++ ph = message.PhNode() ++ ph.StartParsing(u'ph', None) ++ ph.AddChild(message.ExNode()) ++ ph.HandleAttribute(u'name', u'BINGO') ++ ph.AppendContent(u'bongo') ++ node.AddChild(ph) ++ node.AddChild(message.PhNode()) ++ node.AppendContent(u" space before two after '''") ++ ++ order = [message.MessageNode, message.PhNode, message.ExNode, message.PhNode] ++ for n in node: ++ self.failUnless(type(n) == order[0]) ++ order = order[1:] ++ self.failUnless(len(order) == 0) ++ ++ def testGetChildrenOfType(self): ++ xml = ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Hello! ++ ++ ++ ''' ++ grd = grd_reader.Parse(StringIO(xml), ++ util.PathFromRoot('grit/test/data')) ++ from grit.node import node_io ++ output_nodes = grd.GetChildrenOfType(node_io.OutputNode) ++ self.failUnlessEqual(len(output_nodes), 3) ++ self.failUnlessEqual(output_nodes[2].attrs['filename'], ++ 'de/generated_resources.rc') ++ ++ def testEvaluateExpression(self): ++ def AssertExpr(expected_value, expr, defs, target_platform, ++ extra_variables): ++ self.failUnlessEqual(expected_value, base.Node.EvaluateExpression( ++ expr, defs, target_platform, extra_variables)) ++ ++ AssertExpr(True, "True", {}, 'linux', {}) ++ AssertExpr(False, "False", {}, 'linux', {}) ++ AssertExpr(True, "True or False", {}, 'linux', {}) ++ AssertExpr(False, "True and False", {}, 'linux', {}) ++ AssertExpr(True, "os == 'linux'", {}, 'linux', {}) ++ AssertExpr(False, "os == 'linux'", {}, 'ios', {}) ++ AssertExpr(True, "'foo' in defs", {'foo': 'bar'}, 'ios', {}) ++ AssertExpr(False, "'foo' in defs", {'baz': 'bar'}, 'ios', {}) ++ AssertExpr(False, "'foo' in defs", {}, 'ios', {}) ++ AssertExpr(True, "is_linux", {}, 'linux2', {}) ++ AssertExpr(False, "is_linux", {}, 'win32', {}) ++ AssertExpr(True, "is_macosx", {}, 'darwin', {}) ++ AssertExpr(False, "is_macosx", {}, 'ios', {}) ++ AssertExpr(True, "is_win", {}, 'win32', {}) ++ AssertExpr(False, "is_win", {}, 'darwin', {}) ++ AssertExpr(True, "is_android", {}, 'android', {}) ++ AssertExpr(False, "is_android", {}, 'linux3', {}) ++ AssertExpr(True, "is_ios", {}, 'ios', {}) ++ AssertExpr(False, "is_ios", {}, 'darwin', {}) ++ AssertExpr(True, "is_posix", {}, 'linux2', {}) ++ AssertExpr(True, "is_posix", {}, 'darwin', {}) ++ AssertExpr(True, "is_posix", {}, 'android', {}) ++ AssertExpr(True, "is_posix", {}, 'ios', {}) ++ AssertExpr(True, "is_posix", {}, 'freebsd7', {}) ++ AssertExpr(False, "is_posix", {}, 'win32', {}) ++ AssertExpr(True, "pp_ifdef('foo')", {'foo': True}, 'win32', {}) ++ AssertExpr(True, "pp_ifdef('foo')", {'foo': False}, 'win32', {}) ++ AssertExpr(False, "pp_ifdef('foo')", {'bar': True}, 'win32', {}) ++ AssertExpr(True, "pp_if('foo')", {'foo': True}, 'win32', {}) ++ AssertExpr(False, "pp_if('foo')", {'foo': False}, 'win32', {}) ++ AssertExpr(False, "pp_if('foo')", {'bar': True}, 'win32', {}) ++ AssertExpr(True, "foo", {'foo': True}, 'win32', {}) ++ AssertExpr(False, "foo", {'foo': False}, 'win32', {}) ++ AssertExpr(False, "foo", {'bar': True}, 'win32', {}) ++ AssertExpr(True, "foo == 'baz'", {'foo': 'baz'}, 'win32', {}) ++ AssertExpr(False, "foo == 'baz'", {'foo': True}, 'win32', {}) ++ AssertExpr(False, "foo == 'baz'", {}, 'win32', {}) ++ AssertExpr(True, "lang == 'de'", {}, 'win32', {'lang': 'de'}) ++ AssertExpr(False, "lang == 'de'", {}, 'win32', {'lang': 'fr'}) ++ AssertExpr(False, "lang == 'de'", {}, 'win32', {}) ++ ++ # Test a couple more complex expressions for good measure. ++ AssertExpr(True, "is_ios and (lang in ['de', 'fr'] or foo)", ++ {'foo': 'bar'}, 'ios', {'lang': 'fr', 'context': 'today'}) ++ AssertExpr(False, "is_ios and (lang in ['de', 'fr'] or foo)", ++ {'foo': False}, 'linux2', {'lang': 'fr', 'context': 'today'}) ++ AssertExpr(False, "is_ios and (lang in ['de', 'fr'] or foo)", ++ {'baz': 'bar'}, 'ios', {'lang': 'he', 'context': 'today'}) ++ AssertExpr(True, "foo == 'bar' or not baz", ++ {'foo': 'bar', 'fun': True}, 'ios', {'lang': 'en'}) ++ AssertExpr(True, "foo == 'bar' or not baz", ++ {}, 'ios', {'lang': 'en', 'context': 'java'}) ++ AssertExpr(False, "foo == 'bar' or not baz", ++ {'foo': 'ruz', 'baz': True}, 'ios', {'lang': 'en'}) ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/node/brotli_util.py b/tools/grit/grit/node/brotli_util.py +new file mode 100644 +index 0000000000..77f70e49d5 +--- /dev/null ++++ b/tools/grit/grit/node/brotli_util.py +@@ -0,0 +1,29 @@ ++# Copyright 2019 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Framework for compressing resources using Brotli.""" ++ ++import subprocess ++ ++__brotli_executable = None ++ ++ ++def SetBrotliCommand(brotli): ++ # brotli is a list. In production it contains the path to the Brotli executable. ++ # During testing it contains [python, mock_brotli.py] for testing on Windows. ++ global __brotli_executable ++ __brotli_executable = brotli ++ ++ ++def BrotliCompress(data): ++ if not __brotli_executable: ++ raise Exception('Add "use_brotli = true" to you GN grit(...) target ' + ++ 'if you want to use brotli.') ++ compress = subprocess.Popen(__brotli_executable + ['-', '-f'], ++ stdin=subprocess.PIPE, stdout=subprocess.PIPE) ++ return compress.communicate(data)[0] ++ ++def IsInitialized(): ++ global __brotli_executable ++ return __brotli_executable is not None +diff --git a/tools/grit/grit/node/custom/__init__.py b/tools/grit/grit/node/custom/__init__.py +new file mode 100644 +index 0000000000..e179cf7730 +--- /dev/null ++++ b/tools/grit/grit/node/custom/__init__.py +@@ -0,0 +1,8 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Package 'grit.node.custom' ++''' ++ ++pass +diff --git a/tools/grit/grit/node/custom/filename.py b/tools/grit/grit/node/custom/filename.py +new file mode 100644 +index 0000000000..55a27e58c1 +--- /dev/null ++++ b/tools/grit/grit/node/custom/filename.py +@@ -0,0 +1,29 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''A CustomType for filenames.''' ++ ++from __future__ import print_function ++ ++from grit import clique ++from grit import lazy_re ++ ++ ++class WindowsFilename(clique.CustomType): ++ '''Validates that messages can be used as Windows filenames, and strips ++ illegal characters out of translations. ++ ''' ++ ++ BANNED = lazy_re.compile(r'\+|:|\/|\\\\|\*|\?|\"|\<|\>|\|') ++ ++ def Validate(self, message): ++ return not self.BANNED.search(message.GetPresentableContent()) ++ ++ def ValidateAndModify(self, lang, translation): ++ is_ok = self.Validate(translation) ++ self.ModifyEachTextPart(lang, translation) ++ return is_ok ++ ++ def ModifyTextPart(self, lang, text): ++ return self.BANNED.sub(' ', text) +diff --git a/tools/grit/grit/node/custom/filename_unittest.py b/tools/grit/grit/node/custom/filename_unittest.py +new file mode 100644 +index 0000000000..8e2a6dd64a +--- /dev/null ++++ b/tools/grit/grit/node/custom/filename_unittest.py +@@ -0,0 +1,34 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grit.node.custom.filename''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../../..')) ++ ++import unittest ++from grit.node.custom import filename ++from grit import clique ++from grit import tclib ++ ++ ++class WindowsFilenameUnittest(unittest.TestCase): ++ ++ def testValidate(self): ++ factory = clique.UberClique() ++ msg = tclib.Message(text='Bingo bongo') ++ c = factory.MakeClique(msg) ++ c.SetCustomType(filename.WindowsFilename()) ++ translation = tclib.Translation(id=msg.GetId(), text='Bilingo bolongo:') ++ c.AddTranslation(translation, 'fr') ++ self.failUnless(c.MessageForLanguage('fr').GetRealContent() == 'Bilingo bolongo ') ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/node/empty.py b/tools/grit/grit/node/empty.py +new file mode 100644 +index 0000000000..e19d2c4ddb +--- /dev/null ++++ b/tools/grit/grit/node/empty.py +@@ -0,0 +1,64 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Container nodes that don't have any logic. ++''' ++ ++from __future__ import print_function ++ ++from grit.node import base ++from grit.node import include ++from grit.node import message ++from grit.node import misc ++from grit.node import node_io ++from grit.node import structure ++ ++ ++class GroupingNode(base.Node): ++ '''Base class for all the grouping elements (, , ++ and ).''' ++ def DefaultAttributes(self): ++ return { ++ 'first_id' : '', ++ 'comment' : '', ++ 'fallback_to_english' : 'false', ++ 'fallback_to_low_resolution' : 'false', ++ } ++ ++ ++class IncludesNode(GroupingNode): ++ '''The element.''' ++ def _IsValidChild(self, child): ++ return isinstance(child, (include.IncludeNode, misc.IfNode, misc.PartNode)) ++ ++ ++class MessagesNode(GroupingNode): ++ '''The element.''' ++ def _IsValidChild(self, child): ++ return isinstance(child, (message.MessageNode, misc.IfNode, misc.PartNode)) ++ ++ ++class StructuresNode(GroupingNode): ++ '''The element.''' ++ def _IsValidChild(self, child): ++ return isinstance(child, (structure.StructureNode, ++ misc.IfNode, misc.PartNode)) ++ ++ ++class TranslationsNode(base.Node): ++ '''The element.''' ++ def _IsValidChild(self, child): ++ return isinstance(child, (node_io.FileNode, misc.IfNode, misc.PartNode)) ++ ++ ++class OutputsNode(base.Node): ++ '''The element.''' ++ def _IsValidChild(self, child): ++ return isinstance(child, (node_io.OutputNode, misc.IfNode, misc.PartNode)) ++ ++ ++class IdentifiersNode(GroupingNode): ++ '''The element.''' ++ def _IsValidChild(self, child): ++ return isinstance(child, misc.IdentifierNode) +diff --git a/tools/grit/grit/node/include.py b/tools/grit/grit/node/include.py +new file mode 100644 +index 0000000000..b06b9889bb +--- /dev/null ++++ b/tools/grit/grit/node/include.py +@@ -0,0 +1,170 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Handling of the element. ++""" ++ ++from __future__ import print_function ++ ++import os ++ ++from grit import util ++import grit.format.html_inline ++import grit.format.rc ++from grit.format import minifier ++from grit.node import base ++ ++class IncludeNode(base.Node): ++ """An element.""" ++ ++ def __init__(self): ++ super(IncludeNode, self).__init__() ++ ++ # Cache flattened data so that we don't flatten the same file ++ # multiple times. ++ self._flattened_data = None ++ # Also keep track of the last filename we flattened to, so we can ++ # avoid doing it more than once. ++ self._last_flat_filename = None ++ ++ def _IsValidChild(self, child): ++ return False ++ ++ def _GetFlattenedData( ++ self, allow_external_script=False, preprocess_only=False): ++ if not self._flattened_data: ++ filename = self.ToRealPath(self.GetInputPath()) ++ self._flattened_data = ( ++ grit.format.html_inline.InlineToString(filename, self, ++ preprocess_only=preprocess_only, ++ allow_external_script=allow_external_script)) ++ return self._flattened_data.encode('utf-8') ++ ++ def MandatoryAttributes(self): ++ return ['name', 'type', 'file'] ++ ++ def DefaultAttributes(self): ++ """Attributes: ++ translateable: False if the node has contents that should not be ++ translated. ++ preprocess: Takes the same code path as flattenhtml, but it ++ disables any processing/inlining outside of ++ and . ++ compress: The format to compress the data with, e.g. 'gzip' ++ or 'false' if data should not be compressed. ++ skip_minify: If true, skips minifying the node's contents. ++ skip_in_resource_map: If true, do not add to the resource map. ++ """ ++ return { ++ 'translateable': 'true', ++ 'generateid': 'true', ++ 'filenameonly': 'false', ++ 'mkoutput': 'false', ++ 'preprocess': 'false', ++ 'flattenhtml': 'false', ++ 'compress': 'default', ++ 'allowexternalscript': 'false', ++ 'relativepath': 'false', ++ 'use_base_dir': 'true', ++ 'skip_minify': 'false', ++ 'skip_in_resource_map': 'false', ++ } ++ ++ def GetInputPath(self): ++ # Do not mess with absolute paths, that would make them invalid. ++ if os.path.isabs(os.path.expandvars(self.attrs['file'])): ++ return self.attrs['file'] ++ ++ # We have no control over code that calls ToRealPath later, so convert ++ # the path to be relative against our basedir. ++ if self.attrs.get('use_base_dir', 'true') != 'true': ++ # Normalize the directory path to use the appropriate OS separator. ++ # GetBaseDir() may return paths\like\this or paths/like/this, since it is ++ # read from the base_dir attribute in the grd file. ++ norm_base_dir = util.normpath(self.GetRoot().GetBaseDir()) ++ return os.path.relpath(self.attrs['file'], norm_base_dir) ++ ++ return self.attrs['file'] ++ ++ def FileForLanguage(self, lang, output_dir): ++ """Returns the file for the specified language. This allows us to return ++ different files for different language variants of the include file. ++ """ ++ input_path = self.GetInputPath() ++ if input_path is None: ++ return None ++ ++ return self.ToRealPath(input_path) ++ ++ def GetDataPackValue(self, lang, encoding): ++ '''Returns bytes or a str represenation for a data_pack entry.''' ++ filename = self.ToRealPath(self.GetInputPath()) ++ if self.attrs['flattenhtml'] == 'true': ++ allow_external_script = self.attrs['allowexternalscript'] == 'true' ++ data = self._GetFlattenedData(allow_external_script=allow_external_script) ++ elif self.attrs['preprocess'] == 'true': ++ data = self._GetFlattenedData(preprocess_only=True) ++ else: ++ data = util.ReadFile(filename, util.BINARY) ++ ++ if self.attrs['skip_minify'] != 'true': ++ # Note that the minifier will only do anything if a minifier command ++ # has been set in the command line. ++ data = minifier.Minify(data, filename) ++ ++ # Include does not care about the encoding, because it only returns binary ++ # data. ++ return self.CompressDataIfNeeded(data) ++ ++ def Process(self, output_dir): ++ """Rewrite file references to be base64 encoded data URLs. The new file ++ will be written to output_dir and the name of the new file is returned.""" ++ filename = self.ToRealPath(self.GetInputPath()) ++ flat_filename = os.path.join(output_dir, ++ self.attrs['name'] + '_' + os.path.basename(filename)) ++ ++ if self._last_flat_filename == flat_filename: ++ return ++ ++ with open(flat_filename, 'wb') as outfile: ++ outfile.write(self._GetFlattenedData()) ++ ++ self._last_flat_filename = flat_filename ++ return os.path.basename(flat_filename) ++ ++ def GetHtmlResourceFilenames(self): ++ """Returns a set of all filenames inlined by this file.""" ++ allow_external_script = self.attrs['allowexternalscript'] == 'true' ++ return grit.format.html_inline.GetResourceFilenames( ++ self.ToRealPath(self.GetInputPath()), ++ self, ++ allow_external_script=allow_external_script) ++ ++ def IsResourceMapSource(self): ++ skip = self.attrs.get('skip_in_resource_map', 'false') == 'true' ++ return not skip ++ ++ @staticmethod ++ def Construct(parent, name, type, file, translateable=True, ++ filenameonly=False, mkoutput=False, relativepath=False): ++ """Creates a new node which is a child of 'parent', with attributes set ++ by parameters of the same name. ++ """ ++ # Convert types to appropriate strings ++ translateable = util.BoolToString(translateable) ++ filenameonly = util.BoolToString(filenameonly) ++ mkoutput = util.BoolToString(mkoutput) ++ relativepath = util.BoolToString(relativepath) ++ ++ node = IncludeNode() ++ node.StartParsing('include', parent) ++ node.HandleAttribute('name', name) ++ node.HandleAttribute('type', type) ++ node.HandleAttribute('file', file) ++ node.HandleAttribute('translateable', translateable) ++ node.HandleAttribute('filenameonly', filenameonly) ++ node.HandleAttribute('mkoutput', mkoutput) ++ node.HandleAttribute('relativepath', relativepath) ++ node.EndParsing() ++ return node +diff --git a/tools/grit/grit/node/include_unittest.py b/tools/grit/grit/node/include_unittest.py +new file mode 100644 +index 0000000000..4c658f1ffe +--- /dev/null ++++ b/tools/grit/grit/node/include_unittest.py +@@ -0,0 +1,134 @@ ++#!/usr/bin/env python ++# Copyright (c) 2013 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for include.IncludeNode''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++import unittest ++import zlib ++ ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++from grit.node import misc ++from grit.node import include ++from grit.node import empty ++from grit import util ++ ++ ++def checkIsGzipped(filename, compress_attr): ++ test_data_root = util.PathFromRoot('grit/testdata') ++ root = util.ParseGrdForUnittest( ++ ''' ++ ++ ++ ''' % (filename, compress_attr), ++ base_dir=test_data_root) ++ node, = root.GetChildrenOfType(include.IncludeNode) ++ compressed = node.GetDataPackValue(lang='en', encoding=util.BINARY) ++ ++ decompressed_data = zlib.decompress(compressed, 16 + zlib.MAX_WBITS) ++ expected = util.ReadFile(os.path.join(test_data_root, filename), util.BINARY) ++ return expected == decompressed_data ++ ++ ++class IncludeNodeUnittest(unittest.TestCase): ++ def testGetPath(self): ++ root = misc.GritNode() ++ root.StartParsing(u'grit', None) ++ root.HandleAttribute(u'latest_public_release', u'0') ++ root.HandleAttribute(u'current_release', u'1') ++ root.HandleAttribute(u'base_dir', r'..\resource') ++ release = misc.ReleaseNode() ++ release.StartParsing(u'release', root) ++ release.HandleAttribute(u'seq', u'1') ++ root.AddChild(release) ++ includes = empty.IncludesNode() ++ includes.StartParsing(u'includes', release) ++ release.AddChild(includes) ++ include_node = include.IncludeNode() ++ include_node.StartParsing(u'include', includes) ++ include_node.HandleAttribute(u'file', r'flugel\kugel.pdf') ++ includes.AddChild(include_node) ++ root.EndParsing() ++ ++ self.assertEqual(root.ToRealPath(include_node.GetInputPath()), ++ util.normpath( ++ os.path.join(r'../resource', r'flugel/kugel.pdf'))) ++ ++ def testGetPathNoBasedir(self): ++ root = misc.GritNode() ++ root.StartParsing(u'grit', None) ++ root.HandleAttribute(u'latest_public_release', u'0') ++ root.HandleAttribute(u'current_release', u'1') ++ root.HandleAttribute(u'base_dir', r'..\resource') ++ release = misc.ReleaseNode() ++ release.StartParsing(u'release', root) ++ release.HandleAttribute(u'seq', u'1') ++ root.AddChild(release) ++ includes = empty.IncludesNode() ++ includes.StartParsing(u'includes', release) ++ release.AddChild(includes) ++ include_node = include.IncludeNode() ++ include_node.StartParsing(u'include', includes) ++ include_node.HandleAttribute(u'file', r'flugel\kugel.pdf') ++ include_node.HandleAttribute(u'use_base_dir', u'false') ++ includes.AddChild(include_node) ++ root.EndParsing() ++ ++ last_dir = os.path.basename(os.getcwd()) ++ expected_path = util.normpath(os.path.join( ++ u'..', last_dir, u'flugel/kugel.pdf')) ++ self.assertEqual(root.ToRealPath(include_node.GetInputPath()), ++ expected_path) ++ ++ def testCompressGzip(self): ++ self.assertTrue(checkIsGzipped('test_text.txt', 'compress="gzip"')) ++ ++ def testCompressGzipByDefault(self): ++ self.assertTrue(checkIsGzipped('test_html.html', '')) ++ self.assertTrue(checkIsGzipped('test_js.js', '')) ++ self.assertTrue(checkIsGzipped('test_css.css', '')) ++ self.assertTrue(checkIsGzipped('test_svg.svg', '')) ++ ++ self.assertTrue(checkIsGzipped('test_html.html', 'compress="default"')) ++ self.assertTrue(checkIsGzipped('test_js.js', 'compress="default"')) ++ self.assertTrue(checkIsGzipped('test_css.css', 'compress="default"')) ++ self.assertTrue(checkIsGzipped('test_svg.svg', 'compress="default"')) ++ ++ def testSkipInResourceMap(self): ++ root = util.ParseGrdForUnittest(''' ++ ++ ++ ++ ++ ''', base_dir = util.PathFromRoot('grit/testdata')) ++ inc = root.GetChildrenOfType(include.IncludeNode) ++ self.assertTrue(inc[0].IsResourceMapSource()) ++ self.assertFalse(inc[1].IsResourceMapSource()) ++ self.assertTrue(inc[2].IsResourceMapSource()) ++ ++ def testAcceptsPreprocess(self): ++ root = util.ParseGrdForUnittest( ++ ''' ++ ++ ++ ''', ++ base_dir=util.PathFromRoot('grit/testdata')) ++ inc, = root.GetChildrenOfType(include.IncludeNode) ++ result = inc.GetDataPackValue(lang='en', encoding=util.BINARY) ++ self.assertIn(b'should be kept', result) ++ self.assertIn(b'in the middle...', result) ++ self.assertNotIn(b'should be removed', result) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/node/mapping.py b/tools/grit/grit/node/mapping.py +new file mode 100644 +index 0000000000..6297f0b666 +--- /dev/null ++++ b/tools/grit/grit/node/mapping.py +@@ -0,0 +1,60 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Maps each node type to an implementation class. ++When adding a new node type, you add to this mapping. ++''' ++ ++from __future__ import print_function ++ ++from grit import exception ++ ++from grit.node import empty ++from grit.node import include ++from grit.node import message ++from grit.node import misc ++from grit.node import node_io ++from grit.node import structure ++from grit.node import variant ++ ++ ++_ELEMENT_TO_CLASS = { ++ 'identifiers' : empty.IdentifiersNode, ++ 'includes' : empty.IncludesNode, ++ 'messages' : empty.MessagesNode, ++ 'outputs' : empty.OutputsNode, ++ 'structures' : empty.StructuresNode, ++ 'translations' : empty.TranslationsNode, ++ 'include' : include.IncludeNode, ++ 'emit' : node_io.EmitNode, ++ 'file' : node_io.FileNode, ++ 'output' : node_io.OutputNode, ++ 'ex' : message.ExNode, ++ 'message' : message.MessageNode, ++ 'ph' : message.PhNode, ++ 'else' : misc.ElseNode, ++ 'grit' : misc.GritNode, ++ 'identifier' : misc.IdentifierNode, ++ 'if' : misc.IfNode, ++ 'part' : misc.PartNode, ++ 'release' : misc.ReleaseNode, ++ 'then' : misc.ThenNode, ++ 'structure' : structure.StructureNode, ++ 'skeleton' : variant.SkeletonNode, ++} ++ ++ ++def ElementToClass(name, typeattr): ++ '''Maps an element to a class that handles the element. ++ ++ Args: ++ name: 'element' (the name of the element) ++ typeattr: 'type' (the value of the type attribute, if present, else None) ++ ++ Return: ++ type ++ ''' ++ if name not in _ELEMENT_TO_CLASS: ++ raise exception.UnknownElement() ++ return _ELEMENT_TO_CLASS[name] +diff --git a/tools/grit/grit/node/message.py b/tools/grit/grit/node/message.py +new file mode 100644 +index 0000000000..4fa83cf26b +--- /dev/null ++++ b/tools/grit/grit/node/message.py +@@ -0,0 +1,362 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Handling of the element. ++''' ++ ++from __future__ import print_function ++ ++import re ++ ++import six ++ ++from grit.node import base ++ ++from grit import clique ++from grit import exception ++from grit import lazy_re ++from grit import tclib ++from grit import util ++ ++ ++# Matches exactly three dots ending a line or followed by whitespace. ++_ELLIPSIS_PATTERN = lazy_re.compile(r'(?\s*)(?P.+?)(?P\s*)\Z', ++ re.DOTALL | re.MULTILINE) ++ ++# placeholder elements should contain the special character formatters ++# used to format element content. ++# Android format. ++_ANDROID_FORMAT = (r'%[1-9]+\$' ++ r'([-#+ 0,(]*)([0-9]+)?(\.[0-9]+)?' ++ r'([bBhHsScCdoxXeEfgGaAtT%n])') ++# Chrome l10n format. ++_CHROME_FORMAT = r'\$+\d' ++# Windows EWT numeric and GRIT %s %d formats. ++_OTHER_FORMAT = r'%[0-9sd]' ++ ++# Finds formatters that must be in a placeholder () element. ++_FORMATTERS = lazy_re.compile( ++ '(%s)|(%s)|(%s)' % (_ANDROID_FORMAT, _CHROME_FORMAT, _OTHER_FORMAT)) ++_BAD_PLACEHOLDER_MSG = ('ERROR: Placeholder formatter found outside of ' ++ 'tag in message "%s" in %s.') ++_INVALID_PH_CHAR_MSG = ('ERROR: Invalid format characters found in message ' ++ '"%s" tag in %s.') ++ ++# Finds HTML tag tokens. ++_HTMLTOKEN = lazy_re.compile(r'<[/]?[a-z][a-z0-9]*[^>]*>', re.I) ++ ++# Finds HTML entities. ++_HTMLENTITY = lazy_re.compile(r'&[^\s]*;') ++ ++ ++class MessageNode(base.ContentNode): ++ '''A element.''' ++ ++ # For splitting a list of things that can be separated by commas or ++ # whitespace ++ _SPLIT_RE = lazy_re.compile(r'\s*,\s*|\s+') ++ ++ def __init__(self): ++ super(MessageNode, self).__init__() ++ # Valid after EndParsing, this is the MessageClique that contains the ++ # source message and any translations of it that have been loaded. ++ self.clique = None ++ ++ # We don't send leading and trailing whitespace into the translation ++ # console, but rather tack it onto the source message and any ++ # translations when formatting them into RC files or what have you. ++ self.ws_at_start = '' # Any whitespace characters at the start of the text ++ self.ws_at_end = '' # --"-- at the end of the text ++ ++ # A list of "shortcut groups" this message is in. We check to make sure ++ # that shortcut keys (e.g. &J) within each shortcut group are unique. ++ self.shortcut_groups_ = [] ++ ++ # Formatter-specific data used to control the output of individual strings. ++ # formatter_data is a space separated list of C preprocessor-style ++ # definitions. Names without values are given the empty string value. ++ # Example: "foo=5 bar baz=100" ++ self.formatter_data = {} ++ ++ # Whether or not to convert ... -> U+2026 within Translate(). ++ self._replace_ellipsis = False ++ ++ def _IsValidChild(self, child): ++ return isinstance(child, (PhNode)) ++ ++ def _IsValidAttribute(self, name, value): ++ if name not in [ ++ 'name', 'offset', 'translateable', 'desc', 'meaning', ++ 'internal_comment', 'shortcut_groups', 'custom_type', 'validation_expr', ++ 'use_name_for_id', 'sub_variable', 'formatter_data', ++ 'is_accessibility_with_no_ui' ++ ]: ++ return False ++ if (name in ('translateable', 'sub_variable') and ++ value not in ['true', 'false']): ++ return False ++ return True ++ ++ def SetReplaceEllipsis(self, value): ++ r'''Sets whether to replace ... with \u2026. ++ ''' ++ self._replace_ellipsis = value ++ ++ def MandatoryAttributes(self): ++ return ['name|offset'] ++ ++ def DefaultAttributes(self): ++ return { ++ 'custom_type': '', ++ 'desc': '', ++ 'formatter_data': '', ++ 'internal_comment': '', ++ 'is_accessibility_with_no_ui': 'false', ++ 'meaning': '', ++ 'shortcut_groups': '', ++ 'sub_variable': 'false', ++ 'translateable': 'true', ++ 'use_name_for_id': 'false', ++ 'validation_expr': '', ++ } ++ ++ def HandleAttribute(self, attrib, value): ++ base.ContentNode.HandleAttribute(self, attrib, value) ++ if attrib != 'formatter_data': ++ return ++ ++ # Parse value, a space-separated list of defines, into a dict. ++ # Example: "foo=5 bar" -> {'foo':'5', 'bar':''} ++ for item in value.split(): ++ name, _, val = item.partition('=') ++ self.formatter_data[name] = val ++ ++ def GetTextualIds(self): ++ ''' ++ Returns the concatenation of the parent's node first_id and ++ this node's offset if it has one, otherwise just call the ++ superclass' implementation ++ ''' ++ if 'offset' not in self.attrs: ++ return super(MessageNode, self).GetTextualIds() ++ ++ # we search for the first grouping node in the parents' list ++ # to take care of the case where the first parent is an node ++ grouping_parent = self.parent ++ import grit.node.empty ++ while grouping_parent and not isinstance(grouping_parent, ++ grit.node.empty.GroupingNode): ++ grouping_parent = grouping_parent.parent ++ ++ assert 'first_id' in grouping_parent.attrs ++ return [grouping_parent.attrs['first_id'] + '_' + self.attrs['offset']] ++ ++ def IsTranslateable(self): ++ return self.attrs['translateable'] == 'true' ++ ++ def EndParsing(self): ++ super(MessageNode, self).EndParsing() ++ ++ # Make the text (including placeholder references) and list of placeholders, ++ # verify placeholder formats, then strip and store leading and trailing ++ # whitespace and create the tclib.Message() and a clique to contain it. ++ ++ text = '' ++ placeholders = [] ++ ++ for item in self.mixed_content: ++ if isinstance(item, six.string_types): ++ # Not a element: fail if any formatters are detected. ++ if _FORMATTERS.search(item): ++ print(_BAD_PLACEHOLDER_MSG % (item, self.source)) ++ raise exception.PlaceholderNotInsidePhNode ++ text += item ++ else: ++ # Extract the element components. ++ presentation = item.attrs['name'].upper() ++ text += presentation ++ ex = ' ' # example element cdata if present. ++ if len(item.children): ++ ex = item.children[0].GetCdata() ++ original = item.GetCdata() ++ ++ # Sanity check the element content. ++ cdata = original ++ # Replace all HTML tag tokens in cdata. ++ match = _HTMLTOKEN.search(cdata) ++ while match: ++ cdata = cdata.replace(match.group(0), '_') ++ match = _HTMLTOKEN.search(cdata) ++ # Replace all HTML entities in cdata. ++ match = _HTMLENTITY.search(cdata) ++ while match: ++ cdata = cdata.replace(match.group(0), '_') ++ match = _HTMLENTITY.search(cdata) ++ # Remove first matching formatter from cdata. ++ match = _FORMATTERS.search(cdata) ++ if match: ++ cdata = cdata.replace(match.group(0), '') ++ # Fail if special chars remain in cdata. ++ if re.search(r'[%\$]', cdata): ++ message_id = self.attrs['name'] + ' ' + original; ++ print(_INVALID_PH_CHAR_MSG % (message_id, self.source)) ++ raise exception.InvalidCharactersInsidePhNode ++ ++ # Otherwise, accept this placeholder. ++ placeholders.append(tclib.Placeholder(presentation, original, ex)) ++ ++ m = _WHITESPACE.match(text) ++ if m: ++ self.ws_at_start = m.group('start') ++ self.ws_at_end = m.group('end') ++ text = m.group('body') ++ ++ self.shortcut_groups_ = self._SPLIT_RE.split(self.attrs['shortcut_groups']) ++ self.shortcut_groups_ = [i for i in self.shortcut_groups_ if i != ''] ++ ++ description_or_id = self.attrs['desc'] ++ if description_or_id == '' and 'name' in self.attrs: ++ description_or_id = 'ID: %s' % self.attrs['name'] ++ ++ assigned_id = None ++ if self.attrs['use_name_for_id'] == 'true': ++ assigned_id = self.attrs['name'] ++ message = tclib.Message(text=text, placeholders=placeholders, ++ description=description_or_id, ++ meaning=self.attrs['meaning'], ++ assigned_id=assigned_id) ++ self.InstallMessage(message) ++ ++ def InstallMessage(self, message): ++ '''Sets this node's clique from a tclib.Message instance. ++ ++ Args: ++ message: A tclib.Message. ++ ''' ++ self.clique = self.UberClique().MakeClique(message, self.IsTranslateable()) ++ for group in self.shortcut_groups_: ++ self.clique.AddToShortcutGroup(group) ++ if self.attrs['custom_type'] != '': ++ self.clique.SetCustomType(util.NewClassInstance(self.attrs['custom_type'], ++ clique.CustomType)) ++ elif self.attrs['validation_expr'] != '': ++ self.clique.SetCustomType( ++ clique.OneOffCustomType(self.attrs['validation_expr'])) ++ ++ def SubstituteMessages(self, substituter): ++ '''Applies substitution to this message. ++ ++ Args: ++ substituter: a grit.util.Substituter object. ++ ''' ++ message = substituter.SubstituteMessage(self.clique.GetMessage()) ++ if message is not self.clique.GetMessage(): ++ self.InstallMessage(message) ++ ++ def GetCliques(self): ++ return [self.clique] if self.clique else [] ++ ++ def Translate(self, lang): ++ '''Returns a translated version of this message. ++ ''' ++ assert self.clique ++ msg = self.clique.MessageForLanguage(lang, ++ self.PseudoIsAllowed(), ++ self.ShouldFallbackToEnglish() ++ ).GetRealContent() ++ if self._replace_ellipsis: ++ msg = _ELLIPSIS_PATTERN.sub(_ELLIPSIS_SYMBOL, msg) ++ # Always remove all byte order marks (\uFEFF) https://crbug.com/1033305 ++ msg = msg.replace(u'\uFEFF','') ++ return msg.replace('[GRITLANGCODE]', lang) ++ ++ def NameOrOffset(self): ++ key = 'name' if 'name' in self.attrs else 'offset' ++ return self.attrs[key] ++ ++ def ExpandVariables(self): ++ '''We always expand variables on Messages.''' ++ return True ++ ++ def GetDataPackValue(self, lang, encoding): ++ '''Returns a str represenation for a data_pack entry.''' ++ message = self.ws_at_start + self.Translate(lang) + self.ws_at_end ++ return util.Encode(message, encoding) ++ ++ def IsResourceMapSource(self): ++ return True ++ ++ @staticmethod ++ def Construct(parent, message, name, desc='', meaning='', translateable=True): ++ '''Constructs a new message node that is a child of 'parent', with the ++ name, desc, meaning and translateable attributes set using the same-named ++ parameters and the text of the message and any placeholders taken from ++ 'message', which must be a tclib.Message() object.''' ++ # Convert type to appropriate string ++ translateable = 'true' if translateable else 'false' ++ ++ node = MessageNode() ++ node.StartParsing('message', parent) ++ node.HandleAttribute('name', name) ++ node.HandleAttribute('desc', desc) ++ node.HandleAttribute('meaning', meaning) ++ node.HandleAttribute('translateable', translateable) ++ ++ items = message.GetContent() ++ for ix, item in enumerate(items): ++ if isinstance(item, six.string_types): ++ # Ensure whitespace at front and back of message is correctly handled. ++ if ix == 0: ++ item = "'''" + item ++ if ix == len(items) - 1: ++ item = item + "'''" ++ ++ node.AppendContent(item) ++ else: ++ phnode = PhNode() ++ phnode.StartParsing('ph', node) ++ phnode.HandleAttribute('name', item.GetPresentation()) ++ phnode.AppendContent(item.GetOriginal()) ++ ++ if len(item.GetExample()) and item.GetExample() != ' ': ++ exnode = ExNode() ++ exnode.StartParsing('ex', phnode) ++ exnode.AppendContent(item.GetExample()) ++ exnode.EndParsing() ++ phnode.AddChild(exnode) ++ ++ phnode.EndParsing() ++ node.AddChild(phnode) ++ ++ node.EndParsing() ++ return node ++ ++ ++class PhNode(base.ContentNode): ++ '''A element.''' ++ ++ def _IsValidChild(self, child): ++ return isinstance(child, ExNode) ++ ++ def MandatoryAttributes(self): ++ return ['name'] ++ ++ def EndParsing(self): ++ super(PhNode, self).EndParsing() ++ # We only allow a single example for each placeholder ++ if len(self.children) > 1: ++ raise exception.TooManyExamples() ++ ++ def GetTextualIds(self): ++ # The 'name' attribute is not an ID. ++ return [] ++ ++ ++class ExNode(base.ContentNode): ++ '''An element.''' ++ pass +diff --git a/tools/grit/grit/node/message_unittest.py b/tools/grit/grit/node/message_unittest.py +new file mode 100644 +index 0000000000..7a4cbbedc2 +--- /dev/null ++++ b/tools/grit/grit/node/message_unittest.py +@@ -0,0 +1,380 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grit.node.message''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++import unittest ++ ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++from grit import exception ++from grit import tclib ++from grit import util ++from grit.node import message ++ ++class MessageUnittest(unittest.TestCase): ++ def testMessage(self): ++ root = util.ParseGrdForUnittest(''' ++ ++ ++ Hello %sJoi, how are you doing today? ++ ++ ''') ++ msg, = root.GetChildrenOfType(message.MessageNode) ++ cliques = msg.GetCliques() ++ content = cliques[0].GetMessage().GetPresentableContent() ++ self.failUnless(content == 'Hello USERNAME, how are you doing today?') ++ ++ def testMessageWithWhitespace(self): ++ root = util.ParseGrdForUnittest("""\ ++ ++ ++ ''' Hello there %s ''' ++ ++ """) ++ msg, = root.GetChildrenOfType(message.MessageNode) ++ content = msg.GetCliques()[0].GetMessage().GetPresentableContent() ++ self.failUnless(content == 'Hello there USERNAME') ++ self.failUnless(msg.ws_at_start == ' ') ++ self.failUnless(msg.ws_at_end == ' ') ++ ++ def testConstruct(self): ++ msg = tclib.Message(text=" Hello USERNAME, how are you? BINGO\t\t", ++ placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi'), ++ tclib.Placeholder('BINGO', '%d', '11')]) ++ msg_node = message.MessageNode.Construct(None, msg, 'BINGOBONGO') ++ self.failUnless(msg_node.children[0].name == 'ph') ++ self.failUnless(msg_node.children[0].children[0].name == 'ex') ++ self.failUnless(msg_node.children[0].children[0].GetCdata() == 'Joi') ++ self.failUnless(msg_node.children[1].children[0].GetCdata() == '11') ++ self.failUnless(msg_node.ws_at_start == ' ') ++ self.failUnless(msg_node.ws_at_end == '\t\t') ++ ++ def testUnicodeConstruct(self): ++ text = u'Howdie \u00fe' ++ msg = tclib.Message(text=text) ++ msg_node = message.MessageNode.Construct(None, msg, 'BINGOBONGO') ++ msg_from_node = msg_node.GetCdata() ++ self.failUnless(msg_from_node == text) ++ ++ def testFormatterData(self): ++ root = util.ParseGrdForUnittest("""\ ++ ++ ++ Text ++ ++ """) ++ msg, = root.GetChildrenOfType(message.MessageNode) ++ expected_formatter_data = { ++ 'foo': '123', ++ 'bar': '', ++ 'qux': 'low'} ++ ++ # Can't use assertDictEqual, not available in Python 2.6, so do it ++ # by hand. ++ self.failUnlessEqual(len(expected_formatter_data), ++ len(msg.formatter_data)) ++ for key in expected_formatter_data: ++ self.failUnlessEqual(expected_formatter_data[key], ++ msg.formatter_data[key]) ++ ++ def testReplaceEllipsis(self): ++ root = util.ParseGrdForUnittest(''' ++ ++ ++ A...B.... %sA... B... C... ++ ++ ''') ++ msg, = root.GetChildrenOfType(message.MessageNode) ++ msg.SetReplaceEllipsis(True) ++ content = msg.Translate('en') ++ self.failUnlessEqual(u'A...B.... %s\u2026 B\u2026 C\u2026', content) ++ ++ def testRemoveByteOrderMark(self): ++ root = util.ParseGrdForUnittest(u''' ++ ++ ++ \uFEFFThis\uFEFF i\uFEFFs OK\uFEFF ++ ++ ''') ++ msg, = root.GetChildrenOfType(message.MessageNode) ++ content = msg.Translate('en') ++ self.failUnlessEqual(u'This is OK', content) ++ ++ def testPlaceholderHasTooManyExamples(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ Hi $1JoiJoy ++ ++ """) ++ except exception.TooManyExamples: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testPlaceholderHasInvalidName(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ Hi $1 ++ ++ """) ++ except exception.InvalidPlaceholderName: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testChromeLocalizedFormatIsInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ This message is missing the ph node: $1 ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testAndroidStringFormatIsInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ This message is missing a ph node: %1$s ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testAndroidIntegerFormatIsInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ This message is missing a ph node: %2$d ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testAndroidIntegerWidthFormatIsInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ This message is missing a ph node: %2$3d ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testValidAndroidIntegerWidthFormatInPhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ %2$3d042 ++ ++ """) ++ except: ++ self.fail('Should not have gotten exception') ++ ++ def testAndroidFloatFormatIsInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ This message is missing a ph node: %3$4.5f ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testGritStringFormatIsInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ This message is missing the ph node: %s ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testGritIntegerFormatIsInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ This message is missing the ph node: %d ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testWindowsETWIntegerFormatIsInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ This message is missing the ph node: %1 ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testValidMultipleFormattersInsidePhNodes(self): ++ root = util.ParseGrdForUnittest("""\ ++ ++ ++ %1$d1 error, %2$d1 warning ++ ++ """) ++ msg, = root.GetChildrenOfType(message.MessageNode) ++ cliques = msg.GetCliques() ++ content = cliques[0].GetMessage().GetPresentableContent() ++ self.failUnless(content == 'ERROR_COUNT error, WARNING_COUNT warning') ++ ++ def testMultipleFormattersAreInsidePhNodes(self): ++ failed = True ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ %1$d error, %2$d warning ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ failed = False ++ if failed: ++ self.fail('Should have gotten exception') ++ return ++ ++ failed = True ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ %1$d1 error, %2$d warning ++ ++ """) ++ except exception.PlaceholderNotInsidePhNode: ++ failed = False ++ if failed: ++ self.fail('Should have gotten exception') ++ return ++ ++ failed = True ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ %1$d %2$d ++ ++ """) ++ except exception.InvalidCharactersInsidePhNode: ++ failed = False ++ if failed: ++ self.fail('Should have gotten exception') ++ return ++ ++ def testValidHTMLFormatInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ <span>$1</span>1 ++ ++ """) ++ except: ++ self.fail('Should not have gotten exception') ++ ++ def testValidHTMLWithAttributesFormatInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ <span attribute="js:$this %">$2</span>2 ++ ++ """) ++ except: ++ self.fail('Should not have gotten exception') ++ ++ def testValidHTMLEntityFormatInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ >%1$d<1 ++ ++ """) ++ except: ++ self.fail('Should not have gotten exception') ++ ++ def testValidMultipleDollarFormatInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ $$1 ++ ++ """) ++ except: ++ self.fail('Should not have gotten exception') ++ ++ def testInvalidDollarCharacterInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ %1$d $ ++ ++ """) ++ except exception.InvalidCharactersInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testInvalidPercentCharacterInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ %1$d % ++ ++ """) ++ except exception.InvalidCharactersInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ def testInvalidMixedFormatCharactersInsidePhNode(self): ++ try: ++ util.ParseGrdForUnittest("""\ ++ ++ ++ %1$2 ++ ++ """) ++ except exception.InvalidCharactersInsidePhNode: ++ return ++ self.fail('Should have gotten exception') ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/node/misc.py b/tools/grit/grit/node/misc.py +new file mode 100644 +index 0000000000..2d8b06d6a5 +--- /dev/null ++++ b/tools/grit/grit/node/misc.py +@@ -0,0 +1,707 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Miscellaneous node types. ++""" ++ ++from __future__ import print_function ++ ++import os.path ++import re ++import sys ++ ++import six ++ ++from grit import constants ++from grit import exception ++from grit import util ++from grit.extern import FP ++from grit.node import base ++from grit.node import message ++from grit.node import node_io ++ ++ ++# Python 3 doesn't have long() as int() works everywhere. But we really do need ++# the long() behavior on Python 2 as our ids are much too large for int(). ++try: ++ long ++except NameError: ++ long = int ++ ++ ++# RTL languages ++# TODO(jennyz): remove this fixed set of RTL language array ++# now that generic expand_variable code exists. ++_RTL_LANGS = ( ++ 'ar', # Arabic ++ 'fa', # Farsi ++ 'iw', # Hebrew ++ 'ks', # Kashmiri ++ 'ku', # Kurdish ++ 'ps', # Pashto ++ 'ur', # Urdu ++ 'yi', # Yiddish ++) ++ ++ ++def _ReadFirstIdsFromFile(filename, defines): ++ """Read the starting resource id values from |filename|. We also ++ expand variables of the form <(FOO) based on defines passed in on ++ the command line. ++ ++ Returns a tuple, the absolute path of SRCDIR followed by the ++ first_ids dictionary. ++ """ ++ first_ids_dict = eval(util.ReadFile(filename, 'utf-8')) ++ src_root_dir = os.path.abspath(os.path.join(os.path.dirname(filename), ++ first_ids_dict['SRCDIR'])) ++ ++ def ReplaceVariable(matchobj): ++ for key, value in defines.items(): ++ if matchobj.group(1) == key: ++ return value ++ return '' ++ ++ renames = [] ++ for grd_filename in first_ids_dict: ++ new_grd_filename = re.sub(r'<\(([A-Za-z_]+)\)', ReplaceVariable, ++ grd_filename) ++ if new_grd_filename != grd_filename: ++ abs_grd_filename = os.path.abspath(new_grd_filename) ++ if abs_grd_filename[:len(src_root_dir)] != src_root_dir: ++ new_grd_filename = os.path.basename(abs_grd_filename) ++ else: ++ new_grd_filename = abs_grd_filename[len(src_root_dir) + 1:] ++ new_grd_filename = new_grd_filename.replace('\\', '/') ++ renames.append((grd_filename, new_grd_filename)) ++ ++ for grd_filename, new_grd_filename in renames: ++ first_ids_dict[new_grd_filename] = first_ids_dict[grd_filename] ++ del(first_ids_dict[grd_filename]) ++ ++ return (src_root_dir, first_ids_dict) ++ ++ ++def _ComputeIds(root, predetermined_tids): ++ """Returns a dict of textual id -> numeric id for all nodes in root. ++ ++ IDs are mostly assigned sequentially, but will vary based on: ++ * first_id node attribute (from first_ids_file) ++ * hash of textual id (if not first_id is defined) ++ * offset node attribute ++ * whether the textual id matches a system id ++ * whether the node generates its own ID via GetId() ++ ++ Args: ++ predetermined_tids: Dict of textual id -> numeric id to use in return dict. ++ """ ++ from grit.node import empty, include, misc, structure ++ ++ ids = {} # Maps numeric id to textual id ++ tids = {} # Maps textual id to numeric id ++ id_reasons = {} # Maps numeric id to text id and a human-readable explanation ++ group = None ++ last_id = None ++ predetermined_ids = {value: key ++ for key, value in predetermined_tids.items()} ++ ++ for item in root: ++ if isinstance(item, empty.GroupingNode): ++ # Note: this won't work if any GroupingNode can be contained inside ++ # another. ++ group = item ++ last_id = None ++ continue ++ ++ assert not item.GetTextualIds() or isinstance(item, ++ (include.IncludeNode, message.MessageNode, ++ misc.IdentifierNode, structure.StructureNode)) ++ ++ # Resources that use the RES protocol don't need ++ # any numerical ids generated, so we skip them altogether. ++ # This is accomplished by setting the flag 'generateid' to false ++ # in the GRD file. ++ if item.attrs.get('generateid', 'true') == 'false': ++ continue ++ ++ for tid in item.GetTextualIds(): ++ if util.SYSTEM_IDENTIFIERS.match(tid): ++ # Don't emit a new ID for predefined IDs ++ continue ++ ++ if tid in tids: ++ continue ++ ++ if predetermined_tids and tid in predetermined_tids: ++ id = predetermined_tids[tid] ++ reason = "from predetermined_tids map" ++ ++ # Some identifier nodes can provide their own id, ++ # and we use that id in the generated header in that case. ++ elif hasattr(item, 'GetId') and item.GetId(): ++ id = long(item.GetId()) ++ reason = 'returned by GetId() method' ++ ++ elif ('offset' in item.attrs and group and ++ group.attrs.get('first_id', '') != ''): ++ offset_text = item.attrs['offset'] ++ parent_text = group.attrs['first_id'] ++ ++ try: ++ offset_id = long(offset_text) ++ except ValueError: ++ offset_id = tids[offset_text] ++ ++ try: ++ parent_id = long(parent_text) ++ except ValueError: ++ parent_id = tids[parent_text] ++ ++ id = parent_id + offset_id ++ reason = 'first_id %d + offset %d' % (parent_id, offset_id) ++ ++ # We try to allocate IDs sequentially for blocks of items that might ++ # be related, for instance strings in a stringtable (as their IDs might be ++ # used e.g. as IDs for some radio buttons, in which case the IDs must ++ # be sequential). ++ # ++ # We do this by having the first item in a section store its computed ID ++ # (computed from a fingerprint) in its parent object. Subsequent children ++ # of the same parent will then try to get IDs that sequentially follow ++ # the currently stored ID (on the parent) and increment it. ++ elif last_id is None: ++ # First check if the starting ID is explicitly specified by the parent. ++ if group and group.attrs.get('first_id', '') != '': ++ id = long(group.attrs['first_id']) ++ reason = "from parent's first_id attribute" ++ else: ++ # Automatically generate the ID based on the first clique from the ++ # first child of the first child node of our parent (i.e. when we ++ # first get to this location in the code). ++ ++ # According to ++ # http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx ++ # the safe usable range for resource IDs in Windows is from decimal ++ # 101 to 0x7FFF. ++ ++ id = FP.UnsignedFingerPrint(tid) ++ id = id % (0x7FFF - 101) + 101 ++ reason = 'chosen by random fingerprint -- use first_id to override' ++ ++ last_id = id ++ else: ++ id = last_id = last_id + 1 ++ reason = 'sequentially assigned' ++ ++ reason = "%s (%s)" % (tid, reason) ++ # Don't fail when 'offset' is specified, as the base and the 0th ++ # offset will have the same ID. ++ if id in id_reasons and not 'offset' in item.attrs: ++ raise exception.IdRangeOverlap('ID %d was assigned to both %s and %s.' ++ % (id, id_reasons[id], reason)) ++ ++ if id < 101: ++ print('WARNING: Numeric resource IDs should be greater than 100 to\n' ++ 'avoid conflicts with system-defined resource IDs.') ++ ++ if tid not in predetermined_tids and id in predetermined_ids: ++ raise exception.IdRangeOverlap('ID %d overlaps between %s and %s' ++ % (id, tid, predetermined_ids[tid])) ++ ++ ids[id] = tid ++ tids[tid] = id ++ id_reasons[id] = reason ++ ++ return tids ++ ++class SplicingNode(base.Node): ++ """A node whose children should be considered to be at the same level as ++ its siblings for most purposes. This includes and nodes. ++ """ ++ ++ def _IsValidChild(self, child): ++ assert self.parent, '<%s> node should never be root.' % self.name ++ if isinstance(child, SplicingNode): ++ return True # avoid O(n^2) behavior ++ return self.parent._IsValidChild(child) ++ ++ ++class IfNode(SplicingNode): ++ """A node for conditional inclusion of resources. ++ """ ++ ++ def MandatoryAttributes(self): ++ return ['expr'] ++ ++ def _IsValidChild(self, child): ++ return (isinstance(child, (ThenNode, ElseNode)) or ++ super(IfNode, self)._IsValidChild(child)) ++ ++ def EndParsing(self): ++ children = self.children ++ self.if_then_else = False ++ if any(isinstance(node, (ThenNode, ElseNode)) for node in children): ++ if (len(children) != 2 or not isinstance(children[0], ThenNode) or ++ not isinstance(children[1], ElseNode)): ++ raise exception.UnexpectedChild( ++ ' element must be ......') ++ self.if_then_else = True ++ ++ def ActiveChildren(self): ++ cond = self.EvaluateCondition(self.attrs['expr']) ++ if self.if_then_else: ++ return self.children[0 if cond else 1].ActiveChildren() ++ else: ++ # Equivalent to having all children inside with an empty ++ return super(IfNode, self).ActiveChildren() if cond else [] ++ ++ ++class ThenNode(SplicingNode): ++ """A node. Can only appear directly inside an node.""" ++ pass ++ ++ ++class ElseNode(SplicingNode): ++ """An node. Can only appear directly inside an node.""" ++ pass ++ ++ ++class PartNode(SplicingNode): ++ """A node for inclusion of sub-grd (*.grp) files. ++ """ ++ ++ def __init__(self): ++ super(PartNode, self).__init__() ++ self.started_inclusion = False ++ ++ def MandatoryAttributes(self): ++ return ['file'] ++ ++ def _IsValidChild(self, child): ++ return self.started_inclusion and super(PartNode, self)._IsValidChild(child) ++ ++ ++class ReleaseNode(base.Node): ++ """The element.""" ++ ++ def _IsValidChild(self, child): ++ from grit.node import empty ++ return isinstance(child, (empty.IncludesNode, empty.MessagesNode, ++ empty.StructuresNode, empty.IdentifiersNode)) ++ ++ def _IsValidAttribute(self, name, value): ++ return ( ++ (name == 'seq' and int(value) <= self.GetRoot().GetCurrentRelease()) or ++ name == 'allow_pseudo' ++ ) ++ ++ def MandatoryAttributes(self): ++ return ['seq'] ++ ++ def DefaultAttributes(self): ++ return { 'allow_pseudo' : 'true' } ++ ++ ++class GritNode(base.Node): ++ """The root element.""" ++ ++ def __init__(self): ++ super(GritNode, self).__init__() ++ self.output_language = '' ++ self.defines = {} ++ self.substituter = None ++ self.target_platform = sys.platform ++ self.whitelist_support = False ++ self._predetermined_ids_file = None ++ self._id_map = None # Dict of textual_id -> numeric_id. ++ ++ def _IsValidChild(self, child): ++ from grit.node import empty ++ return isinstance(child, (ReleaseNode, empty.TranslationsNode, ++ empty.OutputsNode)) ++ ++ def _IsValidAttribute(self, name, value): ++ if name not in ['base_dir', 'first_ids_file', 'source_lang_id', ++ 'latest_public_release', 'current_release', ++ 'enc_check', 'tc_project', 'grit_version', ++ 'output_all_resource_defines']: ++ return False ++ if name in ['latest_public_release', 'current_release'] and value.strip( ++ '0123456789') != '': ++ return False ++ return True ++ ++ def MandatoryAttributes(self): ++ return ['latest_public_release', 'current_release'] ++ ++ def DefaultAttributes(self): ++ return { ++ 'base_dir' : '.', ++ 'first_ids_file': '', ++ 'grit_version': 1, ++ 'source_lang_id' : 'en', ++ 'enc_check' : constants.ENCODING_CHECK, ++ 'tc_project' : 'NEED_TO_SET_tc_project_ATTRIBUTE', ++ } ++ ++ def EndParsing(self): ++ super(GritNode, self).EndParsing() ++ if (int(self.attrs['latest_public_release']) ++ > int(self.attrs['current_release'])): ++ raise exception.Parsing('latest_public_release cannot have a greater ' ++ 'value than current_release') ++ ++ self.ValidateUniqueIds() ++ ++ # Add the encoding check if it's not present (should ensure that it's always ++ # present in all .grd files generated by GRIT). If it's present, assert if ++ # it's not correct. ++ if 'enc_check' not in self.attrs or self.attrs['enc_check'] == '': ++ self.attrs['enc_check'] = constants.ENCODING_CHECK ++ else: ++ assert self.attrs['enc_check'] == constants.ENCODING_CHECK, ( ++ 'Are you sure your .grd file is in the correct encoding (UTF-8)?') ++ ++ def ValidateUniqueIds(self): ++ """Validate that 'name' attribute is unique in all nodes in this tree ++ except for nodes that are children of nodes. ++ """ ++ unique_names = {} ++ duplicate_names = [] ++ # To avoid false positives from mutually exclusive clauses, check ++ # against whatever the output condition happens to be right now. ++ # TODO(benrg): do something better. ++ for node in self.ActiveDescendants(): ++ if node.attrs.get('generateid', 'true') == 'false': ++ continue # Duplication not relevant in that case ++ ++ for node_id in node.GetTextualIds(): ++ if util.SYSTEM_IDENTIFIERS.match(node_id): ++ continue # predefined IDs are sometimes used more than once ++ ++ if node_id in unique_names and node_id not in duplicate_names: ++ duplicate_names.append(node_id) ++ unique_names[node_id] = 1 ++ ++ if len(duplicate_names): ++ raise exception.DuplicateKey(', '.join(duplicate_names)) ++ ++ ++ def GetCurrentRelease(self): ++ """Returns the current release number.""" ++ return int(self.attrs['current_release']) ++ ++ def GetLatestPublicRelease(self): ++ """Returns the latest public release number.""" ++ return int(self.attrs['latest_public_release']) ++ ++ def GetSourceLanguage(self): ++ """Returns the language code of the source language.""" ++ return self.attrs['source_lang_id'] ++ ++ def GetTcProject(self): ++ """Returns the name of this project in the TranslationConsole, or ++ 'NEED_TO_SET_tc_project_ATTRIBUTE' if it is not defined.""" ++ return self.attrs['tc_project'] ++ ++ def SetOwnDir(self, dir): ++ """Informs the 'grit' element of the directory the file it is in resides. ++ This allows it to calculate relative paths from the input file, which is ++ what we desire (rather than from the current path). ++ ++ Args: ++ dir: r'c:\bla' ++ ++ Return: ++ None ++ """ ++ assert dir ++ self.base_dir = os.path.normpath(os.path.join(dir, self.attrs['base_dir'])) ++ ++ def GetBaseDir(self): ++ """Returns the base directory, relative to the working directory. To get ++ the base directory as set in the .grd file, use GetOriginalBaseDir() ++ """ ++ if hasattr(self, 'base_dir'): ++ return self.base_dir ++ else: ++ return self.GetOriginalBaseDir() ++ ++ def GetOriginalBaseDir(self): ++ """Returns the base directory, as set in the .grd file. ++ """ ++ return self.attrs['base_dir'] ++ ++ def IsWhitelistSupportEnabled(self): ++ return self.whitelist_support ++ ++ def SetWhitelistSupportEnabled(self, whitelist_support): ++ self.whitelist_support = whitelist_support ++ ++ def GetInputFiles(self): ++ """Returns the list of files that are read to produce the output.""" ++ ++ # Importing this here avoids a circular dependency in the imports. ++ # pylint: disable-msg=C6204 ++ from grit.node import include ++ from grit.node import misc ++ from grit.node import structure ++ from grit.node import variant ++ ++ # Check if the input is required for any output configuration. ++ input_files = set() ++ # Collect even inactive PartNodes since they affect ID assignments. ++ for node in self: ++ if isinstance(node, misc.PartNode): ++ input_files.add(self.ToRealPath(node.GetInputPath())) ++ ++ old_output_language = self.output_language ++ for lang, ctx, fallback in self.GetConfigurations(): ++ self.SetOutputLanguage(lang or self.GetSourceLanguage()) ++ self.SetOutputContext(ctx) ++ self.SetFallbackToDefaultLayout(fallback) ++ ++ for node in self.ActiveDescendants(): ++ if isinstance(node, (node_io.FileNode, include.IncludeNode, ++ structure.StructureNode, variant.SkeletonNode)): ++ input_path = node.GetInputPath() ++ if input_path is not None: ++ input_files.add(self.ToRealPath(input_path)) ++ ++ # If it's a flattened node, grab inlined resources too. ++ if ((node.name == 'structure' or node.name == 'include') ++ and node.attrs['flattenhtml'] == 'true'): ++ if node.name == 'structure': ++ node.RunPreSubstitutionGatherer() ++ input_files.update(node.GetHtmlResourceFilenames()) ++ ++ self.SetOutputLanguage(old_output_language) ++ return sorted(input_files) ++ ++ def GetFirstIdsFile(self): ++ """Returns a usable path to the first_ids file, if set, otherwise ++ returns None. ++ ++ The first_ids_file attribute is by default relative to the ++ base_dir of the .grd file, but may be prefixed by GRIT_DIR/, ++ which makes it relative to the directory of grit.py ++ (e.g. GRIT_DIR/../gritsettings/resource_ids). ++ """ ++ if not self.attrs['first_ids_file']: ++ return None ++ ++ path = self.attrs['first_ids_file'] ++ GRIT_DIR_PREFIX = 'GRIT_DIR' ++ if (path.startswith(GRIT_DIR_PREFIX) ++ and path[len(GRIT_DIR_PREFIX)] in ['/', '\\']): ++ return util.PathFromRoot(path[len(GRIT_DIR_PREFIX) + 1:]) ++ else: ++ return self.ToRealPath(path) ++ ++ def GetOutputFiles(self): ++ """Returns the list of nodes that are descendants of this node's ++ child and are not enclosed by unsatisfied conditionals. ++ """ ++ for child in self.children: ++ if child.name == 'outputs': ++ return [node for node in child.ActiveDescendants() ++ if node.name == 'output'] ++ raise exception.MissingElement() ++ ++ def GetConfigurations(self): ++ """Returns the distinct (language, context, fallback_to_default_layout) ++ triples from the output nodes. ++ """ ++ return set((n.GetLanguage(), n.GetContext(), n.GetFallbackToDefaultLayout()) ++ for n in self.GetOutputFiles()) ++ ++ def GetSubstitutionMessages(self): ++ """Returns the list of nodes.""" ++ return [n for n in self.ActiveDescendants() ++ if isinstance(n, message.MessageNode) ++ and n.attrs['sub_variable'] == 'true'] ++ ++ def SetOutputLanguage(self, output_language): ++ """Set the output language. Prepares substitutions. ++ ++ The substitutions are reset every time the language is changed. ++ They include messages designated as variables, and language codes for html ++ and rc files. ++ ++ Args: ++ output_language: a two-letter language code (eg: 'en', 'ar'...) or '' ++ """ ++ if not output_language: ++ # We do not specify the output language for .grh files, ++ # so we get an empty string as the default. ++ # The value should match grit.clique.MessageClique.source_language. ++ output_language = self.GetSourceLanguage() ++ if output_language != self.output_language: ++ self.output_language = output_language ++ self.substituter = None # force recalculate ++ ++ def SetOutputContext(self, output_context): ++ self.output_context = output_context ++ self.substituter = None # force recalculate ++ ++ def SetFallbackToDefaultLayout(self, fallback_to_default_layout): ++ self.fallback_to_default_layout = fallback_to_default_layout ++ self.substituter = None # force recalculate ++ ++ def SetDefines(self, defines): ++ self.defines = defines ++ self.substituter = None # force recalculate ++ ++ def SetTargetPlatform(self, target_platform): ++ self.target_platform = target_platform ++ ++ def GetSubstituter(self): ++ if self.substituter is None: ++ self.substituter = util.Substituter() ++ self.substituter.AddMessages(self.GetSubstitutionMessages(), ++ self.output_language) ++ if self.output_language in _RTL_LANGS: ++ direction = 'dir="RTL"' ++ else: ++ direction = 'dir="LTR"' ++ self.substituter.AddSubstitutions({ ++ 'GRITLANGCODE': self.output_language, ++ 'GRITDIR': direction, ++ }) ++ from grit.format import rc # avoid circular dep ++ rc.RcSubstitutions(self.substituter, self.output_language) ++ return self.substituter ++ ++ def AssignFirstIds(self, filename_or_stream, defines): ++ """Assign first ids to each grouping node based on values from the ++ first_ids file (if specified on the node). ++ """ ++ assert self._id_map is None, 'AssignFirstIds() after InitializeIds()' ++ # If the input is a stream, then we're probably in a unit test and ++ # should skip this step. ++ if not isinstance(filename_or_stream, six.string_types): ++ return ++ ++ # Nothing to do if the first_ids_filename attribute isn't set. ++ first_ids_filename = self.GetFirstIdsFile() ++ if not first_ids_filename: ++ return ++ ++ src_root_dir, first_ids = _ReadFirstIdsFromFile(first_ids_filename, ++ defines) ++ from grit.node import empty ++ for node in self.Preorder(): ++ if isinstance(node, empty.GroupingNode): ++ abs_filename = os.path.abspath(filename_or_stream) ++ if abs_filename[:len(src_root_dir)] != src_root_dir: ++ filename = os.path.basename(filename_or_stream) ++ else: ++ filename = abs_filename[len(src_root_dir) + 1:] ++ filename = filename.replace('\\', '/') ++ ++ if node.attrs['first_id'] != '': ++ raise Exception( ++ "Don't set the first_id attribute when using the first_ids_file " ++ "attribute on the node, update %s instead." % ++ first_ids_filename) ++ ++ try: ++ id_list = first_ids[filename][node.name] ++ except KeyError as e: ++ print('-' * 78) ++ print('Resource id not set for %s (%s)!' % (filename, node.name)) ++ print('Please update %s to include an entry for %s. See the ' ++ 'comments in resource_ids for information on why you need to ' ++ 'update that file.' % (first_ids_filename, filename)) ++ print('-' * 78) ++ raise e ++ ++ try: ++ node.attrs['first_id'] = str(id_list.pop(0)) ++ except IndexError as e: ++ raise Exception('Please update %s and add a first id for %s (%s).' ++ % (first_ids_filename, filename, node.name)) ++ ++ def GetIdMap(self): ++ '''Return a dictionary mapping textual ids to numeric ids.''' ++ return self._id_map ++ ++ def SetPredeterminedIdsFile(self, predetermined_ids_file): ++ assert self._id_map is None, ( ++ 'SetPredeterminedIdsFile() after InitializeIds()') ++ self._predetermined_ids_file = predetermined_ids_file ++ ++ def InitializeIds(self): ++ '''Initializes the text ID -> numeric ID mapping.''' ++ predetermined_id_map = {} ++ if self._predetermined_ids_file: ++ with open(self._predetermined_ids_file) as f: ++ for line in f: ++ tid, nid = line.split() ++ predetermined_id_map[tid] = int(nid) ++ self._id_map = _ComputeIds(self, predetermined_id_map) ++ ++ def RunGatherers(self, debug=False): ++ '''Call RunPreSubstitutionGatherer() on every node of the tree, then apply ++ substitutions, then call RunPostSubstitutionGatherer() on every node. ++ ++ The substitutions step requires that the output language has been set. ++ Locally, get the Substitution messages and add them to the substituter. ++ Also add substitutions for language codes in the Rc. ++ ++ Args: ++ debug: will print information while running gatherers. ++ ''' ++ for node in self.ActiveDescendants(): ++ if hasattr(node, 'RunPreSubstitutionGatherer'): ++ with node: ++ node.RunPreSubstitutionGatherer(debug=debug) ++ ++ assert self.output_language ++ self.SubstituteMessages(self.GetSubstituter()) ++ ++ for node in self.ActiveDescendants(): ++ if hasattr(node, 'RunPostSubstitutionGatherer'): ++ with node: ++ node.RunPostSubstitutionGatherer(debug=debug) ++ ++ ++class IdentifierNode(base.Node): ++ """A node for specifying identifiers that should appear in the resource ++ header file, and be unique amongst all other resource identifiers, but don't ++ have any other attributes or reference any resources. ++ """ ++ ++ def MandatoryAttributes(self): ++ return ['name'] ++ ++ def DefaultAttributes(self): ++ return { 'comment' : '', 'id' : '', 'systemid': 'false' } ++ ++ def GetId(self): ++ """Returns the id of this identifier if it has one, None otherwise ++ """ ++ if 'id' in self.attrs: ++ return self.attrs['id'] ++ return None ++ ++ def EndParsing(self): ++ """Handles system identifiers.""" ++ super(IdentifierNode, self).EndParsing() ++ if self.attrs['systemid'] == 'true': ++ util.SetupSystemIdentifiers((self.attrs['name'],)) ++ ++ @staticmethod ++ def Construct(parent, name, id, comment, systemid='false'): ++ """Creates a new node which is a child of 'parent', with attributes set ++ by parameters of the same name. ++ """ ++ node = IdentifierNode() ++ node.StartParsing('identifier', parent) ++ node.HandleAttribute('name', name) ++ node.HandleAttribute('id', id) ++ node.HandleAttribute('comment', comment) ++ node.HandleAttribute('systemid', systemid) ++ node.EndParsing() ++ return node +diff --git a/tools/grit/grit/node/misc_unittest.py b/tools/grit/grit/node/misc_unittest.py +new file mode 100644 +index 0000000000..c192b096f4 +--- /dev/null ++++ b/tools/grit/grit/node/misc_unittest.py +@@ -0,0 +1,590 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for misc.GritNode''' ++ ++from __future__ import print_function ++ ++import contextlib ++import os ++import sys ++import tempfile ++import unittest ++ ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++from six import StringIO ++ ++from grit import grd_reader ++import grit.exception ++from grit import util ++from grit.format import rc ++from grit.format import rc_header ++from grit.node import misc ++ ++ ++@contextlib.contextmanager ++def _MakeTempPredeterminedIdsFile(content): ++ """Write the |content| string to a temporary file. ++ ++ The temporary file must be deleted by the caller. ++ ++ Example: ++ with _MakeTempPredeterminedIdsFile('foo') as path: ++ ... ++ os.remove(path) ++ ++ Args: ++ content: The string to write. ++ ++ Yields: ++ The name of the temporary file. ++ """ ++ with tempfile.NamedTemporaryFile(mode='w', delete=False) as f: ++ f.write(content) ++ f.flush() ++ f.close() ++ yield f.name ++ ++ ++class GritNodeUnittest(unittest.TestCase): ++ def testUniqueNameAttribute(self): ++ try: ++ restree = grd_reader.Parse( ++ util.PathFromRoot('grit/testdata/duplicate-name-input.xml')) ++ self.fail('Expected parsing exception because of duplicate names.') ++ except grit.exception.Parsing: ++ pass # Expected case ++ ++ def testReadFirstIdsFromFile(self): ++ test_resource_ids = os.path.join(os.path.dirname(__file__), '..', ++ 'testdata', 'resource_ids') ++ base_dir = os.path.dirname(test_resource_ids) ++ ++ src_dir, id_dict = misc._ReadFirstIdsFromFile( ++ test_resource_ids, ++ { ++ 'FOO': os.path.join(base_dir, 'bar'), ++ 'SHARED_INTERMEDIATE_DIR': os.path.join(base_dir, ++ 'out/Release/obj/gen'), ++ }) ++ self.assertEqual({}, id_dict.get('bar/file.grd', None)) ++ self.assertEqual({}, ++ id_dict.get('out/Release/obj/gen/devtools/devtools.grd', None)) ++ ++ src_dir, id_dict = misc._ReadFirstIdsFromFile( ++ test_resource_ids, ++ { ++ 'SHARED_INTERMEDIATE_DIR': '/outside/src_dir', ++ }) ++ self.assertEqual({}, id_dict.get('devtools.grd', None)) ++ ++ # Verifies that GetInputFiles() returns the correct list of files ++ # corresponding to ChromeScaledImage nodes when assets are missing. ++ def testGetInputFilesChromeScaledImage(self): ++ chrome_html_path = util.PathFromRoot('grit/testdata/chrome_html.html') ++ xml = ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''' % chrome_html_path ++ ++ grd = grd_reader.Parse(StringIO(xml), ++ util.PathFromRoot('grit/testdata')) ++ expected = ['chrome_html.html', 'default_100_percent/a.png', ++ 'default_100_percent/b.png', 'included_sample.html', ++ 'special_100_percent/a.png'] ++ actual = [os.path.relpath(path, util.PathFromRoot('grit/testdata')) for ++ path in grd.GetInputFiles()] ++ # Convert path separator for Windows paths. ++ actual = [path.replace('\\', '/') for path in actual] ++ self.assertEquals(expected, actual) ++ ++ # Verifies that GetInputFiles() returns the correct list of files ++ # when files include other files. ++ def testGetInputFilesFromIncludes(self): ++ chrome_html_path = util.PathFromRoot('grit/testdata/chrome_html.html') ++ xml = ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''' % chrome_html_path ++ ++ grd = grd_reader.Parse(StringIO(xml), util.PathFromRoot('grit/testdata')) ++ expected = ['chrome_html.html', 'included_sample.html'] ++ actual = [os.path.relpath(path, util.PathFromRoot('grit/testdata')) for ++ path in grd.GetInputFiles()] ++ # Convert path separator for Windows paths. ++ actual = [path.replace('\\', '/') for path in actual] ++ self.assertEquals(expected, actual) ++ ++ def testNonDefaultEntry(self): ++ grd = util.ParseGrdForUnittest(''' ++ ++ bar ++ ++ bar ++ ++ ''') ++ grd.SetOutputLanguage('fr') ++ output = ''.join(rc_header.Format(grd, 'fr', '.')) ++ self.assertIn('#define IDS_A 2378\n#define IDS_B 2379', output) ++ ++ def testExplicitFirstIdOverlaps(self): ++ # second first_id will overlap preexisting range ++ self.assertRaises(grit.exception.IdRangeOverlap, ++ util.ParseGrdForUnittest, ''' ++ ++ ++ ++ ++ ++ ++ Hello %sJoi, how are you doing today? ++ ++ Frubegfrums ++ ''') ++ ++ def testImplicitOverlapsPreexisting(self): ++ # second message in will overlap preexisting range ++ self.assertRaises(grit.exception.IdRangeOverlap, ++ util.ParseGrdForUnittest, ''' ++ ++ ++ ++ ++ ++ ++ Hello %sJoi, how are you doing today? ++ ++ Frubegfrums ++ ''') ++ ++ def testPredeterminedIds(self): ++ with _MakeTempPredeterminedIdsFile('IDS_A 101\nIDS_B 102') as ids_file: ++ grd = util.ParseGrdForUnittest(''' ++ ++ ++ ++ ++ ++ Hello %sJoi, how are you doing today? ++ ++ ++ Bongo! ++ ++ ''', predetermined_ids_file=ids_file) ++ output = rc_header.FormatDefines(grd) ++ self.assertEqual(('#define IDS_B 102\n' ++ '#define IDS_GREETING 10000\n' ++ '#define IDS_A 101\n'), ''.join(output)) ++ os.remove(ids_file) ++ ++ def testPredeterminedIdsOverlap(self): ++ with _MakeTempPredeterminedIdsFile('ID_LOGO 10000') as ids_file: ++ self.assertRaises(grit.exception.IdRangeOverlap, ++ util.ParseGrdForUnittest, ''' ++ ++ ++ ++ ++ ++ Hello %sJoi, how are you doing today? ++ ++ ++ Bongo! ++ ++ ''', predetermined_ids_file=ids_file) ++ os.remove(ids_file) ++ ++ ++class IfNodeUnittest(unittest.TestCase): ++ def testIffyness(self): ++ grd = grd_reader.Parse(StringIO(''' ++ ++ ++ ++ ++ ++ Bingo! ++ ++ ++ ++ ++ Hello! ++ ++ ++ ++ ++ Good morning ++ ++ ++ ++ is_win ++ ++ ++ ++ '''), dir='.') ++ ++ messages_node = grd.children[0].children[0] ++ bingo_message = messages_node.children[0].children[0] ++ hello_message = messages_node.children[1].children[0] ++ french_message = messages_node.children[2].children[0] ++ is_win_message = messages_node.children[3].children[0] ++ ++ self.assertTrue(bingo_message.name == 'message') ++ self.assertTrue(hello_message.name == 'message') ++ self.assertTrue(french_message.name == 'message') ++ ++ grd.SetOutputLanguage('fr') ++ grd.SetDefines({'hello': '1'}) ++ active = set(grd.ActiveDescendants()) ++ self.failUnless(bingo_message not in active) ++ self.failUnless(hello_message in active) ++ self.failUnless(french_message in active) ++ ++ grd.SetOutputLanguage('en') ++ grd.SetDefines({'bingo': 1}) ++ active = set(grd.ActiveDescendants()) ++ self.failUnless(bingo_message in active) ++ self.failUnless(hello_message not in active) ++ self.failUnless(french_message not in active) ++ ++ grd.SetOutputLanguage('en') ++ grd.SetDefines({'FORCE_FRENCH': '1', 'bingo': '1'}) ++ active = set(grd.ActiveDescendants()) ++ self.failUnless(bingo_message in active) ++ self.failUnless(hello_message not in active) ++ self.failUnless(french_message in active) ++ ++ grd.SetOutputLanguage('en') ++ grd.SetDefines({}) ++ self.failUnless(grd.target_platform == sys.platform) ++ grd.SetTargetPlatform('darwin') ++ active = set(grd.ActiveDescendants()) ++ self.failUnless(is_win_message not in active) ++ grd.SetTargetPlatform('win32') ++ active = set(grd.ActiveDescendants()) ++ self.failUnless(is_win_message in active) ++ ++ def testElsiness(self): ++ grd = util.ParseGrdForUnittest(''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''') ++ included = [msg.attrs['name'] for msg in grd.ActiveDescendants() ++ if msg.name == 'message'] ++ self.assertEqual(['IDS_YES1', 'IDS_YES2', 'IDS_YES3', 'IDS_YES4'], included) ++ ++ def testIffynessWithOutputNodes(self): ++ grd = grd_reader.Parse(StringIO(''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ '''), dir='.') ++ ++ outputs_node = grd.children[0] ++ uncond1_output = outputs_node.children[0] ++ only_fr_adm_output = outputs_node.children[1].children[0] ++ only_fr_plist_output = outputs_node.children[1].children[1] ++ doc_output = outputs_node.children[2].children[0] ++ uncond2_output = outputs_node.children[0] ++ self.assertTrue(uncond1_output.name == 'output') ++ self.assertTrue(only_fr_adm_output.name == 'output') ++ self.assertTrue(only_fr_plist_output.name == 'output') ++ self.assertTrue(doc_output.name == 'output') ++ self.assertTrue(uncond2_output.name == 'output') ++ ++ grd.SetOutputLanguage('ru') ++ grd.SetDefines({'hello': '1'}) ++ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] ++ self.assertEquals( ++ outputs, ++ ['uncond1.rc', 'only_fr.adm', 'only_fr.plist', 'doc.html', ++ 'uncond2.adm', 'iftest.h']) ++ ++ grd.SetOutputLanguage('ru') ++ grd.SetDefines({'bingo': '2'}) ++ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] ++ self.assertEquals( ++ outputs, ++ ['uncond1.rc', 'doc.html', 'uncond2.adm', 'iftest.h']) ++ ++ grd.SetOutputLanguage('fr') ++ grd.SetDefines({'hello': '1'}) ++ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] ++ self.assertEquals( ++ outputs, ++ ['uncond1.rc', 'only_fr.adm', 'only_fr.plist', 'uncond2.adm', ++ 'iftest.h']) ++ ++ grd.SetOutputLanguage('en') ++ grd.SetDefines({'bingo': '1'}) ++ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] ++ self.assertEquals(outputs, ['uncond1.rc', 'uncond2.adm', 'iftest.h']) ++ ++ grd.SetOutputLanguage('fr') ++ grd.SetDefines({'bingo': '1'}) ++ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] ++ self.assertNotEquals(outputs, ['uncond1.rc', 'uncond2.adm', 'iftest.h']) ++ ++ def testChildrenAccepted(self): ++ grd_reader.Parse(StringIO(r''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Bingo! ++ ++ ++ ++ Bingo! ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ '''), dir='.') ++ ++ def testIfBadChildrenNesting(self): ++ # includes ++ xml = StringIO(r''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ''') ++ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) ++ # messages ++ xml = StringIO(r''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ''') ++ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) ++ # structures ++ xml = StringIO(''' ++ ++ ++ ++ ++ Bingo! ++ ++ ++ ++ ''') ++ # translations ++ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) ++ xml = StringIO(''' ++ ++ ++ ++ Bingo! ++ ++ ++ ''') ++ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) ++ # same with nesting ++ xml = StringIO(r''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''') ++ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) ++ xml = StringIO(r''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ''') ++ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) ++ xml = StringIO(''' ++ ++ ++ ++ ++ ++ Bingo! ++ ++ ++ ++ ++ ''') ++ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) ++ xml = StringIO(''' ++ ++ ++ ++ ++ Bingo! ++ ++ ++ ++ ''') ++ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) ++ ++ ++class ReleaseNodeUnittest(unittest.TestCase): ++ def testPseudoControl(self): ++ grd = grd_reader.Parse(StringIO(''' ++ ++ ++ ++ ++ Hello ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Bingo ++ ++ ++ ++ ++ ++ ++ '''), util.PathFromRoot('grit/testdata')) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ ++ hello = grd.GetNodeById('IDS_HELLO') ++ aboutbox = grd.GetNodeById('IDD_ABOUTBOX') ++ bingo = grd.GetNodeById('IDS_BINGO') ++ menu = grd.GetNodeById('IDC_KLONKMENU') ++ ++ for node in [hello, aboutbox]: ++ self.failUnless(not node.PseudoIsAllowed()) ++ ++ for node in [bingo, menu]: ++ self.failUnless(node.PseudoIsAllowed()) ++ ++ # TODO(benrg): There was a test here that formatting hello and aboutbox with ++ # a pseudo language should fail, but they do not fail and the test was ++ # broken and failed to catch it. Fix this. ++ ++ # Should not raise an exception since pseudo is allowed ++ rc.FormatMessage(bingo, 'xyz-pseudo') ++ rc.FormatStructure(menu, 'xyz-pseudo', '.') ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/node/mock_brotli.py b/tools/grit/grit/node/mock_brotli.py +new file mode 100644 +index 0000000000..14237aab20 +--- /dev/null ++++ b/tools/grit/grit/node/mock_brotli.py +@@ -0,0 +1,10 @@ ++#!/usr/bin/env python ++# Copyright 2019 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Mock Brotli Executable for testing purposes.""" ++ ++import sys ++ ++sys.stdout.write('This has been mock compressed!') +diff --git a/tools/grit/grit/node/node_io.py b/tools/grit/grit/node/node_io.py +new file mode 100644 +index 0000000000..ccbc2c0647 +--- /dev/null ++++ b/tools/grit/grit/node/node_io.py +@@ -0,0 +1,117 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''The and elements. ++''' ++ ++from __future__ import print_function ++ ++import os ++ ++from grit import xtb_reader ++from grit.node import base ++ ++ ++class FileNode(base.Node): ++ '''A element.''' ++ ++ def __init__(self): ++ super(FileNode, self).__init__() ++ self.re = None ++ self.should_load_ = True ++ ++ def IsTranslation(self): ++ return True ++ ++ def GetLang(self): ++ return self.attrs['lang'] ++ ++ def DisableLoading(self): ++ self.should_load_ = False ++ ++ def MandatoryAttributes(self): ++ return ['path', 'lang'] ++ ++ def RunPostSubstitutionGatherer(self, debug=False): ++ if not self.should_load_: ++ return ++ ++ root = self.GetRoot() ++ defs = getattr(root, 'defines', {}) ++ target_platform = getattr(root, 'target_platform', '') ++ ++ xtb_file = open(self.ToRealPath(self.GetInputPath()), 'rb') ++ try: ++ lang = xtb_reader.Parse(xtb_file, ++ self.UberClique().GenerateXtbParserCallback( ++ self.attrs['lang'], debug=debug), ++ defs=defs, ++ target_platform=target_platform) ++ except: ++ print("Exception during parsing of %s" % self.GetInputPath()) ++ raise ++ # Translation console uses non-standard language codes 'iw' and 'no' for ++ # Hebrew and Norwegian Bokmal instead of 'he' and 'nb' used in Chrome. ++ # Note that some Chrome's .grd still use 'no' instead of 'nb', but 'nb' is ++ # always used for generated .pak files. ++ ALTERNATIVE_LANG_CODE_MAP = { 'he': 'iw', 'nb': 'no' } ++ assert (lang == self.attrs['lang'] or ++ lang == ALTERNATIVE_LANG_CODE_MAP[self.attrs['lang']]), ( ++ 'The XTB file you reference must contain messages in the language ' ++ 'specified\nby the \'lang\' attribute.') ++ ++ def GetInputPath(self): ++ return os.path.expandvars(self.attrs['path']) ++ ++ ++class OutputNode(base.Node): ++ '''An element.''' ++ ++ def MandatoryAttributes(self): ++ return ['filename', 'type'] ++ ++ def DefaultAttributes(self): ++ return { ++ 'lang' : '', # empty lang indicates all languages ++ 'language_section' : 'neutral', # defines a language neutral section ++ 'context' : '', ++ 'fallback_to_default_layout' : 'true', ++ } ++ ++ def GetType(self): ++ return self.attrs['type'] ++ ++ def GetLanguage(self): ++ '''Returns the language ID, default 'en'.''' ++ return self.attrs['lang'] ++ ++ def GetContext(self): ++ return self.attrs['context'] ++ ++ def GetFilename(self): ++ return self.attrs['filename'] ++ ++ def GetOutputFilename(self): ++ path = None ++ if hasattr(self, 'output_filename'): ++ path = self.output_filename ++ else: ++ path = self.attrs['filename'] ++ return os.path.expandvars(path) ++ ++ def GetFallbackToDefaultLayout(self): ++ return self.attrs['fallback_to_default_layout'].lower() == 'true' ++ ++ def _IsValidChild(self, child): ++ return isinstance(child, EmitNode) ++ ++class EmitNode(base.ContentNode): ++ ''' An element.''' ++ ++ def DefaultAttributes(self): ++ return { 'emit_type' : 'prepend'} ++ ++ def GetEmitType(self): ++ '''Returns the emit_type for this node. Default is 'append'.''' ++ return self.attrs['emit_type'] +diff --git a/tools/grit/grit/node/node_io_unittest.py b/tools/grit/grit/node/node_io_unittest.py +new file mode 100644 +index 0000000000..1f45e51af8 +--- /dev/null ++++ b/tools/grit/grit/node/node_io_unittest.py +@@ -0,0 +1,182 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for node_io.FileNode''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++import unittest ++ ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++from six import StringIO ++ ++from grit.node import misc ++from grit.node import node_io ++from grit.node import empty ++from grit import grd_reader ++from grit import util ++ ++ ++def _GetAllCliques(root_node): ++ """Return all cliques in the |root_node| tree.""" ++ ret = [] ++ for node in root_node: ++ ret.extend(node.GetCliques()) ++ return ret ++ ++ ++class FileNodeUnittest(unittest.TestCase): ++ def testGetPath(self): ++ root = misc.GritNode() ++ root.StartParsing(u'grit', None) ++ root.HandleAttribute(u'latest_public_release', u'0') ++ root.HandleAttribute(u'current_release', u'1') ++ root.HandleAttribute(u'base_dir', r'..\resource') ++ translations = empty.TranslationsNode() ++ translations.StartParsing(u'translations', root) ++ root.AddChild(translations) ++ file_node = node_io.FileNode() ++ file_node.StartParsing(u'file', translations) ++ file_node.HandleAttribute(u'path', r'flugel\kugel.pdf') ++ translations.AddChild(file_node) ++ root.EndParsing() ++ ++ self.failUnless(root.ToRealPath(file_node.GetInputPath()) == ++ util.normpath( ++ os.path.join(r'../resource', r'flugel/kugel.pdf'))) ++ ++ def VerifyCliquesContainEnglishAndFrenchAndNothingElse(self, cliques): ++ self.assertEqual(2, len(cliques)) ++ for clique in cliques: ++ self.assertEqual({'en', 'fr'}, set(clique.clique.keys())) ++ ++ def testLoadTranslations(self): ++ xml = ''' ++ ++ ++ ++ ++ ++ ++ Hello! ++ Hello %sJoi ++ ++ ++ ''' ++ grd = grd_reader.Parse(StringIO(xml), ++ util.PathFromRoot('grit/testdata')) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ self.VerifyCliquesContainEnglishAndFrenchAndNothingElse(_GetAllCliques(grd)) ++ ++ def testIffyness(self): ++ grd = grd_reader.Parse(StringIO(''' ++ ++ ++ ++ ++ ++ ++ ++ ++ Hello! ++ Hello %sJoi ++ ++ ++ '''), util.PathFromRoot('grit/testdata')) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ cliques = _GetAllCliques(grd) ++ self.assertEqual(2, len(cliques)) ++ for clique in cliques: ++ self.assertEqual({'en'}, set(clique.clique.keys())) ++ ++ grd.SetOutputLanguage('fr') ++ grd.RunGatherers() ++ self.VerifyCliquesContainEnglishAndFrenchAndNothingElse(_GetAllCliques(grd)) ++ ++ def testConditionalLoadTranslations(self): ++ xml = ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Hello! ++ Hello %s ++ Joi ++ ++ ++ ''' ++ grd = grd_reader.Parse(StringIO(xml), ++ util.PathFromRoot('grit/testdata')) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ self.VerifyCliquesContainEnglishAndFrenchAndNothingElse(_GetAllCliques(grd)) ++ ++ def testConditionalOutput(self): ++ xml = ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Hello! ++ ++ ++ ''' ++ grd = grd_reader.Parse(StringIO(xml), ++ util.PathFromRoot('grit/test/data'), ++ defines={}) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ outputs = grd.GetChildrenOfType(node_io.OutputNode) ++ active = set(grd.ActiveDescendants()) ++ self.failUnless(outputs[0] in active) ++ self.failUnless(outputs[0].GetType() == 'rc_header') ++ self.failUnless(outputs[1] in active) ++ self.failUnless(outputs[1].GetType() == 'rc_all') ++ self.failUnless(outputs[2] not in active) ++ self.failUnless(outputs[2].GetType() == 'rc_all') ++ ++ # Verify that 'iw' and 'no' language codes in xtb files are mapped to 'he' and ++ # 'nb'. ++ def testLangCodeMapping(self): ++ grd = grd_reader.Parse(StringIO(''' ++ ++ ++ ++ ++ ++ ++ ++ ++ '''), util.PathFromRoot('grit/testdata')) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ self.assertEqual([], _GetAllCliques(grd)) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/node/structure.py b/tools/grit/grit/node/structure.py +new file mode 100644 +index 0000000000..ec170faebb +--- /dev/null ++++ b/tools/grit/grit/node/structure.py +@@ -0,0 +1,375 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''The element. ++''' ++ ++from __future__ import print_function ++ ++import os ++import platform ++import re ++ ++from grit import exception ++from grit import util ++from grit.node import base ++from grit.node import variant ++ ++import grit.gather.admin_template ++import grit.gather.chrome_html ++import grit.gather.chrome_scaled_image ++import grit.gather.policy_json ++import grit.gather.rc ++import grit.gather.tr_html ++import grit.gather.txt ++ ++import grit.format.rc ++ ++# Type of the gatherer to use for each type attribute ++_GATHERERS = { ++ 'accelerators' : grit.gather.rc.Accelerators, ++ 'admin_template' : grit.gather.admin_template.AdmGatherer, ++ 'chrome_html' : grit.gather.chrome_html.ChromeHtml, ++ 'chrome_scaled_image' : grit.gather.chrome_scaled_image.ChromeScaledImage, ++ 'dialog' : grit.gather.rc.Dialog, ++ 'menu' : grit.gather.rc.Menu, ++ 'rcdata' : grit.gather.rc.RCData, ++ 'tr_html' : grit.gather.tr_html.TrHtml, ++ 'txt' : grit.gather.txt.TxtFile, ++ 'version' : grit.gather.rc.Version, ++ 'policy_template_metafile' : grit.gather.policy_json.PolicyJson, ++} ++ ++ ++# TODO(joi) Print a warning if the 'variant_of_revision' attribute indicates ++# that a skeleton variant is older than the original file. ++ ++ ++class StructureNode(base.Node): ++ '''A element.''' ++ ++ # Regular expression for a local variable definition. Each definition ++ # is of the form NAME=VALUE, where NAME cannot contain '=' or ',' and ++ # VALUE must escape all commas: ',' -> ',,'. Each variable definition ++ # should be separated by a comma with no extra whitespace. ++ # Example: THING1=foo,THING2=bar ++ variable_pattern = re.compile(r'([^,=\s]+)=((?:,,|[^,])*)') ++ ++ def __init__(self): ++ super(StructureNode, self).__init__() ++ ++ # Keep track of the last filename we flattened to, so we can ++ # avoid doing it more than once. ++ self._last_flat_filename = None ++ ++ # See _Substitute; this substituter is used for local variables and ++ # the root substituter is used for global variables. ++ self.substituter = None ++ ++ def _IsValidChild(self, child): ++ return isinstance(child, variant.SkeletonNode) ++ ++ def _ParseVariables(self, variables): ++ '''Parse a variable string into a dictionary.''' ++ matches = StructureNode.variable_pattern.findall(variables) ++ return dict((name, value.replace(',,', ',')) for name, value in matches) ++ ++ def EndParsing(self): ++ super(StructureNode, self).EndParsing() ++ ++ # Now that we have attributes and children, instantiate the gatherers. ++ gathertype = _GATHERERS[self.attrs['type']] ++ ++ self.gatherer = gathertype(self.attrs['file'], ++ self.attrs['name'], ++ self.attrs['encoding']) ++ self.gatherer.SetGrdNode(self) ++ self.gatherer.SetUberClique(self.UberClique()) ++ if hasattr(self.GetRoot(), 'defines'): ++ self.gatherer.SetDefines(self.GetRoot().defines) ++ self.gatherer.SetAttributes(self.attrs) ++ if self.ExpandVariables(): ++ self.gatherer.SetFilenameExpansionFunction(self._Substitute) ++ ++ # Parse local variables and instantiate the substituter. ++ if self.attrs['variables']: ++ variables = self.attrs['variables'] ++ self.substituter = util.Substituter() ++ self.substituter.AddSubstitutions(self._ParseVariables(variables)) ++ ++ self.skeletons = {} # Maps expressions to skeleton gatherers ++ for child in self.children: ++ assert isinstance(child, variant.SkeletonNode) ++ skel = gathertype(child.attrs['file'], ++ self.attrs['name'], ++ child.GetEncodingToUse(), ++ is_skeleton=True) ++ skel.SetGrdNode(self) # TODO(benrg): Or child? Only used for ToRealPath ++ skel.SetUberClique(self.UberClique()) ++ if hasattr(self.GetRoot(), 'defines'): ++ skel.SetDefines(self.GetRoot().defines) ++ if self.ExpandVariables(): ++ skel.SetFilenameExpansionFunction(self._Substitute) ++ self.skeletons[child.attrs['expr']] = skel ++ ++ def MandatoryAttributes(self): ++ return ['type', 'name', 'file'] ++ ++ def DefaultAttributes(self): ++ return { ++ 'encoding': 'cp1252', ++ 'exclude_from_rc': 'false', ++ 'line_end': 'unix', ++ 'output_encoding': 'utf-8', ++ 'generateid': 'true', ++ 'expand_variables': 'false', ++ 'output_filename': '', ++ 'fold_whitespace': 'false', ++ # Run an arbitrary command after translation is complete ++ # so that it doesn't interfere with what's in translation ++ # console. ++ 'run_command': '', ++ # Leave empty to run on all platforms, comma-separated ++ # for one or more specific platforms. Values must match ++ # output of platform.system(). ++ 'run_command_on_platforms': '', ++ 'allowexternalscript': 'false', ++ # preprocess takes the same code path as flattenhtml, but it ++ # disables any processing/inlining outside of and . ++ 'preprocess': 'false', ++ 'flattenhtml': 'false', ++ 'fallback_to_low_resolution': 'default', ++ 'variables': '', ++ 'compress': 'default', ++ 'use_base_dir': 'true', ++ } ++ ++ def IsExcludedFromRc(self): ++ return self.attrs['exclude_from_rc'] == 'true' ++ ++ def Process(self, output_dir): ++ """Writes the processed data to output_dir. In the case of a chrome_html ++ structure this will add references to other scale factors. If flattening ++ this will also write file references to be base64 encoded data URLs. The ++ name of the new file is returned.""" ++ filename = self.ToRealPath(self.GetInputPath()) ++ flat_filename = os.path.join(output_dir, ++ self.attrs['name'] + '_' + os.path.basename(filename)) ++ ++ if self._last_flat_filename == flat_filename: ++ return ++ ++ with open(flat_filename, 'wb') as outfile: ++ if self.ExpandVariables(): ++ text = self.gatherer.GetText() ++ file_contents = self._Substitute(text) ++ else: ++ file_contents = self.gatherer.GetData('', 'utf-8') ++ outfile.write(file_contents.encode('utf-8')) ++ ++ self._last_flat_filename = flat_filename ++ return os.path.basename(flat_filename) ++ ++ def GetLineEnd(self): ++ '''Returns the end-of-line character or characters for files output because ++ of this node ('\r\n', '\n', or '\r' depending on the 'line_end' attribute). ++ ''' ++ if self.attrs['line_end'] == 'unix': ++ return '\n' ++ elif self.attrs['line_end'] == 'windows': ++ return '\r\n' ++ elif self.attrs['line_end'] == 'mac': ++ return '\r' ++ else: ++ raise exception.UnexpectedAttribute( ++ "Attribute 'line_end' must be one of 'unix' (default), 'windows' or " ++ "'mac'") ++ ++ def GetCliques(self): ++ return self.gatherer.GetCliques() ++ ++ def GetDataPackValue(self, lang, encoding): ++ """Returns a bytes representation for a data_pack entry.""" ++ if self.ExpandVariables(): ++ text = self.gatherer.GetText() ++ data = util.Encode(self._Substitute(text), encoding) ++ else: ++ data = self.gatherer.GetData(lang, encoding) ++ if encoding != util.BINARY: ++ data = data.encode(encoding) ++ return self.CompressDataIfNeeded(data) ++ ++ def GetHtmlResourceFilenames(self): ++ """Returns a set of all filenames inlined by this node.""" ++ return self.gatherer.GetHtmlResourceFilenames() ++ ++ def GetInputPath(self): ++ path = self.gatherer.GetInputPath() ++ if path is None: ++ return path ++ ++ # Do not mess with absolute paths, that would make them invalid. ++ if os.path.isabs(os.path.expandvars(path)): ++ return path ++ ++ # We have no control over code that calls ToRealPath later, so convert ++ # the path to be relative against our basedir. ++ if self.attrs.get('use_base_dir', 'true') != 'true': ++ # Normalize the directory path to use the appropriate OS separator. ++ # GetBaseDir() may return paths\like\this or paths/like/this, since it is ++ # read from the base_dir attribute in the grd file. ++ norm_base_dir = util.normpath(self.GetRoot().GetBaseDir()) ++ return os.path.relpath(path, norm_base_dir) ++ ++ return path ++ ++ def GetTextualIds(self): ++ if not hasattr(self, 'gatherer'): ++ # This case is needed because this method is called by ++ # GritNode.ValidateUniqueIds before RunGatherers has been called. ++ # TODO(benrg): Fix this? ++ return [self.attrs['name']] ++ return self.gatherer.GetTextualIds() ++ ++ def RunPreSubstitutionGatherer(self, debug=False): ++ if debug: ++ print('Running gatherer %s for file %s' % ++ (type(self.gatherer), self.GetInputPath())) ++ ++ # Note: Parse() is idempotent, therefore this method is also. ++ self.gatherer.Parse() ++ for skel in self.skeletons.values(): ++ skel.Parse() ++ ++ def GetSkeletonGatherer(self): ++ '''Returns the gatherer for the alternate skeleton that should be used, ++ based on the expressions for selecting skeletons, or None if the skeleton ++ from the English version of the structure should be used. ++ ''' ++ for expr in self.skeletons: ++ if self.EvaluateCondition(expr): ++ return self.skeletons[expr] ++ return None ++ ++ def HasFileForLanguage(self): ++ return self.attrs['type'] in ['tr_html', 'admin_template', 'txt', ++ 'chrome_scaled_image', ++ 'chrome_html'] ++ ++ def ExpandVariables(self): ++ '''Variable expansion on structures is controlled by an XML attribute. ++ ++ However, old files assume that expansion is always on for Rc files. ++ ++ Returns: ++ A boolean. ++ ''' ++ attrs = self.GetRoot().attrs ++ if 'grit_version' in attrs and attrs['grit_version'] > 1: ++ return self.attrs['expand_variables'] == 'true' ++ else: ++ return (self.attrs['expand_variables'] == 'true' or ++ self.attrs['file'].lower().endswith('.rc')) ++ ++ def _Substitute(self, text): ++ '''Perform local and global variable substitution.''' ++ if self.substituter: ++ text = self.substituter.Substitute(text) ++ return self.GetRoot().GetSubstituter().Substitute(text) ++ ++ def RunCommandOnCurrentPlatform(self): ++ if self.attrs['run_command_on_platforms'] == '': ++ return True ++ else: ++ target_platforms = self.attrs['run_command_on_platforms'].split(',') ++ return platform.system() in target_platforms ++ ++ def FileForLanguage(self, lang, output_dir, create_file=True, ++ return_if_not_generated=True): ++ '''Returns the filename of the file associated with this structure, ++ for the specified language. ++ ++ Args: ++ lang: 'fr' ++ output_dir: 'c:\temp' ++ create_file: True ++ ''' ++ assert self.HasFileForLanguage() ++ # If the source language is requested, and no extra changes are requested, ++ # use the existing file. ++ if ((not lang or lang == self.GetRoot().GetSourceLanguage()) and ++ self.attrs['expand_variables'] != 'true' and ++ (not self.attrs['run_command'] or ++ not self.RunCommandOnCurrentPlatform())): ++ if return_if_not_generated: ++ input_path = self.GetInputPath() ++ if input_path is None: ++ return None ++ return self.ToRealPath(input_path) ++ else: ++ return None ++ ++ if self.attrs['output_filename'] != '': ++ filename = self.attrs['output_filename'] ++ else: ++ filename = os.path.basename(self.attrs['file']) ++ assert len(filename) ++ filename = '%s_%s' % (lang, filename) ++ filename = os.path.join(output_dir, filename) ++ ++ # Only create the output if it was requested by the call. ++ if create_file: ++ text = self.gatherer.Translate( ++ lang, ++ pseudo_if_not_available=self.PseudoIsAllowed(), ++ fallback_to_english=self.ShouldFallbackToEnglish(), ++ skeleton_gatherer=self.GetSkeletonGatherer()) ++ ++ file_contents = util.FixLineEnd(text, self.GetLineEnd()) ++ if self.ExpandVariables(): ++ # Note that we reapply substitution a second time here. ++ # This is because a) we need to look inside placeholders ++ # b) the substitution values are language-dependent ++ file_contents = self._Substitute(file_contents) ++ ++ with open(filename, 'wb') as file_object: ++ output_stream = util.WrapOutputStream(file_object, ++ self.attrs['output_encoding']) ++ output_stream.write(file_contents) ++ ++ if self.attrs['run_command'] and self.RunCommandOnCurrentPlatform(): ++ # Run arbitrary commands after translation is complete so that it ++ # doesn't interfere with what's in translation console. ++ command = self.attrs['run_command'] % {'filename': filename} ++ result = os.system(command) ++ assert result == 0, '"%s" failed.' % command ++ ++ return filename ++ ++ def IsResourceMapSource(self): ++ return True ++ ++ @staticmethod ++ def Construct(parent, name, type, file, encoding='cp1252'): ++ '''Creates a new node which is a child of 'parent', with attributes set ++ by parameters of the same name. ++ ''' ++ node = StructureNode() ++ node.StartParsing('structure', parent) ++ node.HandleAttribute('name', name) ++ node.HandleAttribute('type', type) ++ node.HandleAttribute('file', file) ++ node.HandleAttribute('encoding', encoding) ++ node.EndParsing() ++ return node ++ ++ def SubstituteMessages(self, substituter): ++ '''Propagates substitution to gatherer. ++ ++ Args: ++ substituter: a grit.util.Substituter object. ++ ''' ++ assert hasattr(self, 'gatherer') ++ if self.ExpandVariables(): ++ self.gatherer.SubstituteMessages(substituter) +diff --git a/tools/grit/grit/node/structure_unittest.py b/tools/grit/grit/node/structure_unittest.py +new file mode 100644 +index 0000000000..0e66dce37a +--- /dev/null ++++ b/tools/grit/grit/node/structure_unittest.py +@@ -0,0 +1,178 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for nodes. ++''' ++ ++from __future__ import print_function ++ ++import os ++import os.path ++import sys ++import zlib ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import platform ++import tempfile ++import unittest ++import struct ++ ++from grit import constants ++from grit import util ++from grit.node import brotli_util ++from grit.node import structure ++from grit.format import rc ++ ++ ++def checkIsGzipped(filename, compress_attr): ++ test_data_root = util.PathFromRoot('grit/testdata') ++ root = util.ParseGrdForUnittest( ++ ''' ++ ++ ++ ''' % (filename, compress_attr), ++ base_dir=test_data_root) ++ node, = root.GetChildrenOfType(structure.StructureNode) ++ node.RunPreSubstitutionGatherer() ++ compressed = node.GetDataPackValue(lang='en', encoding=util.BINARY) ++ ++ decompressed_data = zlib.decompress(compressed, 16 + zlib.MAX_WBITS) ++ expected = util.ReadFile(os.path.join(test_data_root, filename), util.BINARY) ++ return expected == decompressed_data ++ ++ ++class StructureUnittest(unittest.TestCase): ++ def testSkeleton(self): ++ grd = util.ParseGrdForUnittest(''' ++ ++ ++ ++ ++ ''', base_dir=util.PathFromRoot('grit/testdata')) ++ grd.SetOutputLanguage('fr') ++ grd.RunGatherers() ++ transl = ''.join(rc.Format(grd, 'fr', '.')) ++ self.failUnless(transl.count('040704') and transl.count('110978')) ++ self.failUnless(transl.count('2005",IDC_STATIC')) ++ ++ def testRunCommandOnCurrentPlatform(self): ++ node = structure.StructureNode() ++ node.attrs = node.DefaultAttributes() ++ self.failUnless(node.RunCommandOnCurrentPlatform()) ++ node.attrs['run_command_on_platforms'] = 'Nosuch' ++ self.failIf(node.RunCommandOnCurrentPlatform()) ++ node.attrs['run_command_on_platforms'] = ( ++ 'Nosuch,%s,Othernot' % platform.system()) ++ self.failUnless(node.RunCommandOnCurrentPlatform()) ++ ++ def testVariables(self): ++ grd = util.ParseGrdForUnittest(''' ++ ++ ++ ''', base_dir=util.PathFromRoot('grit/testdata')) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ node, = grd.GetChildrenOfType(structure.StructureNode) ++ filename = node.Process(tempfile.gettempdir()) ++ filepath = os.path.join(tempfile.gettempdir(), filename) ++ with open(filepath) as f: ++ result = f.read() ++ self.failUnlessEqual(('

Hello!

\n' ++ 'Some cool things are foo, bar, baz.\n' ++ 'Did you know that 2+2==4?\n' ++ '

\n' ++ ' Hello!\n' ++ '

\n'), result) ++ os.remove(filepath) ++ ++ def testGetPath(self): ++ base_dir = util.PathFromRoot('grit/testdata') ++ grd = util.ParseGrdForUnittest(''' ++ ++ ++ ''', base_dir) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ node, = grd.GetChildrenOfType(structure.StructureNode) ++ self.assertEqual(grd.ToRealPath(node.GetInputPath()), ++ os.path.abspath(os.path.join( ++ base_dir, r'structure_variables.html'))) ++ ++ def testGetPathNoBasedir(self): ++ base_dir = util.PathFromRoot('grit/testdata') ++ abs_path = os.path.join(base_dir, r'structure_variables.html') ++ rel_path = os.path.relpath(abs_path, os.getcwd()) ++ grd = util.ParseGrdForUnittest(''' ++ ++ ++ ''', util.PathFromRoot('grit/testdata')) ++ grd.SetOutputLanguage('en') ++ grd.RunGatherers() ++ node, = grd.GetChildrenOfType(structure.StructureNode) ++ self.assertEqual(grd.ToRealPath(node.GetInputPath()), ++ os.path.abspath(os.path.join( ++ base_dir, r'structure_variables.html'))) ++ ++ def testCompressGzip(self): ++ self.assertTrue(checkIsGzipped('test_text.txt', 'compress="gzip"')) ++ ++ def testCompressGzipByDefault(self): ++ self.assertTrue(checkIsGzipped('test_html.html', '')) ++ self.assertTrue(checkIsGzipped('test_js.js', '')) ++ self.assertTrue(checkIsGzipped('test_css.css', '')) ++ self.assertTrue(checkIsGzipped('test_svg.svg', '')) ++ ++ self.assertTrue(checkIsGzipped('test_html.html', 'compress="default"')) ++ self.assertTrue(checkIsGzipped('test_js.js', 'compress="default"')) ++ self.assertTrue(checkIsGzipped('test_css.css', 'compress="default"')) ++ self.assertTrue(checkIsGzipped('test_svg.svg', 'compress="default"')) ++ ++ def testCompressBrotli(self): ++ test_data_root = util.PathFromRoot('grit/testdata') ++ root = util.ParseGrdForUnittest( ++ ''' ++ ++ ++ ''', ++ base_dir=test_data_root) ++ node, = root.GetChildrenOfType(structure.StructureNode) ++ node.RunPreSubstitutionGatherer() ++ ++ # Using the mock brotli decompression executable. ++ brotli_util.SetBrotliCommand([sys.executable, ++ os.path.join(os.path.dirname(__file__), ++ 'mock_brotli.py')]) ++ compressed = node.GetDataPackValue(lang='en', encoding=util.BINARY) ++ # Assert that the first two bytes in compressed format is BROTLI_CONST. ++ self.assertEqual(constants.BROTLI_CONST, compressed[0:2]) ++ ++ # Compare the actual size of the uncompressed test data with ++ # the size appended during compression. ++ actual_size = len(util.ReadFile( ++ os.path.join(test_data_root, 'test_text.txt'), util.BINARY)) ++ uncompress_size = struct.unpack(' ++ ++ ''', base_dir=test_data_root) ++ node, = root.GetChildrenOfType(structure.StructureNode) ++ node.RunPreSubstitutionGatherer() ++ data = node.GetDataPackValue(lang='en', encoding=util.BINARY) ++ ++ self.assertEqual(util.ReadFile( ++ os.path.join(test_data_root, 'test_text.txt'), util.BINARY), data) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/node/variant.py b/tools/grit/grit/node/variant.py +new file mode 100644 +index 0000000000..9f5845f954 +--- /dev/null ++++ b/tools/grit/grit/node/variant.py +@@ -0,0 +1,41 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''The element. ++''' ++ ++from __future__ import print_function ++ ++from grit.node import base ++ ++ ++class SkeletonNode(base.Node): ++ '''A element.''' ++ ++ # TODO(joi) Support inline skeleton variants as CDATA instead of requiring ++ # a 'file' attribute. ++ ++ def MandatoryAttributes(self): ++ return ['expr', 'variant_of_revision', 'file'] ++ ++ def DefaultAttributes(self): ++ '''If not specified, 'encoding' will actually default to the parent node's ++ encoding. ++ ''' ++ return {'encoding' : ''} ++ ++ def _ContentType(self): ++ if 'file' in self.attrs: ++ return self._CONTENT_TYPE_NONE ++ else: ++ return self._CONTENT_TYPE_CDATA ++ ++ def GetEncodingToUse(self): ++ if self.attrs['encoding'] == '': ++ return self.parent.attrs['encoding'] ++ else: ++ return self.attrs['encoding'] ++ ++ def GetInputPath(self): ++ return self.attrs['file'] +diff --git a/tools/grit/grit/pseudo.py b/tools/grit/grit/pseudo.py +new file mode 100644 +index 0000000000..b607bfc6bb +--- /dev/null ++++ b/tools/grit/grit/pseudo.py +@@ -0,0 +1,129 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Pseudotranslation support. Our pseudotranslations are based on the ++P-language, which is a simple vowel-extending language. Examples of P: ++ - "hello" becomes "hepellopo" ++ - "howdie" becomes "hopowdiepie" ++ - "because" becomes "bepecaupause" (but in our implementation we don't ++ handle the silent e at the end so it actually would return "bepecaupausepe" ++ ++The P-language has the excellent quality of increasing the length of text ++by around 30-50% which is great for pseudotranslations, to stress test any ++GUI layouts etc. ++ ++To make the pseudotranslations more obviously "not a translation" and to make ++them exercise any code that deals with encodings, we also transform all English ++vowels into equivalent vowels with diacriticals on them (rings, acutes, ++diaresis, and circumflex), and we write the "p" in the P-language as a Hebrew ++character Qof. It looks sort of like a latin character "p" but it is outside ++the latin-1 character set which will stress character encoding bugs. ++''' ++ ++from __future__ import print_function ++ ++from grit import lazy_re ++from grit import tclib ++ ++ ++# An RFC language code for the P pseudolanguage. ++PSEUDO_LANG = 'x-P-pseudo' ++ ++# Hebrew character Qof. It looks kind of like a 'p' but is outside ++# the latin-1 character set which is good for our purposes. ++# TODO(joi) For now using P instead of Qof, because of some bugs it used. Find ++# a better solution, i.e. one that introduces a non-latin1 character into the ++# pseudotranslation. ++#_QOF = u'\u05e7' ++_QOF = u'P' ++ ++# How we map each vowel. ++_VOWELS = { ++ u'a' : u'\u00e5', # a with ring ++ u'e' : u'\u00e9', # e acute ++ u'i' : u'\u00ef', # i diaresis ++ u'o' : u'\u00f4', # o circumflex ++ u'u' : u'\u00fc', # u diaresis ++ u'y' : u'\u00fd', # y acute ++ u'A' : u'\u00c5', # A with ring ++ u'E' : u'\u00c9', # E acute ++ u'I' : u'\u00cf', # I diaresis ++ u'O' : u'\u00d4', # O circumflex ++ u'U' : u'\u00dc', # U diaresis ++ u'Y' : u'\u00dd', # Y acute ++} ++_VOWELS_KEYS = set(_VOWELS.keys()) ++ ++# Matches vowels and P ++_PSUB_RE = lazy_re.compile("(%s)" % '|'.join(_VOWELS_KEYS | {'P'})) ++ ++ ++# Pseudotranslations previously created. This is important for performance ++# reasons, especially since we routinely pseudotranslate the whole project ++# several or many different times for each build. ++_existing_translations = {} ++ ++ ++def MapVowels(str, also_p = False): ++ '''Returns a copy of 'str' where characters that exist as keys in _VOWELS ++ have been replaced with the corresponding value. If also_p is true, this ++ function will also change capital P characters into a Hebrew character Qof. ++ ''' ++ def Repl(match): ++ if match.group() == 'p': ++ if also_p: ++ return _QOF ++ else: ++ return 'p' ++ else: ++ return _VOWELS[match.group()] ++ return _PSUB_RE.sub(Repl, str) ++ ++ ++def PseudoString(str): ++ '''Returns a pseudotranslation of the provided string, in our enhanced ++ P-language.''' ++ if str in _existing_translations: ++ return _existing_translations[str] ++ ++ outstr = u'' ++ ix = 0 ++ while ix < len(str): ++ if str[ix] not in _VOWELS_KEYS: ++ outstr += str[ix] ++ ix += 1 ++ else: ++ # We want to treat consecutive vowels as one composite vowel. This is not ++ # always accurate e.g. in composite words but good enough. ++ consecutive_vowels = u'' ++ while ix < len(str) and str[ix] in _VOWELS_KEYS: ++ consecutive_vowels += str[ix] ++ ix += 1 ++ changed_vowels = MapVowels(consecutive_vowels) ++ outstr += changed_vowels ++ outstr += _QOF ++ outstr += changed_vowels ++ ++ _existing_translations[str] = outstr ++ return outstr ++ ++ ++def PseudoMessage(message): ++ '''Returns a pseudotranslation of the provided message. ++ ++ Args: ++ message: tclib.Message() ++ ++ Return: ++ tclib.Translation() ++ ''' ++ transl = tclib.Translation() ++ ++ for part in message.GetContent(): ++ if isinstance(part, tclib.Placeholder): ++ transl.AppendPlaceholder(part) ++ else: ++ transl.AppendText(PseudoString(part)) ++ ++ return transl +diff --git a/tools/grit/grit/pseudo_rtl.py b/tools/grit/grit/pseudo_rtl.py +new file mode 100644 +index 0000000000..2240b571de +--- /dev/null ++++ b/tools/grit/grit/pseudo_rtl.py +@@ -0,0 +1,104 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Pseudo RTL, (aka Fake Bidi) support. It simply wraps each word with ++Unicode RTL overrides. ++More info at https://sites.google.com/a/chromium.org/dev/Home/fake-bidi ++''' ++ ++from __future__ import print_function ++ ++import re ++ ++from grit import lazy_re ++from grit import tclib ++ ++ACCENTED_STRINGS = { ++ 'a': u"\u00e5", 'e': u"\u00e9", 'i': u"\u00ee", 'o': u"\u00f6", ++ 'u': u"\u00fb", 'A': u"\u00c5", 'E': u"\u00c9", 'I': u"\u00ce", ++ 'O': u"\u00d6", 'U': u"\u00db", 'c': u"\u00e7", 'd': u"\u00f0", ++ 'n': u"\u00f1", 'p': u"\u00fe", 'y': u"\u00fd", 'C': u"\u00c7", ++ 'D': u"\u00d0", 'N': u"\u00d1", 'P': u"\u00de", 'Y': u"\u00dd", ++ 'f': u"\u0192", 's': u"\u0161", 'S': u"\u0160", 'z': u"\u017e", ++ 'Z': u"\u017d", 'g': u"\u011d", 'G': u"\u011c", 'h': u"\u0125", ++ 'H': u"\u0124", 'j': u"\u0135", 'J': u"\u0134", 'k': u"\u0137", ++ 'K': u"\u0136", 'l': u"\u013c", 'L': u"\u013b", 't': u"\u0163", ++ 'T': u"\u0162", 'w': u"\u0175", 'W': u"\u0174", ++ '$': u"\u20ac", '?': u"\u00bf", 'R': u"\u00ae", r'!': u"\u00a1", ++} ++ ++# a character set containing the keys in ACCENTED_STRINGS ++# We should not accent characters in an escape sequence such as "\n". ++# To be safe, we assume every character following a backslash is an escaped ++# character. We also need to consider the case like "\\n", which means ++# a blackslash and a character "n", we will accent the character "n". ++TO_ACCENT = lazy_re.compile( ++ r'[%s]|\\[a-z\\]' % ''.join(ACCENTED_STRINGS.keys())) ++ ++# Lex text so that we don't interfere with html tokens and entities. ++# This lexing scheme will handle all well formed tags and entities, html or ++# xhtml. It will not handle comments, CDATA sections, or the unescaping tags: ++# script, style, xmp or listing. If any of those appear in messages, ++# something is wrong. ++TOKENS = [ lazy_re.compile( ++ '^%s' % pattern, # match at the beginning of input ++ re.I | re.S # html tokens are case-insensitive ++ ) ++ for pattern in ++ ( ++ # a run of non html special characters ++ r'[^<&]+', ++ # a tag ++ (r']+|"[^\"]*"|\'[^\']*\'))?' # attribute value ++ r')*\s*/?>'), ++ # an entity ++ r'&(?:[a-z]\w+|#\d+|#x[\da-f]+);', ++ # an html special character not part of a special sequence ++ r'.' ++ ) ] ++ ++ALPHABETIC_RUN = lazy_re.compile(r'([^\W0-9_]+)') ++ ++RLO = u'\u202e' ++PDF = u'\u202c' ++ ++def PseudoRTLString(text): ++ '''Returns a fake bidirectional version of the source string. This code is ++ based on accentString above, in turn copied from Frank Tang. ++ ''' ++ parts = [] ++ while text: ++ m = None ++ for token in TOKENS: ++ m = token.search(text) ++ if m: ++ part = m.group(0) ++ text = text[len(part):] ++ if part[0] not in ('<', '&'): ++ # not a tag or entity, so accent ++ part = ALPHABETIC_RUN.sub(lambda run: RLO + run.group() + PDF, part) ++ parts.append(part) ++ break ++ return ''.join(parts) ++ ++ ++def PseudoRTLMessage(message): ++ '''Returns a pseudo-RTL (aka Fake-Bidi) translation of the provided message. ++ ++ Args: ++ message: tclib.Message() ++ ++ Return: ++ tclib.Translation() ++ ''' ++ transl = tclib.Translation() ++ for part in message.GetContent(): ++ if isinstance(part, tclib.Placeholder): ++ transl.AppendPlaceholder(part) ++ else: ++ transl.AppendText(PseudoRTLString(part)) ++ ++ return transl +diff --git a/tools/grit/grit/pseudo_unittest.py b/tools/grit/grit/pseudo_unittest.py +new file mode 100644 +index 0000000000..b1d53ff401 +--- /dev/null ++++ b/tools/grit/grit/pseudo_unittest.py +@@ -0,0 +1,55 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grit.pseudo''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) ++ ++import unittest ++ ++from grit import pseudo ++from grit import tclib ++ ++ ++class PseudoUnittest(unittest.TestCase): ++ def testVowelMapping(self): ++ self.failUnless(pseudo.MapVowels('abebibobuby') == ++ u'\u00e5b\u00e9b\u00efb\u00f4b\u00fcb\u00fd') ++ self.failUnless(pseudo.MapVowels('ABEBIBOBUBY') == ++ u'\u00c5B\u00c9B\u00cfB\u00d4B\u00dcB\u00dd') ++ ++ def testPseudoString(self): ++ out = pseudo.PseudoString('hello') ++ self.failUnless(out == pseudo.MapVowels(u'hePelloPo', True)) ++ ++ def testConsecutiveVowels(self): ++ out = pseudo.PseudoString("beautiful weather, ain't it?") ++ self.failUnless(out == pseudo.MapVowels( ++ u"beauPeautiPifuPul weaPeathePer, aiPain't iPit?", 1)) ++ ++ def testCapitals(self): ++ out = pseudo.PseudoString("HOWDIE DOODIE, DR. JONES") ++ self.failUnless(out == pseudo.MapVowels( ++ u"HOPOWDIEPIE DOOPOODIEPIE, DR. JOPONEPES", 1)) ++ ++ def testPseudoMessage(self): ++ msg = tclib.Message(text='Hello USERNAME, how are you?', ++ placeholders=[ ++ tclib.Placeholder('USERNAME', '%s', 'Joi')]) ++ trans = pseudo.PseudoMessage(msg) ++ # TODO(joi) It would be nicer if 'you' -> 'youPou' instead of ++ # 'you' -> 'youPyou' and if we handled the silent e in 'are' ++ self.failUnless(trans.GetPresentableContent() == ++ pseudo.MapVowels( ++ u'HePelloPo USERNAME, hoPow aParePe youPyou?', 1)) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/shortcuts.py b/tools/grit/grit/shortcuts.py +new file mode 100644 +index 0000000000..0db2ce436c +--- /dev/null ++++ b/tools/grit/grit/shortcuts.py +@@ -0,0 +1,93 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Stuff to prevent conflicting shortcuts. ++''' ++ ++from __future__ import print_function ++ ++from grit import lazy_re ++ ++ ++class ShortcutGroup(object): ++ '''Manages a list of cliques that belong together in a single shortcut ++ group. Knows how to detect conflicting shortcut keys. ++ ''' ++ ++ # Matches shortcut keys, e.g. &J ++ SHORTCUT_RE = lazy_re.compile('([^&]|^)(&[A-Za-z])') ++ ++ def __init__(self, name): ++ self.name = name ++ # Map of language codes to shortcut keys used (which is a map of ++ # shortcut keys to counts). ++ self.keys_by_lang = {} ++ # List of cliques in this group ++ self.cliques = [] ++ ++ def AddClique(self, c): ++ for existing_clique in self.cliques: ++ if existing_clique.GetId() == c.GetId(): ++ # This happens e.g. when we have e.g. ++ # ++ # where only one will really be included in the output. ++ return ++ ++ self.cliques.append(c) ++ for (lang, msg) in c.clique.items(): ++ if lang not in self.keys_by_lang: ++ self.keys_by_lang[lang] = {} ++ keymap = self.keys_by_lang[lang] ++ ++ content = msg.GetRealContent() ++ keys = [groups[1] for groups in self.SHORTCUT_RE.findall(content)] ++ for key in keys: ++ key = key.upper() ++ if key in keymap: ++ keymap[key] += 1 ++ else: ++ keymap[key] = 1 ++ ++ def GenerateWarnings(self, tc_project): ++ # For any language that has more than one occurrence of any shortcut, ++ # make a list of the conflicting shortcuts. ++ problem_langs = {} ++ for (lang, keys) in self.keys_by_lang.items(): ++ for (key, count) in keys.items(): ++ if count > 1: ++ if lang not in problem_langs: ++ problem_langs[lang] = [] ++ problem_langs[lang].append(key) ++ ++ warnings = [] ++ if len(problem_langs): ++ warnings.append("WARNING - duplicate keys exist in shortcut group %s" % ++ self.name) ++ for (lang,keys) in problem_langs.items(): ++ warnings.append(" %6s duplicates: %s" % (lang, ', '.join(keys))) ++ return warnings ++ ++ ++def GenerateDuplicateShortcutsWarnings(uberclique, tc_project): ++ '''Given an UberClique and a project name, will print out helpful warnings ++ if there are conflicting shortcuts within shortcut groups in the provided ++ UberClique. ++ ++ Args: ++ uberclique: clique.UberClique() ++ tc_project: 'MyProjectNameInTheTranslationConsole' ++ ++ Returns: ++ ['warning line 1', 'warning line 2', ...] ++ ''' ++ warnings = [] ++ groups = {} ++ for c in uberclique.AllCliques(): ++ for group in c.shortcut_groups: ++ if group not in groups: ++ groups[group] = ShortcutGroup(group) ++ groups[group].AddClique(c) ++ for group in groups.values(): ++ warnings += group.GenerateWarnings(tc_project) ++ return warnings +diff --git a/tools/grit/grit/shortcuts_unittest.py b/tools/grit/grit/shortcuts_unittest.py +new file mode 100644 +index 0000000000..30e7c4f758 +--- /dev/null ++++ b/tools/grit/grit/shortcuts_unittest.py +@@ -0,0 +1,79 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grit.shortcuts ++''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) ++ ++import unittest ++ ++from six import StringIO ++ ++from grit import shortcuts ++from grit import clique ++from grit import tclib ++from grit.gather import rc ++ ++class ShortcutsUnittest(unittest.TestCase): ++ ++ def setUp(self): ++ self.uq = clique.UberClique() ++ ++ def testFunctionality(self): ++ c = self.uq.MakeClique(tclib.Message(text="Hello &there")) ++ c.AddToShortcutGroup('group_name') ++ c = self.uq.MakeClique(tclib.Message(text="Howdie &there partner")) ++ c.AddToShortcutGroup('group_name') ++ ++ warnings = shortcuts.GenerateDuplicateShortcutsWarnings(self.uq, 'PROJECT') ++ self.failUnless(warnings) ++ ++ def testAmpersandEscaping(self): ++ c = self.uq.MakeClique(tclib.Message(text="Hello &there")) ++ c.AddToShortcutGroup('group_name') ++ c = self.uq.MakeClique(tclib.Message(text="S&&T are the &letters S and T")) ++ c.AddToShortcutGroup('group_name') ++ ++ warnings = shortcuts.GenerateDuplicateShortcutsWarnings(self.uq, 'PROJECT') ++ self.failUnless(len(warnings) == 0) ++ ++ def testDialog(self): ++ dlg = rc.Dialog(StringIO('''\ ++IDD_SIDEBAR_RSS_PANEL_PROPPAGE DIALOGEX 0, 0, 239, 221 ++STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD ++FONT 8, "MS Shell Dlg", 400, 0, 0x1 ++BEGIN ++ PUSHBUTTON "Add &URL",IDC_SIDEBAR_RSS_ADD_URL,182,53,57,14 ++ EDITTEXT IDC_SIDEBAR_RSS_NEW_URL,0,53,178,15,ES_AUTOHSCROLL ++ PUSHBUTTON "&Remove",IDC_SIDEBAR_RSS_REMOVE,183,200,56,14 ++ PUSHBUTTON "&Edit",IDC_SIDEBAR_RSS_EDIT,123,200,56,14 ++ CONTROL "&Automatically add commonly viewed clips", ++ IDC_SIDEBAR_RSS_AUTO_ADD,"Button",BS_AUTOCHECKBOX | ++ BS_MULTILINE | WS_TABSTOP,0,200,120,17 ++ PUSHBUTTON "",IDC_SIDEBAR_RSS_HIDDEN,179,208,6,6,NOT WS_VISIBLE ++ LTEXT "You can display clips from blogs, news sites, and other online sources.", ++ IDC_STATIC,0,0,239,10 ++ LISTBOX IDC_SIDEBAR_DISPLAYED_FEED_LIST,0,69,239,127,LBS_SORT | ++ LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | ++ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | ++ WS_TABSTOP ++ LTEXT "Add a clip from a recently viewed website by clicking Add Recent Clips.", ++ IDC_STATIC,0,13,141,19 ++ LTEXT "Or, if you know a site supports RSS or Atom, you can enter the RSS or Atom URL below and add it to your list of Web Clips.", ++ IDC_STATIC,0,33,239,18 ++ PUSHBUTTON "Add Recent &Clips (10)...", ++ IDC_SIDEBAR_RSS_ADD_RECENT_CLIPS,146,14,93,14 ++END'''), 'IDD_SIDEBAR_RSS_PANEL_PROPPAGE') ++ dlg.SetUberClique(self.uq) ++ dlg.Parse() ++ ++ warnings = shortcuts.GenerateDuplicateShortcutsWarnings(self.uq, 'PROJECT') ++ self.failUnless(len(warnings) == 0) ++ +diff --git a/tools/grit/grit/tclib.py b/tools/grit/grit/tclib.py +new file mode 100644 +index 0000000000..27ba366924 +--- /dev/null ++++ b/tools/grit/grit/tclib.py +@@ -0,0 +1,246 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Adaptation of the extern.tclib classes for our needs. ++''' ++ ++from __future__ import print_function ++ ++import functools ++import re ++ ++import six ++ ++from grit import exception ++from grit import lazy_re ++import grit.extern.tclib ++ ++ ++# Matches whitespace sequences which can be folded into a single whitespace ++# character. This matches single characters so that non-spaces are replaced ++# with spaces. ++_FOLD_WHITESPACE = re.compile(r'\s+') ++ ++# Caches compiled regexp used to split tags in BaseMessage.__init__() ++_RE_CACHE = {} ++ ++def Identity(i): ++ return i ++ ++ ++class BaseMessage(object): ++ '''Base class with methods shared by Message and Translation. ++ ''' ++ ++ def __init__(self, text='', placeholders=[], description='', meaning=''): ++ self.parts = [] ++ self.placeholders = [] ++ self.meaning = meaning ++ self.dirty = True # True if self.id is (or might be) wrong ++ self.id = 0 ++ self.SetDescription(description) ++ ++ if text != '': ++ if not placeholders or placeholders == []: ++ self.AppendText(text) ++ else: ++ tag_map = {} ++ for placeholder in placeholders: ++ tag_map[placeholder.GetPresentation()] = [placeholder, 0] ++ # This creates a regexp like '(TAG1|TAG2|TAG3)'. ++ # The tags have to be sorted in order of decreasing length, so that ++ # longer tags are substituted before shorter tags that happen to be ++ # substrings of the longer tag. ++ # E.g. "EXAMPLE_FOO_NAME" must be matched before "EXAMPLE_FOO", ++ # otherwise "EXAMPLE_FOO" splits "EXAMPLE_FOO_NAME" too. ++ tags = sorted(tag_map.keys(), ++ key=functools.cmp_to_key( ++ lambda x, y: len(x) - len(y) or ((x > y) - (x < y))), ++ reverse=True) ++ tag_re = '(' + '|'.join(tags) + ')' ++ ++ # This caching improves the time to build ++ # chrome/app:generated_resources from 21.562s to 17.672s on Linux. ++ compiled_re = _RE_CACHE.get(tag_re, None) ++ if compiled_re is None: ++ compiled_re = re.compile(tag_re) ++ _RE_CACHE[tag_re] = compiled_re ++ ++ chunked_text = compiled_re.split(text) ++ ++ for chunk in chunked_text: ++ if chunk: # ignore empty chunk ++ if chunk in tag_map: ++ self.AppendPlaceholder(tag_map[chunk][0]) ++ tag_map[chunk][1] += 1 # increase placeholder use count ++ else: ++ self.AppendText(chunk) ++ for key in tag_map: ++ assert tag_map[key][1] != 0 ++ ++ def GetRealContent(self, escaping_function=Identity): ++ '''Returns the original content, i.e. what your application and users ++ will see. ++ ++ Specify a function to escape each translateable bit, if you like. ++ ''' ++ bits = [] ++ for item in self.parts: ++ if isinstance(item, six.string_types): ++ bits.append(escaping_function(item)) ++ else: ++ bits.append(item.GetOriginal()) ++ return ''.join(bits) ++ ++ def GetPresentableContent(self): ++ presentable_content = [] ++ for part in self.parts: ++ if isinstance(part, Placeholder): ++ presentable_content.append(part.GetPresentation()) ++ else: ++ presentable_content.append(part) ++ return ''.join(presentable_content) ++ ++ def AppendPlaceholder(self, placeholder): ++ assert isinstance(placeholder, Placeholder) ++ dup = False ++ for other in self.GetPlaceholders(): ++ if other.presentation == placeholder.presentation: ++ assert other.original == placeholder.original ++ dup = True ++ ++ if not dup: ++ self.placeholders.append(placeholder) ++ self.parts.append(placeholder) ++ self.dirty = True ++ ++ def AppendText(self, text): ++ assert isinstance(text, six.string_types) ++ assert text != '' ++ ++ self.parts.append(text) ++ self.dirty = True ++ ++ def GetContent(self): ++ '''Returns the parts of the message. You may modify parts if you wish. ++ Note that you must not call GetId() on this object until you have finished ++ modifying the contents. ++ ''' ++ self.dirty = True # user might modify content ++ return self.parts ++ ++ def GetDescription(self): ++ return self.description ++ ++ def SetDescription(self, description): ++ self.description = _FOLD_WHITESPACE.sub(' ', description) ++ ++ def GetMeaning(self): ++ return self.meaning ++ ++ def GetId(self): ++ if self.dirty: ++ self.id = self.GenerateId() ++ self.dirty = False ++ return self.id ++ ++ def GenerateId(self): ++ return grit.extern.tclib.GenerateMessageId(self.GetPresentableContent(), ++ self.meaning) ++ ++ def GetPlaceholders(self): ++ return self.placeholders ++ ++ def FillTclibBaseMessage(self, msg): ++ msg.SetDescription(self.description.encode('utf-8')) ++ ++ for part in self.parts: ++ if isinstance(part, Placeholder): ++ ph = grit.extern.tclib.Placeholder( ++ part.presentation.encode('utf-8'), ++ part.original.encode('utf-8'), ++ part.example.encode('utf-8')) ++ msg.AppendPlaceholder(ph) ++ else: ++ msg.AppendText(part.encode('utf-8')) ++ ++ ++class Message(BaseMessage): ++ '''A message.''' ++ ++ def __init__(self, text='', placeholders=[], description='', meaning='', ++ assigned_id=None): ++ super(Message, self).__init__(text, placeholders, description, meaning) ++ self.assigned_id = assigned_id ++ ++ def ToTclibMessage(self): ++ msg = grit.extern.tclib.Message('utf-8', meaning=self.meaning) ++ self.FillTclibBaseMessage(msg) ++ return msg ++ ++ def GetId(self): ++ '''Use the assigned id if we have one.''' ++ if self.assigned_id: ++ return self.assigned_id ++ ++ return super(Message, self).GetId() ++ ++ def HasAssignedId(self): ++ '''Returns True if this message has an assigned id.''' ++ return bool(self.assigned_id) ++ ++ ++class Translation(BaseMessage): ++ '''A translation.''' ++ ++ def __init__(self, text='', id='', placeholders=[], description='', meaning=''): ++ super(Translation, self).__init__(text, placeholders, description, meaning) ++ self.id = id ++ ++ def GetId(self): ++ assert id != '', "ID has not been set." ++ return self.id ++ ++ def SetId(self, id): ++ self.id = id ++ ++ def ToTclibMessage(self): ++ msg = grit.extern.tclib.Message( ++ 'utf-8', id=self.id, meaning=self.meaning) ++ self.FillTclibBaseMessage(msg) ++ return msg ++ ++ ++class Placeholder(grit.extern.tclib.Placeholder): ++ '''Modifies constructor to accept a Unicode string ++ ''' ++ ++ # Must match placeholder presentation names ++ _NAME_RE = lazy_re.compile('^[A-Za-z0-9_]+$') ++ ++ def __init__(self, presentation, original, example): ++ '''Creates a new placeholder. ++ ++ Args: ++ presentation: 'USERNAME' ++ original: '%s' ++ example: 'Joi' ++ ''' ++ assert presentation != '' ++ assert original != '' ++ assert example != '' ++ if not self._NAME_RE.match(presentation): ++ raise exception.InvalidPlaceholderName(presentation) ++ self.presentation = presentation ++ self.original = original ++ self.example = example ++ ++ def GetPresentation(self): ++ return self.presentation ++ ++ def GetOriginal(self): ++ return self.original ++ ++ def GetExample(self): ++ return self.example +diff --git a/tools/grit/grit/tclib_unittest.py b/tools/grit/grit/tclib_unittest.py +new file mode 100644 +index 0000000000..7a08654e1b +--- /dev/null ++++ b/tools/grit/grit/tclib_unittest.py +@@ -0,0 +1,180 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grit.tclib''' ++ ++from __future__ import print_function ++ ++import sys ++import os.path ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) ++ ++import unittest ++ ++import six ++ ++from grit import tclib ++ ++from grit import exception ++import grit.extern.tclib ++ ++ ++class TclibUnittest(unittest.TestCase): ++ def testInit(self): ++ msg = tclib.Message(text=u'Hello Earthlings', ++ description='Greetings\n\t message') ++ self.failUnlessEqual(msg.GetPresentableContent(), 'Hello Earthlings') ++ self.failUnless(isinstance(msg.GetPresentableContent(), six.string_types)) ++ self.failUnlessEqual(msg.GetDescription(), 'Greetings message') ++ ++ def testGetAttr(self): ++ msg = tclib.Message() ++ msg.AppendText(u'Hello') # Tests __getattr__ ++ self.failUnless(msg.GetPresentableContent() == 'Hello') ++ self.failUnless(isinstance(msg.GetPresentableContent(), six.string_types)) ++ ++ def testAll(self): ++ text = u'Howdie USERNAME' ++ phs = [tclib.Placeholder(u'USERNAME', u'%s', 'Joi')] ++ msg = tclib.Message(text=text, placeholders=phs) ++ self.failUnless(msg.GetPresentableContent() == 'Howdie USERNAME') ++ ++ trans = tclib.Translation(text=text, placeholders=phs) ++ self.failUnless(trans.GetPresentableContent() == 'Howdie USERNAME') ++ self.failUnless(isinstance(trans.GetPresentableContent(), six.string_types)) ++ ++ def testUnicodeReturn(self): ++ text = u'\u00fe' ++ msg = tclib.Message(text=text) ++ self.failUnless(msg.GetPresentableContent() == text) ++ from_list = msg.GetContent()[0] ++ self.failUnless(from_list == text) ++ ++ def testRegressionTranslationInherited(self): ++ '''Regression tests a bug that was caused by grit.tclib.Translation ++ inheriting from the translation console's Translation object ++ instead of only owning an instance of it. ++ ''' ++ msg = tclib.Message(text=u"BLA1\r\nFrom: BLA2 \u00fe BLA3", ++ placeholders=[ ++ tclib.Placeholder('BLA1', '%s', '%s'), ++ tclib.Placeholder('BLA2', '%s', '%s'), ++ tclib.Placeholder('BLA3', '%s', '%s')]) ++ transl = tclib.Translation(text=msg.GetPresentableContent(), ++ placeholders=msg.GetPlaceholders()) ++ content = transl.GetContent() ++ self.failUnless(isinstance(content[3], six.string_types)) ++ ++ def testFingerprint(self): ++ # This has Windows line endings. That is on purpose. ++ id = grit.extern.tclib.GenerateMessageId( ++ 'Google Desktop for Enterprise\r\n' ++ 'All Rights Reserved\r\n' ++ '\r\n' ++ '---------\r\n' ++ 'Contents\r\n' ++ '---------\r\n' ++ 'This distribution contains the following files:\r\n' ++ '\r\n' ++ 'GoogleDesktopSetup.msi - Installation and setup program\r\n' ++ 'GoogleDesktop.adm - Group Policy administrative template file\r\n' ++ 'AdminGuide.pdf - Google Desktop for Enterprise administrative guide\r\n' ++ '\r\n' ++ '\r\n' ++ '--------------\r\n' ++ 'Documentation\r\n' ++ '--------------\r\n' ++ 'Full documentation and installation instructions are in the \r\n' ++ 'administrative guide, and also online at \r\n' ++ 'http://desktop.google.com/enterprise/adminguide.html.\r\n' ++ '\r\n' ++ '\r\n' ++ '------------------------\r\n' ++ 'IBM Lotus Notes Plug-In\r\n' ++ '------------------------\r\n' ++ 'The Lotus Notes plug-in is included in the release of Google \r\n' ++ 'Desktop for Enterprise. The IBM Lotus Notes Plug-in for Google \r\n' ++ 'Desktop indexes mail, calendar, task, contact and journal \r\n' ++ 'documents from Notes. Discussion documents including those from \r\n' ++ 'the discussion and team room templates can also be indexed by \r\n' ++ 'selecting an option from the preferences. Once indexed, this data\r\n' ++ 'will be returned in Google Desktop searches. The corresponding\r\n' ++ 'document can be opened in Lotus Notes from the Google Desktop \r\n' ++ 'results page.\r\n' ++ '\r\n' ++ 'Install: The plug-in will install automatically during the Google \r\n' ++ 'Desktop setup process if Lotus Notes is already installed. Lotus \r\n' ++ 'Notes must not be running in order for the install to occur. \r\n' ++ '\r\n' ++ 'Preferences: Preferences and selection of databases to index are\r\n' ++ 'set in the \'Google Desktop for Notes\' dialog reached through the \r\n' ++ '\'Actions\' menu.\r\n' ++ '\r\n' ++ 'Reindexing: Selecting \'Reindex all databases\' will index all the \r\n' ++ 'documents in each database again.\r\n' ++ '\r\n' ++ '\r\n' ++ 'Notes Plug-in Known Issues\r\n' ++ '---------------------------\r\n' ++ '\r\n' ++ 'If the \'Google Desktop for Notes\' item is not available from the \r\n' ++ 'Lotus Notes Actions menu, then installation was not successful. \r\n' ++ 'Installation consists of writing one file, notesgdsplugin.dll, to \r\n' ++ 'the Notes application directory and a setting to the notes.ini \r\n' ++ 'configuration file. The most likely cause of an unsuccessful \r\n' ++ 'installation is that the installer was not able to locate the \r\n' ++ 'notes.ini file. Installation will complete if the user closes Notes\r\n' ++ 'and manually adds the following setting to this file on a new line:\r\n' ++ 'AddinMenus=notegdsplugin.dll\r\n' ++ '\r\n' ++ 'If the notesgdsplugin.dll file is not in the application directory\r\n' ++ r'(e.g., C:\Program Files\Lotus\Notes) after Google Desktop \r\n' ++ 'installation, it is likely that Notes was not installed correctly. \r\n' ++ '\r\n' ++ 'Only local databases can be indexed. If they can be determined, \r\n' ++ 'the user\'s local mail file and address book will be included in the\r\n' ++ 'list automatically. Mail archives and other databases must be \r\n' ++ 'added with the \'Add\' button.\r\n' ++ '\r\n' ++ 'Some users may experience performance issues during the initial \r\n' ++ 'indexing of a database. The \'Perform the initial index of a \r\n' ++ 'database only when I\'m idle\' option will limit the indexing process\r\n' ++ 'to times when the user is not using the machine. If this does not \r\n' ++ 'alleviate the problem or the user would like to continually index \r\n' ++ 'but just do so more slowly or quickly, the GoogleWaitTime notes.ini\r\n' ++ 'value can be set. Increasing the GoogleWaitTime value will slow \r\n' ++ 'down the indexing process, and lowering the value will speed it up.\r\n' ++ 'A value of zero causes the fastest possible indexing. Removing the\r\n' ++ 'ini parameter altogether returns it to the default (20).\r\n' ++ '\r\n' ++ 'Crashes have been known to occur with certain types of history \r\n' ++ 'bookmarks. If the Notes client seems to crash randomly, try \r\n' ++ 'disabling the \'Index note history\' option. If it crashes before,\r\n' ++ 'you can get to the preferences, add the following line to your \r\n' ++ 'notes.ini file:\r\n' ++ 'GDSNoIndexHistory=1\r\n') ++ self.assertEqual(id, '7660964495923572726') ++ ++ def testPlaceholderNameChecking(self): ++ try: ++ ph = tclib.Placeholder('BINGO BONGO', 'bla', 'bla') ++ raise Exception("We shouldn't get here") ++ except exception.InvalidPlaceholderName: ++ pass # Expect exception to be thrown because presentation contained space ++ ++ def testTagsWithCommonSubstring(self): ++ word = 'ABCDEFGHIJ' ++ text = ' '.join([word[:i] for i in range(1, 11)]) ++ phs = [tclib.Placeholder(word[:i], str(i), str(i)) for i in range(1, 11)] ++ try: ++ msg = tclib.Message(text=text, placeholders=phs) ++ self.failUnless(msg.GetRealContent() == '1 2 3 4 5 6 7 8 9 10') ++ except: ++ self.fail('tclib.Message() should handle placeholders that are ' ++ 'substrings of each other') ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/test_suite_all.py b/tools/grit/grit/test_suite_all.py +new file mode 100644 +index 0000000000..3bfe2a79d5 +--- /dev/null ++++ b/tools/grit/grit/test_suite_all.py +@@ -0,0 +1,34 @@ ++#!/usr/bin/env python3 ++# Copyright (c) 2011 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit test suite that collects all test cases for GRIT.''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++ ++ ++CUR_DIR = os.path.dirname(os.path.realpath(__file__)) ++SRC_DIR = os.path.dirname(os.path.dirname(os.path.dirname(CUR_DIR))) ++TYP_DIR = os.path.join( ++ SRC_DIR, 'third_party', 'catapult', 'third_party', 'typ') ++ ++if TYP_DIR not in sys.path: ++ sys.path.insert(0, TYP_DIR) ++ ++ ++import typ # pylint: disable=import-error,unused-import ++ ++ ++def main(args): ++ return typ.main( ++ top_level_dirs=[os.path.join(CUR_DIR, '..')], ++ skip=['grit.format.gen_predetermined_ids_unittest.*', ++ 'grit.pseudo_unittest.*'] ++ ) ++ ++if __name__ == '__main__': ++ sys.exit(main(sys.argv[1:])) +diff --git a/tools/grit/grit/testdata/GoogleDesktop.adm b/tools/grit/grit/testdata/GoogleDesktop.adm +new file mode 100644 +index 0000000000..082f56bb1a +--- /dev/null ++++ b/tools/grit/grit/testdata/GoogleDesktop.adm +@@ -0,0 +1,945 @@ ++CLASS MACHINE ++ CATEGORY !!Cat_Google ++ CATEGORY !!Cat_GoogleDesktopSearch ++ KEYNAME "Software\Policies\Google\Google Desktop" ++ ++ CATEGORY !!Cat_Preferences ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences" ++ ++ CATEGORY !!Cat_IndexAndCaptureControl ++ POLICY !!Blacklist_Email ++ EXPLAIN !!Explain_Blacklist_Email ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ VALUENAME "1" ++ END POLICY ++ ++ POLICY !!Blacklist_Gmail ++ EXPLAIN !!Explain_Blacklist_Gmail ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-pop" ++ VALUENAME "gmail" ++ END POLICY ++ ++ POLICY !!Blacklist_WebHistory ++ EXPLAIN !!Explain_Blacklist_WebHistory ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ VALUENAME "2" ++ END POLICY ++ ++ POLICY !!Blacklist_Chat ++ EXPLAIN !!Explain_Blacklist_Chat ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "3" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Text ++ EXPLAIN !!Explain_Blacklist_Text ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "4" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Media ++ EXPLAIN !!Explain_Blacklist_Media ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "5" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Contact ++ EXPLAIN !!Explain_Blacklist_Contact ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "9" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Calendar ++ EXPLAIN !!Explain_Blacklist_Calendar ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "10" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Task ++ EXPLAIN !!Explain_Blacklist_Task ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "11" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Note ++ EXPLAIN !!Explain_Blacklist_Note ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "12" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Journal ++ EXPLAIN !!Explain_Blacklist_Journal ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "13" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Word ++ EXPLAIN !!Explain_Blacklist_Word ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "DOC" ++ END POLICY ++ ++ POLICY !!Blacklist_Excel ++ EXPLAIN !!Explain_Blacklist_Excel ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "XLS" ++ END POLICY ++ ++ POLICY !!Blacklist_Powerpoint ++ EXPLAIN !!Explain_Blacklist_Powerpoint ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "PPT" ++ END POLICY ++ ++ POLICY !!Blacklist_PDF ++ EXPLAIN !!Explain_Blacklist_PDF ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "PDF" ++ END POLICY ++ ++ POLICY !!Blacklist_ZIP ++ EXPLAIN !!Explain_Blacklist_ZIP ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "ZIP" ++ END POLICY ++ ++ POLICY !!Blacklist_HTTPS ++ EXPLAIN !!Explain_Blacklist_HTTPS ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-3" ++ VALUENAME "HTTPS" ++ END POLICY ++ ++ POLICY !!Blacklist_PasswordProtectedOffice ++ EXPLAIN !!Explain_Blacklist_PasswordProtectedOffice ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-13" ++ VALUENAME "SECUREOFFICE" ++ END POLICY ++ ++ POLICY !!Blacklist_URI_Contains ++ EXPLAIN !!Explain_Blacklist_URI_Contains ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-6" ++ PART !!Blacklist_URI_Contains LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Blacklist_Extensions ++ EXPLAIN !!Explain_Blacklist_Extensions ++ PART !!Blacklist_Extensions EDITTEXT ++ VALUENAME "file_extensions_to_skip" ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Disallow_UserSearchLocations ++ EXPLAIN !!Explain_Disallow_UserSearchLocations ++ VALUENAME user_search_locations ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Search_Location_Whitelist ++ EXPLAIN !!Explain_Search_Location_Whitelist ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\policy_search_location_whitelist" ++ PART !!Search_Locations_Whitelist LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Email_Retention ++ EXPLAIN !!Explain_Email_Retention ++ PART !!Email_Retention_Edit NUMERIC ++ VALUENAME "email_days_to_retain" ++ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!Webpage_Retention ++ EXPLAIN !!Explain_Webpage_Retention ++ PART !!Webpage_Retention_Edit NUMERIC ++ VALUENAME "webpage_days_to_retain" ++ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!File_Retention ++ EXPLAIN !!Explain_File_Retention ++ PART !!File_Retention_Edit NUMERIC ++ VALUENAME "file_days_to_retain" ++ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!IM_Retention ++ EXPLAIN !!Explain_IM_Retention ++ PART !!IM_Retention_Edit NUMERIC ++ VALUENAME "im_days_to_retain" ++ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Remove_Deleted_Items ++ EXPLAIN !!Explain_Remove_Deleted_Items ++ VALUENAME remove_deleted_items ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Allow_Simultaneous_Indexing ++ EXPLAIN !!Explain_Allow_Simultaneous_Indexing ++ VALUENAME simultaneous_indexing ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ END CATEGORY ++ ++ POLICY !!Pol_TurnOffAdvancedFeatures ++ EXPLAIN !!Explain_TurnOffAdvancedFeatures ++ VALUENAME error_report_on ++ VALUEON NUMERIC 0 ++ END POLICY ++ ++ POLICY !!Pol_TurnOffImproveGd ++ EXPLAIN !!Explain_TurnOffImproveGd ++ VALUENAME improve_gd ++ VALUEON NUMERIC 0 ++ VALUEOFF NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_NoPersonalizationInfo ++ EXPLAIN !!Explain_NoPersonalizationInfo ++ VALUENAME send_personalization_info ++ VALUEON NUMERIC 0 ++ VALUEOFF NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_OneBoxMode ++ EXPLAIN !!Explain_OneBoxMode ++ VALUENAME onebox_mode ++ VALUEON NUMERIC 0 ++ END POLICY ++ ++ POLICY !!Pol_EncryptIndex ++ EXPLAIN !!Explain_EncryptIndex ++ VALUENAME encrypt_index ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Hyper ++ EXPLAIN !!Explain_Hyper ++ VALUENAME hyper_off ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Display_Mode ++ EXPLAIN !!Explain_Display_Mode ++ PART !!Pol_Display_Mode DROPDOWNLIST ++ VALUENAME display_mode ++ ITEMLIST ++ NAME !!Sidebar VALUE NUMERIC 1 ++ NAME !!Deskbar VALUE NUMERIC 8 ++ NAME !!FloatingDeskbar VALUE NUMERIC 4 ++ NAME !!None VALUE NUMERIC 0 ++ END ITEMLIST ++ END PART ++ END POLICY ++ ++ END CATEGORY ; Preferences ++ ++ CATEGORY !!Cat_Enterprise ++ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise" ++ ++ POLICY !!Pol_Autoupdate ++ EXPLAIN !!Explain_Autoupdate ++ VALUENAME autoupdate_host ++ VALUEON "" ++ END POLICY ++ ++ POLICY !!Pol_AutoupdateAsSystem ++ EXPLAIN !!Explain_AutoupdateAsSystem ++ VALUENAME autoupdate_impersonate_user ++ VALUEON NUMERIC 0 ++ VALUEOFF NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_EnterpriseTab ++ EXPLAIN !!Explain_EnterpriseTab ++ PART !!EnterpriseTabText EDITTEXT ++ VALUENAME enterprise_tab_text ++ END PART ++ PART !!EnterpriseTabHomepage EDITTEXT ++ VALUENAME enterprise_tab_homepage ++ END PART ++ PART !!EnterpriseTabHomepageQuery CHECKBOX ++ VALUENAME enterprise_tab_homepage_query ++ END PART ++ PART !!EnterpriseTabResults EDITTEXT ++ VALUENAME enterprise_tab_results ++ END PART ++ PART !!EnterpriseTabResultsQuery CHECKBOX ++ VALUENAME enterprise_tab_results_query ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_GSAHosts ++ EXPLAIN !!Explain_GSAHosts ++ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\GSAHosts" ++ PART !!Pol_GSAHosts LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_PolicyUnawareClientProhibitedFlag ++ EXPLAIN !!Explain_PolicyUnawareClientProhibitedFlag ++ KEYNAME "Software\Policies\Google\Google Desktop" ++ VALUENAME PolicyUnawareClientProhibitedFlag ++ END POLICY ++ ++ POLICY !!Pol_MinimumAllowedVersion ++ EXPLAIN !!Explain_MinimumAllowedVersion ++ PART !!Pol_MinimumAllowedVersion EDITTEXT ++ VALUENAME minimum_allowed_version ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_MaximumAllowedVersion ++ EXPLAIN !!Explain_MaximumAllowedVersion ++ PART !!Pol_MaximumAllowedVersion EDITTEXT ++ VALUENAME maximum_allowed_version ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Disallow_Gadgets ++ EXPLAIN !!Explain_Disallow_Gadgets ++ VALUENAME disallow_gadgets ++ VALUEON NUMERIC 1 ++ PART !!Disallow_Only_Non_Builtin_Gadgets CHECKBOX DEFCHECKED ++ VALUENAME disallow_only_non_builtin_gadgets ++ VALUEON NUMERIC 1 ++ VALUEOFF NUMERIC 0 ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Gadget_Whitelist ++ EXPLAIN !!Explain_Gadget_Whitelist ++ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\gadget_whitelist" ++ PART !!Pol_Gadget_Whitelist LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Gadget_Install_Confirmation_Whitelist ++ EXPLAIN !!Explain_Gadget_Install_Confirmation_Whitelist ++ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\install_confirmation_whitelist" ++ PART !!Pol_Gadget_Install_Confirmation_Whitelist LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Alternate_User_Data_Dir ++ EXPLAIN !!Explain_Alternate_User_Data_Dir ++ PART !!Pol_Alternate_User_Data_Dir EDITTEXT ++ VALUENAME alternate_user_data_dir ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_MaxAllowedOutlookConnections ++ EXPLAIN !!Explain_MaxAllowedOutlookConnections ++ PART !!Pol_MaxAllowedOutlookConnections NUMERIC ++ VALUENAME max_allowed_outlook_connections ++ MIN 1 MAX 65535 DEFAULT 400 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_DisallowSsdService ++ EXPLAIN !!Explain_DisallowSsdService ++ VALUENAME disallow_ssd_service ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_DisallowSsdOutbound ++ EXPLAIN !!Explain_DisallowSsdOutbound ++ VALUENAME disallow_ssd_outbound ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Disallow_Store_Gadget_Service ++ EXPLAIN !!Explain_Disallow_Store_Gadget_Service ++ VALUENAME disallow_store_gadget_service ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_MaxExchangeIndexingRate ++ EXPLAIN !!Explain_MaxExchangeIndexingRate ++ PART !!Pol_MaxExchangeIndexingRate NUMERIC ++ VALUENAME max_exchange_indexing_rate ++ MIN 1 MAX 1000 DEFAULT 60 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_EnableSafeweb ++ EXPLAIN !!Explain_Safeweb ++ VALUENAME safe_browsing ++ VALUEON NUMERIC 1 ++ VALUEOFF NUMERIC 0 ++ END POLICY ++ ++ END CATEGORY ; Enterprise ++ ++ END CATEGORY ; GoogleDesktopSearch ++ END CATEGORY ; Google ++ ++ ++CLASS USER ++ CATEGORY !!Cat_Google ++ CATEGORY !!Cat_GoogleDesktopSearch ++ KEYNAME "Software\Policies\Google\Google Desktop" ++ ++ CATEGORY !!Cat_Preferences ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences" ++ ++ CATEGORY !!Cat_IndexAndCaptureControl ++ POLICY !!Blacklist_Email ++ EXPLAIN !!Explain_Blacklist_Email ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ VALUENAME "1" ++ END POLICY ++ ++ POLICY !!Blacklist_Gmail ++ EXPLAIN !!Explain_Blacklist_Gmail ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-pop" ++ VALUENAME "gmail" ++ END POLICY ++ ++ POLICY !!Blacklist_WebHistory ++ EXPLAIN !!Explain_Blacklist_WebHistory ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ VALUENAME "2" ++ END POLICY ++ ++ POLICY !!Blacklist_Chat ++ EXPLAIN !!Explain_Blacklist_Chat ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "3" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Text ++ EXPLAIN !!Explain_Blacklist_Text ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "4" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Media ++ EXPLAIN !!Explain_Blacklist_Media ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "5" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Contact ++ EXPLAIN !!Explain_Blacklist_Contact ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "9" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Calendar ++ EXPLAIN !!Explain_Blacklist_Calendar ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "10" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Task ++ EXPLAIN !!Explain_Blacklist_Task ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "11" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Note ++ EXPLAIN !!Explain_Blacklist_Note ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "12" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Journal ++ EXPLAIN !!Explain_Blacklist_Journal ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" ++ ACTIONLISTON ++ VALUENAME "13" VALUE NUMERIC 1 ++ END ACTIONLISTON ++ END POLICY ++ ++ POLICY !!Blacklist_Word ++ EXPLAIN !!Explain_Blacklist_Word ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "DOC" ++ END POLICY ++ ++ POLICY !!Blacklist_Excel ++ EXPLAIN !!Explain_Blacklist_Excel ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "XLS" ++ END POLICY ++ ++ POLICY !!Blacklist_Powerpoint ++ EXPLAIN !!Explain_Blacklist_Powerpoint ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "PPT" ++ END POLICY ++ ++ POLICY !!Blacklist_PDF ++ EXPLAIN !!Explain_Blacklist_PDF ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "PDF" ++ END POLICY ++ ++ POLICY !!Blacklist_ZIP ++ EXPLAIN !!Explain_Blacklist_ZIP ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" ++ VALUENAME "ZIP" ++ END POLICY ++ ++ POLICY !!Blacklist_HTTPS ++ EXPLAIN !!Explain_Blacklist_HTTPS ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-3" ++ VALUENAME "HTTPS" ++ END POLICY ++ ++ POLICY !!Blacklist_PasswordProtectedOffice ++ EXPLAIN !!Explain_Blacklist_PasswordProtectedOffice ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-13" ++ VALUENAME "SECUREOFFICE" ++ END POLICY ++ ++ POLICY !!Blacklist_URI_Contains ++ EXPLAIN !!Explain_Blacklist_URI_Contains ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-6" ++ PART !!Blacklist_URI_Contains LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Blacklist_Extensions ++ EXPLAIN !!Explain_Blacklist_Extensions ++ PART !!Blacklist_Extensions EDITTEXT ++ VALUENAME "file_extensions_to_skip" ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Disallow_UserSearchLocations ++ EXPLAIN !!Explain_Disallow_UserSearchLocations ++ VALUENAME user_search_locations ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Search_Location_Whitelist ++ EXPLAIN !!Explain_Search_Location_Whitelist ++ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\policy_search_location_whitelist" ++ PART !!Search_Locations_Whitelist LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Email_Retention ++ EXPLAIN !!Explain_Email_Retention ++ PART !!Email_Retention_Edit NUMERIC ++ VALUENAME "email_days_to_retain" ++ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!Webpage_Retention ++ EXPLAIN !!Explain_Webpage_Retention ++ PART !!Webpage_Retention_Edit NUMERIC ++ VALUENAME "webpage_days_to_retain" ++ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!File_Retention ++ EXPLAIN !!Explain_File_Retention ++ PART !!File_Retention_Edit NUMERIC ++ VALUENAME "file_days_to_retain" ++ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!IM_Retention ++ EXPLAIN !!Explain_IM_Retention ++ PART !!IM_Retention_Edit NUMERIC ++ VALUENAME "im_days_to_retain" ++ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Remove_Deleted_Items ++ EXPLAIN !!Explain_Remove_Deleted_Items ++ VALUENAME remove_deleted_items ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Allow_Simultaneous_Indexing ++ EXPLAIN !!Explain_Allow_Simultaneous_Indexing ++ VALUENAME simultaneous_indexing ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ END CATEGORY ++ ++ POLICY !!Pol_TurnOffAdvancedFeatures ++ EXPLAIN !!Explain_TurnOffAdvancedFeatures ++ VALUENAME error_report_on ++ VALUEON NUMERIC 0 ++ END POLICY ++ ++ POLICY !!Pol_TurnOffImproveGd ++ EXPLAIN !!Explain_TurnOffImproveGd ++ VALUENAME improve_gd ++ VALUEON NUMERIC 0 ++ VALUEOFF NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_NoPersonalizationInfo ++ EXPLAIN !!Explain_NoPersonalizationInfo ++ VALUENAME send_personalization_info ++ VALUEON NUMERIC 0 ++ VALUEOFF NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_OneBoxMode ++ EXPLAIN !!Explain_OneBoxMode ++ VALUENAME onebox_mode ++ VALUEON NUMERIC 0 ++ END POLICY ++ ++ POLICY !!Pol_EncryptIndex ++ EXPLAIN !!Explain_EncryptIndex ++ VALUENAME encrypt_index ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Hyper ++ EXPLAIN !!Explain_Hyper ++ VALUENAME hyper_off ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Display_Mode ++ EXPLAIN !!Explain_Display_Mode ++ PART !!Pol_Display_Mode DROPDOWNLIST ++ VALUENAME display_mode ++ ITEMLIST ++ NAME !!Sidebar VALUE NUMERIC 1 ++ NAME !!Deskbar VALUE NUMERIC 8 ++ NAME !!FloatingDeskbar VALUE NUMERIC 4 ++ NAME !!None VALUE NUMERIC 0 ++ END ITEMLIST ++ END PART ++ END POLICY ++ ++ END CATEGORY ; Preferences ++ ++ CATEGORY !!Cat_Enterprise ++ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise" ++ ++ POLICY !!Pol_Autoupdate ++ EXPLAIN !!Explain_Autoupdate ++ VALUENAME autoupdate_host ++ VALUEON "" ++ END POLICY ++ ++ POLICY !!Pol_AutoupdateAsSystem ++ EXPLAIN !!Explain_AutoupdateAsSystem ++ VALUENAME autoupdate_impersonate_user ++ VALUEON NUMERIC 0 ++ VALUEOFF NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_EnterpriseTab ++ EXPLAIN !!Explain_EnterpriseTab ++ PART !!EnterpriseTabText EDITTEXT ++ VALUENAME enterprise_tab_text ++ END PART ++ PART !!EnterpriseTabHomepage EDITTEXT ++ VALUENAME enterprise_tab_homepage ++ END PART ++ PART !!EnterpriseTabHomepageQuery CHECKBOX ++ VALUENAME enterprise_tab_homepage_query ++ END PART ++ PART !!EnterpriseTabResults EDITTEXT ++ VALUENAME enterprise_tab_results ++ END PART ++ PART !!EnterpriseTabResultsQuery CHECKBOX ++ VALUENAME enterprise_tab_results_query ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_GSAHosts ++ EXPLAIN !!Explain_GSAHosts ++ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\GSAHosts" ++ PART !!Pol_GSAHosts LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Disallow_Gadgets ++ EXPLAIN !!Explain_Disallow_Gadgets ++ VALUENAME disallow_gadgets ++ VALUEON NUMERIC 1 ++ PART !!Disallow_Only_Non_Builtin_Gadgets CHECKBOX DEFCHECKED ++ VALUENAME disallow_only_non_builtin_gadgets ++ VALUEON NUMERIC 1 ++ VALUEOFF NUMERIC 0 ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Gadget_Whitelist ++ EXPLAIN !!Explain_Gadget_Whitelist ++ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\gadget_whitelist" ++ PART !!Pol_Gadget_Whitelist LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Gadget_Install_Confirmation_Whitelist ++ EXPLAIN !!Explain_Gadget_Install_Confirmation_Whitelist ++ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\install_confirmation_whitelist" ++ PART !!Pol_Gadget_Install_Confirmation_Whitelist LISTBOX ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_Alternate_User_Data_Dir ++ EXPLAIN !!Explain_Alternate_User_Data_Dir ++ PART !!Pol_Alternate_User_Data_Dir EDITTEXT ++ VALUENAME alternate_user_data_dir ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_MaxAllowedOutlookConnections ++ EXPLAIN !!Explain_MaxAllowedOutlookConnections ++ PART !!Pol_MaxAllowedOutlookConnections NUMERIC ++ VALUENAME max_allowed_outlook_connections ++ MIN 1 MAX 65535 DEFAULT 400 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_DisallowSsdService ++ EXPLAIN !!Explain_DisallowSsdService ++ VALUENAME disallow_ssd_service ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_DisallowSsdOutbound ++ EXPLAIN !!Explain_DisallowSsdOutbound ++ VALUENAME disallow_ssd_outbound ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_Disallow_Store_Gadget_Service ++ EXPLAIN !!Explain_Disallow_Store_Gadget_Service ++ VALUENAME disallow_store_gadget_service ++ VALUEON NUMERIC 1 ++ END POLICY ++ ++ POLICY !!Pol_MaxExchangeIndexingRate ++ EXPLAIN !!Explain_MaxExchangeIndexingRate ++ PART !!Pol_MaxExchangeIndexingRate NUMERIC ++ VALUENAME max_exchange_indexing_rate ++ MIN 1 MAX 1000 DEFAULT 60 SPIN 1 ++ END PART ++ END POLICY ++ ++ POLICY !!Pol_EnableSafeweb ++ EXPLAIN !!Explain_Safeweb ++ VALUENAME safe_browsing ++ VALUEON NUMERIC 1 ++ VALUEOFF NUMERIC 0 ++ END POLICY ++ ++ END CATEGORY ; Enterprise ++ ++ END CATEGORY ; GoogleDesktopSearch ++ END CATEGORY ; Google ++ ++;------------------------------------------------------------------------------ ++ ++[strings] ++Cat_Google="Google" ++Cat_GoogleDesktopSearch="Google Desktop" ++ ++;------------------------------------------------------------------------------ ++; Preferences ++;------------------------------------------------------------------------------ ++Cat_Preferences="Preferences" ++Explain_Preferences="Controls Google Desktop preferences" ++ ++Cat_IndexAndCaptureControl="Indexing and Capture Control" ++Explain_IndexAndCaptureControl="Controls what files, web pages, and other content will be indexed by Google Desktop." ++ ++Blacklist_Email="Prevent indexing of email" ++Explain_Blacklist_Email="Enabling this policy will prevent Google Desktop from indexing emails.\n\nIf this policy is not configured, the user can choose whether or not to index emails." ++Blacklist_Gmail="Prevent indexing of Gmail" ++Explain_Blacklist_Gmail="Enabling this policy prevents Google Desktop from indexing Gmail messages.\n\nThis policy is in effect only when the policy "Prevent indexing of email" is disabled. When that policy is enabled, all email indexing is disabled, including Gmail indexing.\n\nIf both this policy and "Prevent indexing of email" are disabled or not configured, a user can choose whether or not to index Gmail messages." ++Blacklist_WebHistory="Prevent indexing of web pages" ++Explain_Blacklist_WebHistory="Enabling this policy will prevent Google Desktop from indexing web pages.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index web pages." ++Blacklist_Text="Prevent indexing of text files" ++Explain_Blacklist_Text="Enabling this policy will prevent Google Desktop from indexing text files.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index text files." ++Blacklist_Media="Prevent indexing of media files" ++Explain_Blacklist_Media="Enabling this policy will prevent Google Desktop from indexing media files.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index media files." ++Blacklist_Contact="Prevent indexing of contacts" ++Explain_Blacklist_Contact="Enabling this policy will prevent Google Desktop from indexing contacts.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index contacts." ++Blacklist_Calendar="Prevent indexing of calendar entries" ++Explain_Blacklist_Calendar="Enabling this policy will prevent Google Desktop from indexing calendar entries.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index calendar entries." ++Blacklist_Task="Prevent indexing of tasks" ++Explain_Blacklist_Task="Enabling this policy will prevent Google Desktop from indexing tasks.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index tasks." ++Blacklist_Note="Prevent indexing of notes" ++Explain_Blacklist_Note="Enabling this policy will prevent Google Desktop from indexing notes.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index notes." ++Blacklist_Journal="Prevent indexing of journal entries" ++Explain_Blacklist_Journal="Enabling this policy will prevent Google Desktop from indexing journal entries.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index journal entries." ++Blacklist_Word="Prevent indexing of Word documents" ++Explain_Blacklist_Word="Enabling this policy will prevent Google Desktop from indexing Word documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index Word documents." ++Blacklist_Excel="Prevent indexing of Excel documents" ++Explain_Blacklist_Excel="Enabling this policy will prevent Google Desktop from indexing Excel documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index Excel documents." ++Blacklist_Powerpoint="Prevent indexing of PowerPoint documents" ++Explain_Blacklist_Powerpoint="Enabling this policy will prevent Google Desktop from indexing PowerPoint documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index PowerPoint documents." ++Blacklist_PDF="Prevent indexing of PDF documents" ++Explain_Blacklist_PDF="Enabling this policy will prevent Google Desktop from indexing PDF documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index PDF documents." ++Blacklist_ZIP="Prevent indexing of ZIP files" ++Explain_Blacklist_ZIP="Enabling this policy will prevent Google Desktop from indexing ZIP files.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index ZIP files." ++Blacklist_HTTPS="Prevent indexing of secure web pages" ++Explain_Blacklist_HTTPS="Enabling this policy will prevent Google Desktop from indexing secure web pages (pages with HTTPS in the URL).\n\nIf this policy is disabled or not configured, the user can choose whether or not to index secure web pages." ++Blacklist_URI_Contains="Prevent indexing of specific web sites and folders" ++Explain_Blacklist_URI_Contains="This policy allows you to prevent Google Desktop from indexing specific websites or folders. If an item's URL or path name contains any of these specified strings, it will not be indexed. These restrictions will be applied in addition to any websites or folders that the user has specified.\n\nThis policy has no effect when disabled or not configured." ++Blacklist_Chat="Prevent indexing of IM chats" ++Explain_Blacklist_Chat="Enabling this policy will prevent Google Desktop from indexing IM chat conversations.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index IM chat conversations." ++Blacklist_PasswordProtectedOffice="Prevent indexing of password-protected Office documents (Word, Excel)" ++Explain_Blacklist_PasswordProtectedOffice="Enabling this policy will prevent Google Desktop from indexing password-protected office documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index password-protected office documents." ++Blacklist_Extensions="Prevent indexing of specific file extensions" ++Explain_Blacklist_Extensions="This policy allows you to prevent Google Desktop from indexing files with specific extensions. Enter a list of file extensions, separated by commas, that you wish to exclude from indexing.\n\nThis policy has no effect when disabled or not configured." ++Pol_Disallow_UserSearchLocations="Disallow adding search locations for indexing" ++Explain_Disallow_UserSearchLocations="Enabling this policy will prevent the user from specifying additional drives or networked folders to be indexed by Google Desktop.\n\nIf this policy is disabled or not configured, users may specify additional drives and networked folders to be indexed." ++Pol_Search_Location_Whitelist="Allow indexing of specific folders" ++Explain_Search_Location_Whitelist="This policy allows you to add additional drives and networked folders to index." ++Search_Locations_Whitelist="Search these locations" ++Email_Retention="Only retain emails that are less than x days old" ++Explain_Email_Retention="This policy allows you to configure Google Desktop to only retain emails that are less than the specified number of days old in the index. Enter the number of days to retain emails for\n\nThis policy has no effect when disabled or not configured." ++Email_Retention_Edit="Number of days to retain emails" ++Webpage_Retention="Only retain webpages that are less than x days old" ++Explain_Webpage_Retention="This policy allows you to configure Google Desktop to only retain webpages that are less than the specified number of days old in the index. Enter the number of days to retain webpages for\n\nThis policy has no effect when disabled or not configured." ++Webpage_Retention_Edit="Number of days to retain webpages" ++File_Retention="Only retain files that are less than x days old" ++Explain_File_Retention="This policy allows you to configure Google Desktop to only retain files that are less than the specified number of days old in the index. Enter the number of days to retain files for\n\nThis policy has no effect when disabled or not configured." ++File_Retention_Edit="Number of days to retain files" ++IM_Retention="Only retain IM that are less than x days old" ++Explain_IM_Retention="This policy allows you to configure Google Desktop to only retain IM that are less than the specified number of days old in the index. Enter the number of days to retain IM for\n\nThis policy has no effect when disabled or not configured." ++IM_Retention_Edit="Number of days to retain IM" ++ ++Pol_Remove_Deleted_Items="Remove deleted items from the index." ++Explain_Remove_Deleted_Items="Enabling this policy will remove all deleted items from the index and cache. Any items that are deleted will no longer be searchable." ++ ++Pol_Allow_Simultaneous_Indexing="Allow historical indexing for multiple users simultaneously." ++Explain_Allow_Simultaneous_Indexing="Enabling this policy will allow a computer to generate first-time indexes for multiple users simultaneously. \n\nIf this policy is disabled or not configured, historical indexing will happen only for the logged-in user that was connected last; historical indexing for any other logged-in user will happen the next time that other user connects." ++ ++Pol_TurnOffAdvancedFeatures="Turn off Advanced Features options" ++Explain_TurnOffAdvancedFeatures="Enabling this policy will prevent Google Desktop from sending Advanced Features data to Google (for either improvements or personalization), and users won't be able to change these options. Enabling this policy also prevents older versions of Google Desktop from sending data.\n\nIf this policy is disabled or not configured and the user has a pre-5.5 version of Google Desktop, the user can choose whether or not to enable sending data to Google. If the user has version 5.5 or later, the 'Turn off Improve Google Desktop option' and 'Do not send personalization info' policies will be used instead." ++ ++Pol_TurnOffImproveGd="Turn off Improve Google Desktop option" ++Explain_TurnOffImproveGd="Enabling this policy will prevent Google Desktop from sending improvement data, including crash reports and anonymous usage data, to Google.\n\nIf this policy is disabled, improvement data will be sent to Google and the user won't be able to change the option.\n\nIf this policy is not configured, the user can choose whether or not to enable the Improve Google Desktop option.\n\nNote that this policy applies only to version 5.5 or later and doesn't affect previous versions of Google Desktop.\n\nAlso note that this policy can be overridden by the 'Turn off Advanced Features options' policy." ++ ++Pol_NoPersonalizationInfo="Do not send personalization info" ++Explain_NoPersonalizationInfo="Enabling this policy will prevent Google Desktop from displaying personalized content, such as news that reflects the user's past interest in articles. Personalized content is derived from anonymous usage data sent to Google.\n\nIf this policy is disabled, personalized content will be displayed for all users, and users won't be able to disable this feature.\n\nIf this policy is not configured, users can choose whether or not to enable personalization in each gadget that supports this feature.\n\nNote that this policy applies only to version 5.5 or later and doesn't affect previous versions of Google Desktop.\n\nAlso note that this policy can be overridden by the 'Turn off Advanced Features options' policy." ++ ++Pol_OneBoxMode="Turn off Google Web Search Integration" ++Explain_OneBoxMode="Enabling this policy will prevent Google Desktop from displaying Desktop Search results in queries to google.com.\n\nIf this policy is disabled or not configured, the user can choose whether or not to include Desktop Search results in queries to google.com." ++ ++Pol_EncryptIndex="Encrypt index data" ++Explain_EncryptIndex="Enabling this policy will cause Google Desktop to turn on Windows file encryption for the folder containing the Google Desktop index and related user data the next time it is run.\n\nNote that Windows EFS is only available on NTFS volumes. If the user's data is stored on a FAT volume, this policy will have no effect.\n\nThis policy has no effect when disabled or not configured." ++ ++Pol_Hyper="Turn off Quick Find" ++Explain_Hyper="Enabling this policy will cause Google Desktop to turn off Quick Find feature. Quick Find allows you to see results as you type.\n\nIf this policy is disabled or not configured, the user can choose whether or not to enable it." ++ ++Pol_Display_Mode="Choose display option" ++Explain_Display_Mode="This policy sets the Google Desktop display option: Sidebar, Deskbar, Floating Deskbar or none.\n\nNote that on 64-bit systems, a setting of Deskbar will be interpreted as Floating Deskbar.\n\nIf this policy is disabled or not configured, the user can choose a display option." ++Sidebar="Sidebar" ++Deskbar="Deskbar" ++FloatingDeskbar="Floating Deskbar" ++None="None" ++ ++;------------------------------------------------------------------------------ ++; Enterprise ++;------------------------------------------------------------------------------ ++Cat_Enterprise="Enterprise Integration" ++Explain_Enterprise="Controls features specific to Enterprise installations of Google Desktop" ++ ++Pol_Autoupdate="Block Auto-update" ++Explain_Autoupdate="Enabling this policy prevents Google Desktop from automatically checking for and installing updates from google.com.\n\nIf you enable this policy, you must distribute updates to Google Desktop using Group Policy, SMS, or a similar enterprise software distribution mechanism. You should check http://desktop.google.com/enterprise/ for updates.\n\nIf this policy is disabled or not configured, Google Desktop will periodically check for updates from desktop.google.com." ++ ++Pol_AutoupdateAsSystem="Use system proxy settings when auto-updating" ++Explain_AutoupdateAsSystem="Enabling this policy makes Google Desktop use the machine-wide proxy settings (as specified using e.g. proxycfg.exe) when performing autoupdates (if enabled).\n\nIf this policy is disabled or not configured, Google Desktop will use the logged-on user's Internet Explorer proxy settings when checking for auto-updates (if enabled)." ++ ++Pol_EnterpriseTab="Enterprise search tab" ++Explain_EnterpriseTab="This policy allows you to add a search tab for your Google Search Appliance to Google Desktop and google.com web pages.\n\nYou must provide the name of the tab, such as "Intranet", as well as URLs for the search homepage and for retrieving search results. Use [DISP_QUERY] in place of the query term for the search results URL.\n\nSee the administrator's guide for more details." ++EnterpriseTabText="Tab name" ++EnterpriseTabHomepage="Search homepage URL" ++EnterpriseTabHomepageQuery="Check if search homepage supports '&&q='" ++EnterpriseTabResults="Search results URL" ++EnterpriseTabResultsQuery="Check if search results page supports '&&q='" ++ ++Pol_GSAHosts="Google Search Appliances" ++Explain_GSAHosts="This policy allows you to list any Google Search Appliances in your intranet. When properly configured, Google Desktop will insert Google Desktop results into the results of queries on the Google Search Appliance" ++ ++Pol_PolicyUnawareClientProhibitedFlag="Prohibit Policy-Unaware versions" ++Explain_PolicyUnawareClientProhibitedFlag="Prohibits installation and execution of versions of Google Desktop that are unaware of group policy.\n\nEnabling this policy will prevent users from installing or running version 1.0 of Google Desktop.\n\nThis policy has no effect when disabled or not configured." ++ ++Pol_MinimumAllowedVersion="Minimum allowed version" ++Explain_MinimumAllowedVersion="This policy allows you to prevent installation and/or execution of older versions of Google Desktop by specifying the minimum version you wish to allow. When enabling this policy, you should also enable the "Prohibit Policy-Unaware versions" policy to block versions of Google Desktop that did not support group policy.\n\nThis policy has no effect when disabled or not configured." ++ ++Pol_MaximumAllowedVersion="Maximum allowed version" ++Explain_MaximumAllowedVersion="This policy allows you to prevent installation and/or execution of newer versions of Google Desktop by specifying the maximum version you wish to allow.\n\nThis policy has no effect when disabled or not configured." ++ ++Pol_Disallow_Gadgets="Disallow gadgets and indexing plug-ins" ++Explain_Disallow_Gadgets="This policy prevents the use of all Google Desktop gadgets and indexing plug-ins. The policy applies to gadgets that are included in the Google Desktop installation package (built-in gadgets), built-in indexing plug-ins (currently only the Lotus Notes plug-in), and to gadgets or indexing plug-ins that a user might want to add later (non-built-in gadgets and indexing plug-ins).\n\nYou can prohibit use of all non-built-in gadgets and indexing plug-ins, but allow use of built-in gadgets and indexing plug-ins. To do so, enable this policy and then select the option "Disallow only non-built-in gadgets and indexing plug-ins.\n\nYou can supersede this policy to allow specified built-in and non-built-in gadgets and indexing plug-ins. To do so, enable this policy and then specify the gadgets and/or indexing plug-ins you want to allow under "Gadget and Plug-in Whitelist."" ++Disallow_Only_Non_Builtin_Gadgets="Disallow only non-built-in gadgets and indexing plug-ins" ++ ++Pol_Gadget_Whitelist="Gadget and plug-in whitelist" ++Explain_Gadget_Whitelist="This policy specifies a list of Google Desktop gadgets and indexing plug-ins that you want to allow, as exceptions to the "Disallow gadgets and indexing plug-ins" policy. This policy is valid only when the "Disallow gadgets and indexing plug-ins" policy is enabled.\n\nFor each gadget or indexing plug-in you wish to allow, add the CLSID or PROGID of the gadget or indexing plug-in (see the administrator's guide for more details).\n\nThis policy has no effect when disabled or not configured." ++ ++Pol_Gadget_Install_Confirmation_Whitelist="Allow silent installation of gadgets" ++Explain_Gadget_Install_Confirmation_Whitelist="Enabling this policy lets you specify a list of Google Desktop gadgets or indexing plug-ins that can be installed without confirmation from the user.\n\nAdd a gadget or indexing plug-in by placing its class ID (CLSID) or program identifier (PROGID) in the list, surrounded with curly braces ({ }).\n\nThis policy has no effect when disabled or not configured." ++ ++Pol_Alternate_User_Data_Dir="Alternate user data directory" ++Explain_Alternate_User_Data_Dir="This policy allows you to specify a directory to be used to store user data for Google Desktop (such as index data and cached documents).\n\nYou may use [USER_NAME] or [DOMAIN_NAME] in the path to specify the current user's name or domain. If [USER_NAME] is not specified, the user name will be appended at the end of the path.\n\nThis policy has no effect when disabled or not configured." ++ ++Pol_MaxAllowedOutlookConnections="Maximum allowed Outlook connections" ++Explain_MaxAllowedOutlookConnections="This policy specifies the maximum number of open connections that Google Desktop maintains with the Exchange server. Google Desktop opens a connection for each email folder that it indexes. If insufficient connections are allowed, Google Desktop cannot index all the user email folders.\n\nThe default value is 400. Because users rarely have as many as 400 email folders, Google Desktop rarely reaches the limit.\n\nIf you set this policy's value above 400, you must also configure the number of open connections between Outlook and the Exchange server. By default, approximately 400 connections are allowed. If Google Desktop uses too many of these connections, Outlook might be unable to access email.\n\nThis policy has no effect when disabled or not configured." ++ ++Pol_DisallowSsdService="Disallow sharing and receiving of web history and documents across computers" ++Explain_DisallowSsdService="Enabling this policy will prevent Google Desktop from sharing the user's web history and document contents across the user's different Google Desktop installations, and will also prevent it from receiving such shared items from the user's other machines. To allow reception but disallow sharing, use DisallowSsdOutbound.\nThis policy has no effect when disabled or not configured." ++ ++Pol_DisallowSsdOutbound="Disallow sharing of web history and documents to user's other computers." ++Explain_DisallowSsdOutbound="Enabling this policy will prevent Google Desktop from sending the user's web history and document contents from this machine to the user's other machines. It does not prevent reception of items from the user's other machines; to disallow both, use DisallowSsdService.\nThis policy has no effect when disabled or not configured." ++ ++Pol_Disallow_Store_Gadget_Service="Disallow storage of gadget content and settings." ++Explain_Disallow_Store_Gadget_Service="Enabling this policy will prevent users from storing their gadget content and settings with Google. Users will be unable to access their gadget content and settings from other computers and all content and settings will be lost if Google Desktop is uninstalled." ++ ++Pol_MaxExchangeIndexingRate="Maximum allowed Exchange indexing rate" ++Explain_MaxExchangeIndexingRate="This policy allows you to specify the maximum number of emails that are indexed per minute. \n\nThis policy has no effect when disabled or not configured." ++ ++Pol_EnableSafeweb="Enable or disable safe browsing" ++Explain_Safeweb="Google Desktop safe browsing informs the user whenever they visit any site which is a suspected forgery site or may harm their computer. Enabling this policy turns on safe browsing; disabling the policy turns it off. \n\nIf this policy is not configured, the user can select whether to turn on safe browsing." +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/README.txt b/tools/grit/grit/testdata/README.txt +new file mode 100644 +index 0000000000..a683b3b9e3 +--- /dev/null ++++ b/tools/grit/grit/testdata/README.txt +@@ -0,0 +1,87 @@ ++Google Desktop for Enterprise ++Copyright (C) 2007 Google Inc. ++All Rights Reserved ++ ++--------- ++Contents ++--------- ++This distribution contains the following files: ++ ++GoogleDesktopSetup.msi - Installation and setup program ++GoogleDesktop.adm - Group Policy administrative template file ++AdminGuide.pdf - Google Desktop for Enterprise administrative guide ++ ++ ++-------------- ++Documentation ++-------------- ++Full documentation and installation instructions are in the ++administrative guide, and also online at ++http://desktop.google.com/enterprise/adminguide.html. ++ ++ ++------------------------ ++IBM Lotus Notes Plug-In ++------------------------ ++The Lotus Notes plug-in is included in the release of Google ++Desktop for Enterprise. The IBM Lotus Notes Plug-in for Google ++Desktop indexes mail, calendar, task, contact and journal ++documents from Notes. Discussion documents including those from ++the discussion and team room templates can also be indexed by ++selecting an option from the preferences. Once indexed, this data ++will be returned in Google Desktop searches. The corresponding ++document can be opened in Lotus Notes from the Google Desktop ++results page. ++ ++Install: The plug-in will install automatically during the Google ++Desktop setup process if Lotus Notes is already installed. Lotus ++Notes must not be running in order for the install to occur. The ++Class ID for this plug-in is {8F42BDFB-33E8-427B-AFDC-A04E046D3F07}. ++ ++Preferences: Preferences and selection of databases to index are ++set in the 'Google Desktop for Notes' dialog reached through the ++'Actions' menu. ++ ++Reindexing: Selecting 'Reindex all databases' will index all the ++documents in each database again. ++ ++ ++Notes Plug-in Known Issues ++--------------------------- ++ ++If the 'Google Desktop for Notes' item is not available from the ++Lotus Notes Actions menu, then installation was not successful. ++Installation consists of writing one file, notesgdsplugin.dll, to ++the Notes application directory and a setting to the notes.ini ++configuration file. The most likely cause of an unsuccessful ++installation is that the installer was not able to locate the ++notes.ini file. Installation will complete if the user closes Notes ++and manually adds the following setting to this file on a new line: ++AddinMenus=notesgdsplugin.dll ++ ++If the notesgdsplugin.dll file is not in the application directory ++(e.g., C:\Program Files\Lotus\Notes) after Google Desktop ++installation, it is likely that Notes was not installed correctly. ++ ++Only local databases can be indexed. If they can be determined, ++the user's local mail file and address book will be included in the ++list automatically. Mail archives and other databases must be ++added with the 'Add' button. ++ ++Some users may experience performance issues during the initial ++indexing of a database. The 'Perform the initial index of a ++database only when I'm idle' option will limit the indexing process ++to times when the user is not using the machine. If this does not ++alleviate the problem or the user would like to continually index ++but just do so more slowly or quickly, the GoogleWaitTime notes.ini ++value can be set. Increasing the GoogleWaitTime value will slow ++down the indexing process, and lowering the value will speed it up. ++A value of zero causes the fastest possible indexing. Removing the ++ini parameter altogether returns it to the default (20). ++ ++Crashes have been known to occur with certain types of history ++bookmarks. If the Notes client seems to crash randomly, try ++disabling the 'Index note history' option. If it crashes before, ++you can get to the preferences, add the following line to your ++notes.ini file: ++GDSNoIndexHistory=1 +diff --git a/tools/grit/grit/testdata/about.html b/tools/grit/grit/testdata/about.html +new file mode 100644 +index 0000000000..8e5fad7b2b +--- /dev/null ++++ b/tools/grit/grit/testdata/about.html +@@ -0,0 +1,45 @@ ++[HEADER] ++
++
 [TITLE]
++
Google Desktop Search: Search your own computer.

++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
  Outlook Email   Netscape Mail / Thunderbird
  Outlook Express   Netscape / Firefox / Mozilla
  Word   PDF
  Excel   Music
  PowerPoint   Images
  Internet Explorer   Video
  AOL Instant Messenger   Even more with these plug-ins
  Text and others
++
++

++ ++ ++ ++ ++ ++
Getting Started - Learn more about using Google Desktop Search
Online Help - Up-to-date answers to your questions
Privacy - A few words about privacy and Google Desktop Search
Uninstall - How to uninstall Google Desktop Search
Submit Feedback - Send us your comments and ideas

Google Desktop Search [$~BUILDNUMBER~$]

++[FOOTER] +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/android.xml b/tools/grit/grit/testdata/android.xml +new file mode 100644 +index 0000000000..cc3b141f70 +--- /dev/null ++++ b/tools/grit/grit/testdata/android.xml +@@ -0,0 +1,24 @@ ++ ++ ++ ++ ++ ++ Open %s? ++ ++ ++ ++ A simple string. ++ ++ ++ Contains a comment. ++ ++ ++ Another simple string. ++ ++ ++ Do not translate me. ++ +diff --git a/tools/grit/grit/testdata/bad_browser.html b/tools/grit/grit/testdata/bad_browser.html +new file mode 100644 +index 0000000000..e8cf34664d +--- /dev/null ++++ b/tools/grit/grit/testdata/bad_browser.html +@@ -0,0 +1,16 @@ ++

We're sorry, but we don't seem to be compatible.

++

Our software suggests that you're using a browser incompatible with Google Desktop Search. ++ Google Desktop Search currently supports the following:

++ ++ ++

You may click here to use your ++ unsupported browser, though you likely will encounter some areas that don't ++ work as expected. You need to have Javascript enabled, regardless of the ++ browser you use. ++

We hope to expand this list in the near future and announce new ++ browsers as they become available. +diff --git a/tools/grit/grit/testdata/browser.html b/tools/grit/grit/testdata/browser.html +new file mode 100644 +index 0000000000..45d364d56f +--- /dev/null ++++ b/tools/grit/grit/testdata/browser.html +@@ -0,0 +1,42 @@ ++ ++[$~TITLE~$] ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
[$~IMAGE~$] ++   ++ ++ ++ ++ ++
++ ++ ++ ++ ++
 [$~CHROME_TITLE~$]
++
++ ++ ++ ++ ++ ++
++ [$~BODY~$] ++
++[$~FOOTER~$] ++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/buildinfo.grd b/tools/grit/grit/testdata/buildinfo.grd +new file mode 100644 +index 0000000000..80458a8265 +--- /dev/null ++++ b/tools/grit/grit/testdata/buildinfo.grd +@@ -0,0 +1,46 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Copyright 2008 Google Inc. All Rights Reserved. ++ ++ ++ Google Desktop News gadget ++[IDS_COPYRIGHT_GOOGLE_LONG] ++View news that is personalized based on the articles you read. ++ ++For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles. ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/cache_prefix.html b/tools/grit/grit/testdata/cache_prefix.html +new file mode 100644 +index 0000000000..b1f91dd82b +--- /dev/null ++++ b/tools/grit/grit/testdata/cache_prefix.html +@@ -0,0 +1,24 @@ ++ ++ ++ ++ ++ ++ ++
++ ++ ++
This is one version of ++[URL-DISP] from your personal cache.
++The page may have changed since that time. Click here for the current page.
++Since this page is stored on your computer, publicly linking to this page will not work.[$~EXTRA~$]

++Google may not be affiliated with the authors of this page nor responsible for its content. This page may be protected by copyright. ++
++ ++ ++


++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/cache_prefix_file.html b/tools/grit/grit/testdata/cache_prefix_file.html +new file mode 100644 +index 0000000000..f3eb8e0f11 +--- /dev/null ++++ b/tools/grit/grit/testdata/cache_prefix_file.html +@@ -0,0 +1,25 @@ ++ ++ ++ ++ ++ ++ ++
++ ++ ++
This is one version of [URL-DISP] ++from your personal cache.
++The file may have changed since that time. Click here for the current file.
++Since this file is stored on your computer, publicly linking to it will not work.[$~EXTRA~$]

++Google may not be affiliated with the authors of this page nor responsible for its content. This page may be protected by copyright. ++
++
++ ++ ++
++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/chat_result.html b/tools/grit/grit/testdata/chat_result.html +new file mode 100644 +index 0000000000..318078bc3d +--- /dev/null ++++ b/tools/grit/grit/testdata/chat_result.html +@@ -0,0 +1,24 @@ ++[HEADER] ++[CHROME] ++ ++ ++
[$~STARTCHAT~$]
++
++
++   [$~TITLE~$] ++

Participants: [USERNAME], [BUDDYNAME]
++Date: [TIME]
++
++ ++
++ ++ ++
[$~STARTCHAT~$]
++ ++ ++[FOOTER] +diff --git a/tools/grit/grit/testdata/chrome/app/generated_resources.grd b/tools/grit/grit/testdata/chrome/app/generated_resources.grd +new file mode 100644 +index 0000000000..c2efb77fd8 +--- /dev/null ++++ b/tools/grit/grit/testdata/chrome/app/generated_resources.grd +@@ -0,0 +1,199 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ New background app installed ++ ++ ++ $1Background App will launch at system startup and continue to run in the background even once you've closed all other $2Google Chrome windows. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/chrome_html.html b/tools/grit/grit/testdata/chrome_html.html +new file mode 100644 +index 0000000000..7f7633c5cf +--- /dev/null ++++ b/tools/grit/grit/testdata/chrome_html.html +@@ -0,0 +1,6 @@ ++ ++ +diff --git a/tools/grit/grit/testdata/default_100_percent/a.png b/tools/grit/grit/testdata/default_100_percent/a.png +new file mode 100644 +index 0000000000000000000000000000000000000000..5d5089038ca71172e95db9e7aae1e1fa5cebd505 +GIT binary patch +literal 159 +zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>0wld=oSO}#(mY)pLnNjq|2Y3)zGGzYPN&L+ +zMSC}CcCfp=Dtxv4%6W%G#Q=|R|L;6pCCLUWO)Z<5eoL%TkDTw=s4X!^d(Qa<2khAN +zZPy!XToBAic1Ss}vcWiD27B3&`Zj^H6CO>7R1{ToQ;=ggdEYbV=IISvfHpFCy85}S +Ib4q9e0O9jEh5!Hn + +literal 0 +HcmV?d00001 + +diff --git a/tools/grit/grit/testdata/default_100_percent/b.png b/tools/grit/grit/testdata/default_100_percent/b.png +new file mode 100644 +index 0000000000..6178079822 +--- /dev/null ++++ b/tools/grit/grit/testdata/default_100_percent/b.png +@@ -0,0 +1 @@ ++b +diff --git a/tools/grit/grit/testdata/del_footer.html b/tools/grit/grit/testdata/del_footer.html +new file mode 100644 +index 0000000000..4e19950bfc +--- /dev/null ++++ b/tools/grit/grit/testdata/del_footer.html +@@ -0,0 +1,8 @@ ++ ++ ++ ++
 Remove checked results and return to search.Check all - Uncheck all   ++ ++
++

[$~BOTTOMLINE~$] - ©2005 Google
++ +diff --git a/tools/grit/grit/testdata/del_header.html b/tools/grit/grit/testdata/del_header.html +new file mode 100644 +index 0000000000..72bc6756eb +--- /dev/null ++++ b/tools/grit/grit/testdata/del_header.html +@@ -0,0 +1,60 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
Go to Google Desktop Search  ++ ++ ++ ++ ++
++ ++ ++ ++ ++ ++
 Remove Specific ItemsHelp  
++
++ ++ ++ ++ ++ ++ ++
 Remove checked results and return to search.Check all - ++Uncheck all  
++
++ ++ ++ ++ ++
 Remove ++checked items from Google Desktop Search. Other copies of the same items will not be ++affected.
++ If you view the item again, it will be added back to Google Desktop Search.
++
+\ No newline at end of file +diff --git a/tools/grit/grit/testdata/deleted.html b/tools/grit/grit/testdata/deleted.html +new file mode 100644 +index 0000000000..5ae5f355fa +--- /dev/null ++++ b/tools/grit/grit/testdata/deleted.html +@@ -0,0 +1,21 @@ ++ ++Database Deleted ++ ++ ++ ++ ++ ++ ++ ++
++ ++
Google Desktop Search ++

++
The database has been deleted. Click here to continue.
++ ++ ++
[$~BOTTOMLINE~$]

++

©2005 Google

+\ No newline at end of file +diff --git a/tools/grit/grit/testdata/depfile.grd b/tools/grit/grit/testdata/depfile.grd +new file mode 100644 +index 0000000000..e2f7191218 +--- /dev/null ++++ b/tools/grit/grit/testdata/depfile.grd +@@ -0,0 +1,18 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/details.html b/tools/grit/grit/testdata/details.html +new file mode 100644 +index 0000000000..0ab0e2a90c +--- /dev/null ++++ b/tools/grit/grit/testdata/details.html +@@ -0,0 +1,10 @@ ++[!] ++title Improve Google Desktop Search by Sending Non-Personal Information ++template ++bottomline ++hp_image ++ ++

This documentation is not yet available

++

++[$~BOTTOMLINE~$] - ©2005 Google ++
+diff --git a/tools/grit/grit/testdata/duplicate-name-input.xml b/tools/grit/grit/testdata/duplicate-name-input.xml +new file mode 100644 +index 0000000000..cc4d1d65c5 +--- /dev/null ++++ b/tools/grit/grit/testdata/duplicate-name-input.xml +@@ -0,0 +1,26 @@ ++ ++ ++ ++ ++ ++ Hello %sJoi, how are you doing today? ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/email_result.html b/tools/grit/grit/testdata/email_result.html +new file mode 100644 +index 0000000000..8bb04b988c +--- /dev/null ++++ b/tools/grit/grit/testdata/email_result.html +@@ -0,0 +1,34 @@ ++[HEADER] ++[CHROME] ++ ++ ++
[CONV] ++Reply | Reply to All[$~FORWARD_URL~$] | Compose[$~OUTLOOKVIEW~$] ++
++
++
++   [SUBJECT] ++

[FROM-DISP] ++[TO-DISP] ++[CC-DISP] ++[BCC-DISP] ++[REPLYTO-DISP] ++[DATE-DISP] ++[VIEW-DISP] ++[$~ATTACH~$] ++

++

++ ++
++ ++
[CONV] ++Reply | Reply to All[$~FORWARD_URL~$] | Compose[$~OUTLOOKVIEW~$] ++
++ ++ ++[FOOTER] +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/email_thread.html b/tools/grit/grit/testdata/email_thread.html +new file mode 100644 +index 0000000000..3c7279b841 +--- /dev/null ++++ b/tools/grit/grit/testdata/email_thread.html +@@ -0,0 +1,10 @@ ++[HEADER] ++[CHROME] ++
++   [SUBJECT]

++ ++[CONTENTS] ++
++
++[NEXT_PREV] ++[FOOTER] +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/error.html b/tools/grit/grit/testdata/error.html +new file mode 100644 +index 0000000000..66875a234c +--- /dev/null ++++ b/tools/grit/grit/testdata/error.html +@@ -0,0 +1,8 @@ ++[HEADER] ++[CHROME] ++
++
++[ERROR]

++If you think this is an error, please contact us. ++
++[FOOTER] +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/explicit_web.html b/tools/grit/grit/testdata/explicit_web.html +new file mode 100644 +index 0000000000..1424adc617 +--- /dev/null ++++ b/tools/grit/grit/testdata/explicit_web.html +@@ -0,0 +1,11 @@ ++[HEADER] ++ ++[WEB_TOP_CHROME] ++[$~STATUS~$] ++[$~MESSAGE~$] ++[WEB_FILES] ++
[NEXT_PREV] ++[FOOTER] +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/footer.html b/tools/grit/grit/testdata/footer.html +new file mode 100644 +index 0000000000..3372d6afac +--- /dev/null ++++ b/tools/grit/grit/testdata/footer.html +@@ -0,0 +1,14 @@ ++


++
++ ++ ++

++ ++ ++ ++
[$~BOTTOM~$]

++
++

++[$~BOTTOMLINE~$] - ©2005 Google
++[SCRIPT] ++ +diff --git a/tools/grit/grit/testdata/generated_resources_fr.xtb b/tools/grit/grit/testdata/generated_resources_fr.xtb +new file mode 100644 +index 0000000000..373c40feea +--- /dev/null ++++ b/tools/grit/grit/testdata/generated_resources_fr.xtb +@@ -0,0 +1,3079 @@ ++ ++ ++ ++Salut! ++Salut ++Supprime&r ++Activer la barre de favoris ++Déconnexion du réseau privé ++ sur  ++Déconnecter ce compte... ++&Vérifier l'orthographe dans ce champ ++Aucune donnée reçue. ++Une erreur s'est produite lors de la tentative de lecture du fichier : . ++Le mot de passe multiterme est obligatoire. ++Importer les données d'un autre navigateur... ++Saisie automatique ++API P2P ++Exécuter automatiquement (recommandé) ++Le certificat de sécurité du site a expiré ! ++Clé publique de l'objet ++Importer ++Afficher dan&s un onglet ++ID : ++Le certificat n'indique aucun mécanisme permettant de vérifier s'il a été révoqué. ++Touches de modification... ++Signé par : ++Utiliser un service Web pour résoudre les erreurs de navigation ++Guillemet ++Une nouvelle tentative de connexion avec SSL 3.0 a dû être effectuée. Cette opération indique généralement que le serveur utilise un logiciel très ancien et qu'il est susceptible de présenter d'autres problèmes de sécurité. ++Autoriser le stockage des données locales (recommandé) ++Ouvrir dans une fenêtre ++Google pense qu'un logiciel malveillant pourrait être installé sur votre ordinateur si vous continuez. Nous vous conseillons de ne pas continuer, même si vous avez déjà consulté ce site auparavant ou si vous avez confiance en celui-ci. Il se peut qu'il ait été piraté récemment. Réessayez demain ou utilisez un autre site. ++&Rechercher : ++Échec de génération de clé privée RSA aléatoire ++Certificat en attente ++Technologie réseau : ++Le certificat du serveur ne figure pas dans le DNS. ++Demander le mot de passe au retour de veille ++Désactiver la synchronisation ++Base de données indexée ++Ne pas enregistrer ++ synchronise vos données avec votre compte Google en toute sécurité. Synchronisez toutes vos données ou personnalisez les types de données synchronisées et les options de chiffrement. ++Le délai imparti à l'opération est dépassé. ++Nordique ++Créer des raccourcis vers des applications ++Pas encore chargé ++Confirmer le nouveau code PIN : ++L2TP/IPSec + Certificat utilisateur ++Préfecture ++Extraction de l'image de récupération... ++Terminé ++Il se peut que la page Web à l'adresse soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web. ++Cache des scripts ++Barre d'outils Google ++Importés depuis Safari ++Le plug-in n'est pas autorisé. ++Vous exécutez à partir de son image disque. Si vous l'installez sur votre ordinateur, vous pourrez l'utiliser sans image disque et bénéficierez de mises à jour automatiques. ++Certificat du serveur SSL ++Z&oom arrière ++Indique si la suggestion du moteur de recherche doit être entrée immédiatement via la saisie semi-automatique lorsque la fonctionnalité Recherche instantanée est activée. ++Mise à jour du système : % téléchargés ++Les informations d'identification associées au partage de vos imprimantes via sont arrivées à expiration. Cliquez ici pour saisir à nouveau votre nom d'utilisateur et votre mot de passe. ++Erreur de définition du paramètre de confiance du certificat ++ peut maintenant synchroniser vos mots de passe. ++Sélectionnez le certificat à présenter pour l'identification : ++ a planté. Cliquez sur cette info-bulle pour actualiser l'extension. ++Compatibilité expérimentale avec des méthodes Wi-Fi Extensible Authentication Protocol supplémentaires, telles que EAP-TLS et LEAP. ++Échec de lecture de la clé privée ++Les plug-ins suivants ont été bloqués sur cette page : ++Configuration de la synchronisation ++Case d'option cochée ++Très petite ++URL de révocation de l'autorité de certification Netscape ++Style de pavé numérique ++Active les feuilles de style CSS 3D et la composition graphique haute performance des pages Web via le processeur graphique. ++&Rétablir ++Redémarrer ++La connexion n'est pas compressée. ++Fin ++&Nouvelle fenêtre ++Configuration automatique du proxy ++Afficher l'orthographe et la grammaire ++Aucune imprimante n'a été trouvée. Veuillez en installer une. ++Saisissez les caractères visibles dans l'image ci-dessous. ++Certificat d'authentification de client SSL incorrect ++Le certificat du serveur ou un certificat AC intermédiaire présenté au navigateur a été signé avec un algorithme de signature faible tel que RSA-MD2. D'après des études récentes menées par des informaticiens, les algorithmes de signature seraient plus faibles qu'on ne le pensait jusqu'alors. Aujourd'hui, ils sont très rarement utilisés par les sites Web jugés dignes de confiance. Ce certificat a peut-être été contrefait. Nous vous déconseillons vivement de continuer. ++Rechercher le précédent ++I&nspecter l'élément ++État d'itinérance : ++&Non ++Effacer les données de navigation... ++Nombre maximal de suggestions ++L'accessibilité est désactivée. ++Sélectionner par domaine ++Tout réduire... ++Ne jamais traduire les pages rédigées en ++Non confirmé ++Avant de vous connecter, démarrez une session en tant qu'invité afin d'activer le réseau . ++La gravure de l'image est terminée. ++Si vous supprimez le certificat d'une autorité de certification, votre navigateur ne fera plus confiance aux certificats émis par cette autorité de certification. ++Synchronisez toutes les données de cet ordinateur ou sélectionnez celles que vous souhaitez synchroniser. ++ hours ago ++Domaine : ++Aperçu ++Associe chaque fenêtre du navigateur à un profil et ajoute une option de sélection des profils en haut à droite. Chaque profil possède ses propres favoris, extensions, applications, etc. ++Ignorer le verrouillage des majuscules et saisir des minuscules par défaut ++Aucune parole détectée ++Changer de moteur de recherche par défaut ++Cliquer pour revenir en arrière, maintenir pour voir l'historique ++ secondes restantes ++Unicode ++Ouverture à la fin du téléchargement ++Les extensions, les applications et les thèmes peuvent endommager votre ordinateur. Voulez-vous vraiment continuer ? ++Schéma du pinyin double ++Déconnecter ce compte... ++&Fichier ++Microsoft Internet Explorer ++Aucune correspondance trouvée ++État de votre commentaire ++Mise à jour terminée. Veuillez redémarrer le système. ++Lorsque vous supprimez un certificat de serveur, vous rétablissez les contrôles de sécurité habituels du serveur et un certificat valide lui est demandé. ++Essayez d'ajouter ++ ++ aux programmes autorisés dans les paramètres de votre pare-feu ou de votre antivirus. S'il ++ est déjà autorisé, tentez de le supprimer de la liste et de l'ajouter à nouveau à ++ la liste des programmes autorisés. ++Réseaux sans fil ++Masquer ++Zoom arrière ++Méthode EAP : ++Développer ++Veuillez vous connecter ++de n'importe quand ++Désactiver la validation des formulaires interactifs HTML5 ++Le suivi de votre position géographique sur cette page a été bloqué pour les sites suivants : ++La gravure de l'image a été interrompue. ++&Afficher dans le dossier ++Continuer à bloquer JavaScript ++Enregistrer la page sous... ++Le serveur à l'adresse requiert un nom d'utilisateur et un mot de passe. ++Exceptions de géolocalisation ++13px ++Contenu : ++Le plug-in a été bloqué, car il n'est plus à jour. ++Taille ré&elle ++Échec de la connexion au serveur proxy. ++Vérification de pilote matériel Microsoft Windows ++Paysage ++Détecter automatiquement ++Page ++Nom d'utilisateur : ++Nous aider à améliorer en envoyant automatiquement les statistiques d'utilisation et les rapports d'erreur à Google ++Réseau ++Connexion en cours ++Ajouter tous les onglets aux favoris... ++Onglets ou fenêtres ++Sites récemment consultés ++Ouvrir dans une fenêtre de navigation privée ++Préférences de saisie automatique... ++Compteur d'images par seconde ++Mot de passe ++Afficher le compte ++ : ++Le suivi de votre position géographique a été bloqué pour cette page. ++Connexion à l'aide de votre compte Google ++Le mot de passe multiterme entré est incorrect. ++télécopie : # ++Le navigateur par défaut est actuellement . ++ secondes restantes ++Mot de passe précédent ++Code PIN incorrect ++Modifier l'adresse ++Zoom avant ++Micrologiciel ++Une erreur s'est produite lors de l'affichage de cette page Web. Pour continuer, actualisez cette page ou ouvrez-en une autre. ++Récupération de clé Microsoft ++recto verso ++Fichier ou répertoire introuvable ++Aucun forfait de données actif ++Tout sélectionner ++Le fichier manifeste est incorrect. ++Les pages suivantes ne répondent plus. Vous pouvez attendre qu'elles soient de nouveau accessibles ou les supprimer. ++ minutes restantes ++Le certificat du serveur n'est pas encore valide. ++Menu contenant des extensions masquées ++Enregistrer les infos ++Configuration de l'accès à distance à cet ordinateur. ++Point ++Ajouter un moteur de recherche ++Impossible d'atteindre le serveur. ++Importer mes favoris... ++Enregistrer le &cadre sous... ++Vous n'êtes pas autorisé à accéder à la page Web . Votre connexion peut être requise. ++Envoyer la capture d'écran du dernier onglet actif ++Erreur ++Utiliser le thème GTK+ ++Ouvrir une fenêtre du navigateur ++ a planté. Cliquez sur cette info-bulle pour redémarrer l'application. ++Définir comme navigateur par défaut ++Certificat de courrier électronique ++Clavier en superposition ++La connexion est compressée avec . ++Exporter mes favoris... ++Format : ++Ignorer ++Déplacer un mot ++Index de ++Mémoire ++Impossible d'utiliser cette langue pour corriger l'orthographe. ++Recherche ++Ajouter une autre carte de paiement... ++Envoyer la dernière capture d'écran enregistrée ++Ce fichier contient du code malveillant. Voulez-vous vraiment continuer ? ++Erreur de synchronisation... ++Clavier brésilien ++Utiliser TLS 1.0 ++&Signaler un problème... ++Créer des raccourci&s vers des applications... ++Le certificat "" a été émis par : ++ ne contrôlant pas la façon dont les extensions gèrent vos données personnelles, toutes les extensions sont désactivées dans les fenêtres de navigation privée. Vous pouvez les réactiver individuellement dans le gestionnaire des extensions. ++Logiciels malveillants ++Mise en page ou mise en forme de la page ++Acheter davantage... ++Traduire ++Tout ++Créé : ++Annuler l'importation ++Le mode indiqué est incorrect. ++ copié(s) sur ++L'accès à distance à cet ordinateur est activé pour . ++Options... ++Un problème est survenu lors de la création du support de récupération du système d'exploitation. Le périphérique de stockage utilisé est introuvable. ++Toujours &afficher la barre de favoris ++Erreur SSL ++Confirmer les préférences de synchronisation ++Utiliser les valeurs par défaut ++Code secret manquant ++L'accès à distance à cet ordinateur est désactivé. ++API des extensions expérimentales ++Inclure les informations système ++Date d'expiration ++Autorité de certification compromise ++À propos de la saisie automatique ++Activer la fonction "Taper pour cliquer" ++Accès à la page Web refusé ++&Gestionnaire de favoris ++Erreur serveur ++Cette carte SIM est désactivée et ne peut être utilisée. Veuillez demander à votre fournisseur de services de la remplacer. ++Outils ++Clavier néerlandais ++EAP-TTLS ++Choisissez une image à associer à votre compte. Celle-ci s'affichera sur l'écran de connexion. ++Configurer le blocage des fenêtres pop-up... ++des 4 dernières semaines ++Une situation inattendue s'est produite tandis que le serveur tentait de traiter la demande. ++Impossible d'afficher certaines parties de ce document PDF. Souhaitez-vous l'ouvrir dans Adobe Reader ? ++Proxy FTP ++Si vous utilisez la version PPAPI de Flash, exécutez-la dans chaque processus de moteur du rendu plutôt que dans un processus de plug-in dédié. ++Cela signifie que le certificat présenté à votre navigateur contient des erreurs et qu'il ne peut pas être compris. Il est possible que les informations sur l'identité du certificat ou que d'autres informations du certificat relatives à la sécurité de la connexion soient incompréhensibles. Ne poursuivez pas. ++Activer l'onglet 1 ++Communication à distance ++Importer les favoris et les paramètres... ++À propos ++Modifier le favori de cette page ++Ajouter un format d'exception ++Configurer l'accès à distance... ++Supprimer le certificat "" ? ++Cache des images ++Configuration du proxy ++En l'absence de connexion Wi-Fi, Google Chrome utilise les données 3G. ++Appuyez sur pour sélectionner le mode de saisie précédent. ++La création du support de récupération du système d'exploitation a été annulée. ++Le plug-in suivant est bloqué : ++Erreur de connexion réseau ++Mot de passe multiterme ++Internet ++Configurer les paramètres de blocage des plug-ins... ++Afficher dan&s un onglet ++Synchroniser vos mots de passe ++Le serveur proxy agit comme un intermédiaire entre votre ordinateur et les autres serveurs. Votre configuration système utilise actuellement un proxy, mais ++ ++ ne parvient pas à s'y connecter. ++Sélectionner par type d'application ++Procéder à l'i&nspection de l'élément ++Impossible de valider entièrement l'identité du serveur auquel vous êtes connecté. Le nom utilisé pour cette connexion n'est valide que sur votre réseau et aucune autorité de certification externe ne peut en vérifier la propriété. Certaines autorités de certification délivrent tout de même des certificats pour ces types de nom, par conséquent nous ne sommes pas en mesure de vérifier que vous êtes connecté au site voulu et non à un site malveillant. ++Impossible de déplacer le répertoire d'extensions dans le profil. ++Supprimer ces paramètres pour les prochaines visites ++L'accessibilité est activée. ++Appuyer sur la touche Espace pour sélectionner la suggestion ++Vos favoris ++ () ++Fermer les onglets ++Applications en arrière-plan ++Favoris ++Supprimer les données synchronisées de Google Dashboard ++Veuillez patienter pendant que installe les dernières mises à jour système. ++Utilisez les touches Maj gauche et droite pour sélectionner les 2e et 3e propositions ++WEP ++Mode Zhuyin complet. La sélection automatique de la suggestion et les options associées sont désactivées ou ignorées. ++&Paramètres linguistiques... ++CRX-less Web Apps ++Connexion au réseau ++Reliure bord long ++ utilise les paramètres proxy du système pour se connecter au réseau. ++Application : ++&Descendre ++? Toutes les données présentes sur le périphérique seront supprimées. ++Adresse IP ++Active le nouveau design de la page "Nouvel onglet" (en cours de développement). ++Échec de l'activation ++Ne pas vérifier ++Le chinois simplifié est le mode de saisie initial ++Paramètres SSL sur tout l'ordinateur : ++Votre connexion à n'est pas chiffrée. ++matériel requis ++Gérer les exceptions... ++Rechercher des mises à jour ++Utiliser un mot de passe multiterme pour chiffrer mes données de synchronisation ++Connexion en cours... ++Le serveur ne parvient pas à traiter la demande pour le moment. Ce code indique une situation temporaire. Le serveur sera de nouveau opérationnel ultérieurement. ++Historique ++Destination ++Web audio ++Cookies placés par cette page ++Accès partagé ++Afficher... ++Veuillez vous connecter à . ++Ajouter un nouvel e-mail ++Personnaliser les polices... ++Matériel : ++Erreur de connexion au réseau. ++Cette page Web est introuvable. ++En&registrer la vidéo sous... ++Le certificat du serveur n'est pas approuvé. ++Cop&ier l'image ++Sebeol-sik 390 ++ mins ago ++Autre réseau mobile... ++Erreur HTTP () : ++Signature du code ++Aide ++<sans nom> ++Version du micrologiciel : ++La page ne se charge pas ++Attention, ces fonctionnalités expérimentales peuvent mordre. ++Verrouiller l'écran ou éteindre ++La connexion est chiffrée au moyen de , avec pour l'authentification des messages et pour la méthode d'échange de clés. ++Clavier portugais ++Importation ++Connexion au réseau ++Langues ++Cette erreur peut se produire lors de la connexion à un serveur sécurisé (HTTPS). ++ Elle indique que le serveur tente d'établir une connexion sécurisée, mais ++ que celle-ci ne sera pas du tout sécurisée en raison d'une grave erreur de configuration. ++ Dans ce cas, une intervention ++ est requise sur le serveur. ++ ++ n'utilise pas de connexion non sécurisée pour protéger la confidentialité ++ de vos données. ++La synchronisation de vous permet de partager vos données (favoris, préférences) sur vos ordinateurs en toute simplicité. Pour ce faire, enregistre vos données en ligne via Google lorsque vous vous connectez à votre compte. ++Format ou mise en forme de la page ++Clavier suisse ++En&registrer l'image sous... ++Basculer en mode pleine chasse ou demi-chasse ++Sélectionner... ++Effacer les paramètres d'ouverture automatique ++Ajouter un réseau privé ++ secondes ++Ne pas envoyer de capture d'écran ++Hébreu ++Toujours afficher la barre de favoris ++Impossible de trouver le chemin d'accès absolu du répertoire à empaqueter. ++Créer un profil ++Diners Club ++Paramètres de contenu... ++Activer la recherche instantanée pour accélérer la recherche et la navigation ? ++Plus d'extensions >> ++La valeur d'entrée de la clé privée est obligatoire. ++PEAP ++Fonctionnalités de localisation expérimentales ++Ou&vrir la vidéo dans un nouvel onglet ++Toujours afficher la barre de favoris ++Reliure ++Utilisation de la clé du certificat ++Clavier belge ++ heures restantes ++Afficher toutes les images (recommandé) ++Cliquez sur ++ Démarrer, ++ puis sur ++ Exécuter. ++ Saisissez ++ et cliquez sur ++ OK. ++Nom de volume ++Reliure bord court ++ va configurer les mises à jour automatiques pour tous les utilisateurs de cet ordinateur. ++Effacer les éléments datant : ++Interdire à tous les sites d'afficher des notifications sur le Bureau ++Appuyez sur pour passer d'un mode de saisie à l'autre. ++Ajouter un nouveau fax ++Recherche de contenu en cours... ++Style d'entrée avec Espace ++Vous avez tenté d'accéder à , mais, au lieu de cela, vous communiquez actuellement avec un serveur identifié comme . Cela est peut-être dû à un défaut de configuration du serveur ou à quelque chose de plus grave. Un pirate informatique sur votre réseau cherche peut-être à vous faire visiter une version falsifiée de , donc potentiellement préjudiciable. Nous vous déconseillons vivement de continuer. ++Masquer le bouton ++Modifier l'image ++Ne pas synchroniser mes mots de passe ++JavaScript ++Activer les notifications de ++Afficher les incompatibilités ++Nouvel onglet ++Impossible de charger l'icône "" d'action de page. ++Fermer l'onglet ++Nom d'hôte du serveur : ++Ajouter une carte de paiement ++ : type de fichier inconnu ++Non défini ++Gérer les paramètres de saisie automatique... ++Respecter la &casse ++Autoriser tous les sites à exécuter JavaScript (recommandé) ++Gérer vos périphériques depuis le cloud ++Clavier catalan ++Me demander lorsqu'un site essaie de stocker des données ++Menu ++Sélectionnez le périphérique de stockage amovible à utiliser. ++La traduction a échoué, car nous n'avons pas pu déterminer la langue de la page. ++Vous pouvez créer des profils supplémentaires pour autoriser plusieurs personnes à utiliser et personnaliser Google Chrome. ++Deux-points ++Toujours traduire en ++(désactivée) ++Cela signifie que le certificat n'a pas été vérifié par un tiers reconnu par votre ordinateur. N'importe qui peut émettre un certificat en se faisant passer pour un autre site Web. Ce certificat doit donc être vérifié par un tiers approuvé. Sans cette vérification, les informations sur l'identité du certificat sont sans intérêt. Par conséquent, il nous est impossible de vérifier que vous communiquez bien avec et non avec un pirate informatique ayant émis son propre certificat en prétendant être . Nous vous déconseillons vivement de continuer. ++ requiert que vous cryptiez vos données à l'aide de votre mot de passe Google ou de votre propre mot de passe multiterme. ++ ++N'est pas une autorité de certification ++Date et heure : ++Impossible de charger "" pour le thème. ++Rechercher à nouveau ++En attente de ... ++Masquer ce plug-in ++Enregistrer &sous... ++Ajouter une langue : ++Annuler ++Ouvrir une &adresse... ++Supprimer le mot ++Vous devez saisir deux fois le même mot de passe multiterme. ++Ouvrir dans un onglet épinglé ++Page Web, tout type de contenu ++Activer ++Considérer ce certificat comme fiable pour identifier les développeurs de logiciels. ++Ajouter tous les onglets aux favoris ++Impossible de créer le dossier de favoris. ++Copier l'URL ++Si vous pensez ne pas avoir à utiliser de serveur proxy, procédez comme suit : ++ ++Définir les utilisateurs autorisés à se connecter à un périphérique et autoriser les sessions de navigation en tant qu'invité ++Sélectionnez le répertoire racine de l'extension à empaqueter. Pour mettre à jour une extension, sélectionnez également le fichier de clé privée à réutiliser. ++Pool restreint : ++&Rafraîchir cette page ++&Normal ++PKCS #1 SHA-384 avec chiffrement RSA ++Numéro de série : ++HTTPS/SSL ++Toutes les données de votre ordinateur et des sites Web que vous visitez ++Ceci est une installation secondaire de et ce dernier ne peut pas être défini comme navigateur par défaut. ++Erreur lors de la signature de l'extension ++ permet d'effectuer des recherches sur Internet à l'aide du champ polyvalent. Sélectionnez le moteur de recherche à utiliser : ++Sécurité : ++Adobe Reader n'est pas à jour ++Extensions ou applications ++Effacer les cookies et autres données de site et de plug-in lorsque je ferme le navigateur ++Téléchargement de l'image terminé. ++Favoris ++Afficher les vignettes ++Ne plus afficher ce message ++Agent de récupération de clé Microsoft ++Page de diagnostic de navigation sécurisée ++Adresse ligne 2 ++Décrivez-nous le problème recontré. (Champ obligatoire) ++Cela peut prendre quelques minutes. ++Options de base ++Niveau de zoom par défaut : ++Stockage externe ++Modifi&er les moteurs de recherche... ++Cartes de paiement ++Nom du fichier ++Arrêter la synchronisation ++Actualiser le cadre ++Connexion ++Mémoire privée ++Tout effacer ++Activer la correction orthographique automatique ++Afficher les &infos sur la page ++favoris_.html ++Autoriser uniquement les utilisateurs suivants à se connecter : ++&Muet ++Nouvel ongle&t ++Erreur de synchronisation ++Zoom ++ sur ++Type de clavier ++Délai d'expiration atteint au niveau de la passerelle ou du serveur proxy en attente d'une réponse d'un serveur en amont. ++Déplacer ++Mode de saisie du vietnamien (VIQR) ++Ajouter la page actuelle aux favoris ++<aucun cookie sélectionné> ++Le mot de passe de l'application est incorrect. ++Sélectionner "un mot à la fois" ++Tout bloquer ++Chargement en cours… ++&Rouvrir la fenêtre fermée ++Gérer les exceptions... ++URL ++Katakana demi-chasse ++Ouvrir une adresse ++Données de navigation ++Code PIN incorrect. Veuillez réessayer. ++Non ++Utiliser cette langue pour corriger l'orthographe ++Fermer les autres onglets ++Clé privée non valide. ++Une erreur réseau s'est produite pendant la communication avec le service de gestion des périphériques. ++Importer les données d'un autre navigateur... ++&Ajouter au dictionnaire ++Voulez-vous vraiment ouvrir  onglets ? ++Fabricant du périphérique : ++Afficher l'historique complet ++Illimité ++Clavier Neo2 allemand ++Liste déroulante ++Clé : ++Coller en texte brut ++Afficher les &commandes ++Cette page suit votre position géographique. ++Certificat de chiffrement de courrier électronique ++&Profilage activé ++En savoir plus sur la récupération du système ++Essentielle ++Type MIME ++Autoriser le téléchargement ? ++Clavier croate ++Interdire à tous les sites de suivre ma position géographique ++Utiliser la barre de titre du système et les bordures de la fenêtre ++En bas à gauche ++Informations sur l'erreur : ++Essayez : saisissez "orchidées", puis appuyez sur Entrée. ++Pour utiliser Chrome Web Store, vous devez être connecté à un compte Google. ++Configurer ++Petit problème... Nous n'avons pas réussi à vous authentifier. Veuillez vérifier vos identifiants de connexion puis réessayer. ++Pour gérer à distance la configuration de ce périphérique depuis le cloud, connectez-vous avec votre compte Google Apps. ++Réactiver ++Fermer la fenêtre ++Présentation ++Vous avez saisi un trop grand nombre de codes PIN incorrects. Veuillez contacter pour obtenir une nouvelle clé de déverrouillage du code PIN à 8 chiffres. ++Bloquer le contenu inapproprié ++Configuration avancée ++Utiliser SSL 3.0 ++Règles de confidentialité liées à la navigation sécurisée ++Vous devez être connecté à votre compte Google pour importer les favoris de la barre d'outils Google dans Google Chrome. Connectez-vous et relancez l'importation. ++Ouvrir le lien dans une nouvelle &fenêtre ++Les cookies de ont été bloqués. ++Copies ++&Ouvrir le fichier audio dans un nouvel onglet ++Afficher les noms d'utilisateurs et leur photo sur la page de connexion ++URL de révocation de certificat Netscape ++Ajoute des options de regroupement des onglets dans le menu contextuel des onglets. ++Clavier finnois ++Vérifiez votre connexion Internet. Redémarrez votre routeur, votre modem ++ ou tout autre périphérique réseau que vous utilisez. ++&Afficher le code source de la page ++Le serveur ne prend pas en charge la version HTTP utilisée dans la demande. ++Vos mots de passe enregistrés s'afficheront ici. ++Fermer les onglets sur la droite ++ heures ++ ++ indique qu'un produit ESET intercepte les connexions sécurisées. ++ En général, cela ne constitue pas un problème de sécurité car le ++ logiciel ESET s'exécute souvent sur le même ordinateur. Toutefois, en raison ++ de certaines incompatibilités avec les connexions sécurisées ++ , ++ vous devez configurer les produits ESET de manière à éviter ces ++ interceptions. Cliquez sur le lien En savoir plus pour obtenir des instructions. ++Les requêtes adressées au serveur ont été temporairement limitées. ++Impossible de télécharger l'image. Gravure annulée. ++Activer/désactiver le mode Hanja ++Effacer les paramètres d'ouverture automatique ++Pas après le ++Manifeste : ++Visa ++Clavier anglais canadien ++Récupération de fichier Microsoft ++En&registrer l'image sous... ++Zone ++Chemin : ++Prendre la photo ++Inactif ++Certains de vos certificats enregistrés identifient ces autorités de certification : ++Impossible d'afficher la page Web, car le serveur n'a envoyé aucune donnée. ++Considérer ce certificat comme fiable pour identifier les utilisateurs de messageries. ++Ce type de fichier peut endommager votre ordinateur. Voulez-vous vraiment télécharger  ? ++Importés depuis la barre d'outils Google ++Recherche instantanée et saisie semi-automatique ++Tout synchroniser ++Dvorak (Hsu) ++Exécuter la commande  : ++Le fichier contenait un certificat, qui n'a pas été importé : ++Vous utilisez actuellement un mot de passe multiterme. Si vous l'oubliez, vous pouvez réinitialiser la synchronisation afin de supprimer vos données des serveurs Google à l'aide de Google Dashboard. ++Impossible de détecter les modules chargés. ++Cette fonctionnalité affiche une bordure autour des couches de rendu afin de déboguer et d'étudier leur composition. ++Processus de traitement Web : ++Invité ++Nom du fichier : ++Un élément est manquant. ++Échec de la tentative de connexion au serveur. ++Des fenêtres pop-up ont été bloquées sur cette page. ++Personnaliser les langues et la saisie... ++Proxy HTTP ++Mot de passe multiterme de chiffrement ++Nouvelle fenêtre ++Certains certificats provenant de ces organisations vous identifient : ++Autoriser l'itinérance des données mobiles ++Alt ++Utiliser les pages actuelles ++Version ++En&registrer le fichier audio sous... ++Itinérance ++Romaji ++ minutes ++Synchroniser uniquement les paramètres et\ndonnées qui ont changé depuis la dernière connexion\n(requiert votre mot de passe précédent) ++Autoriser tous les sites à afficher des notifications sur le Bureau ++Ouvrir le fichier... ++Changer de fenêtre ++Chèvres téléportées ++Si vous arrêtez la synchronisation, les données stockées sur cet ordinateur et dans votre compte Google demeureront à ces deux emplacements. Toutefois, les nouvelles données ou les modifications apportées au contenu existant ne seront pas synchronisées. ++Le certificat du serveur ne correspond pas à l'URL. ++Commune ++Impossible d'activer les plug-ins désactivés par une stratégie d'entreprise. ++Ne pas afficher sur cette page ++Méthodes EAP en Wi-Fi expérimentales ++Disque dur ++Nouveau dossier ++intégration sur ++Autorité de certification de messagerie ++Cache CSS ++En haut à gauche ++Saisissez le nom du nouveau dossier. ++L'extension de renégociation SSL était introuvable lors de la négociation sécurisée. Avec certains sites, connus pour leur prise en charge de l'extension de renégociation, Google Chrome exige une négociation mieux sécurisée afin de prévenir certaines attaques. L'absence de cette extension suggère que votre connexion a été interceptée et manipulée au cours du transfert. ++Petit problème... Une erreur de communication avec le réseau est survenue lors de la tentative d'inscription de ce périphérique. Veuillez vérifier votre connexion réseau et réessayer. ++pause ++Afficher tous les téléchargements... ++Connexion à ++Impossible de résoudre l'adresse DNS du serveur. ++En attente de l'affichage du cache ++Thèmes ++Impossible de se connecter au serveur proxy. ++Ignorer la synchronisation des données chiffrées ? ++Oui ++Nombre de suggestions par page ++Modifier le code PIN ++Un problème est survenu lors de la copie de l'image de récupération sur le périphérique. ++ jours restants ++La connexion Internet a été interrompue. ++Début ++« Précédent ++C&opier l'URL de la vidéo ++Vos données sur et ++Langue ++Mappages des stratégies de certificat ++ minutes restantes ++Sélectionner la position ++Le site Web à l'adresse contient des éléments provenant de sites signalés comme étant des sites de phishing. Ces derniers incitent les internautes à divulguer leurs informations personnelles en se faisant passer pour des institutions de confiance, telles que des banques. ++ ++Hors de portée ++Effacer l'historique de navigation ++Aucune page Web trouvée à l'adresse : ++Nouveau moteur de recherche : ++Jamais pour ce site ++ jours restants ++Impossible d'accéder au réseau. ++Modifier l'adresse ++&Masquer le panneau de la vérification orthographique ++1 cookie ++Activer ces fonctionnalités... ++ secondes restantes ++Cou&per ++Fermer la barre de recherche ++Signataire de la liste de révocation de certificats ++Afficher des informations à propos du site ++UC ++Fermer les pages ++MSPY ++ () ++Très petite ++Afficher les réseaux privés dans le menu Réseau pour activer la connexion à un VPN ++Vérification de la mise à jour du système... ++L'entrée demandée est introuvable dans le cache. ++Connectez-vous à pour importer le certificat client. ++Modifier la mise en page ++Se déconnecter ++Espace insuffisant. ++Préférences synchronisées ++Imp&rimer le cadre... ++MSCHAP ++Continuer à bloquer les images ++Lorsqu'un site utilise des plug-ins : ++Échec d'exportation de la clé publique ++Choisir les éléments à synchroniser ++Paramètres de saisie du Pinyin ++Ouvrir les pages suivantes : ++Déconnexion ++Moteurs de recherche ++Erreur de suppression de certificat ++Ne rien faire ++Épingler l'onglet ++réinitialiser la synchronisation ++PKCS #1 SHA-256 avec chiffrement RSA ++Katakana ++Choisir un réseau mobile ++&Historique ++Mode développeur : ++Lien ++Système ++Sélectionnez le fichier de clé privée. ++Insérez une carte SD ou une carte mémoire USB. ++Temps restant : ++Cliquez ici pour exécuter le plug-in . ++Hanyu ++pages ++Configuration en cours ++Erreur inconnue ++ days ago ++La langue utilisée pour Google Chrome est passée de "" à "" après la synchronisation de vos paramètres. ++&Aucune suggestion orthographique ++Erreur de protocole SSL ++Mode de saisie du thaï (clavier Pattachote) ++Ce compte utilisateur n'est pas compatible avec ce service. ++ ne peut pas être exécuté en tant que root. ++C&oller ++Paramètres de contenu... ++Dimensions de l'image ++Sélectionner le fichier à enregistrer sous ++Disque Flash ++Moteur de recherche actuel : ++L'identité de situé à a été vérifiée par . ++Version de l'autorité de certification Microsoft ++Enregistrer une capture d'écran ++Page sur ++Console &JavaScript ++Réponse reçue incorrecte lors de la tentative de chargement de . ++ Cela peut être dû à une opération de maintenance ou à une configuration incorrecte sur le serveur. ++Serveur DNS : ++Pré-rendu : ++Impossible d'accéder à la bibliothèque réseau. ++Des images ont été bloquées sur cette page. ++Toujours autoriser à afficher les images ++Copier l'adr&esse du lien ++Ouvrir dans une fenêtre de navigation privée ++Mode développeur ++Chiffrement des données ++Activer la protection contre le phishing et les logiciels malveillants ++Appuyez sur pour rechercher sur ++Voulez-vous utiliser () au lieu de pour gérer les liens :// à partir de maintenant ? ++Démarrer une session en tant qu'invité ++Nombre maximal de caractères chinois dans la mémoire tampon de pré-édition, notamment les entrées de symboles Zhuyin ++Barre de menus GNOME expérimentale disponible ++Effacer l'historique des téléchargements ++Navigateur bloqué... ++Parenthèse drte ++Calcul du temps de chargement ++Ajouter une carte de paiement... ++Itinérance : ++Arrêter ++Erreur de synchronisation... ++ID de clé de l'autorité de certification ++Extensions ++Imprimez où que vous soyez. ++Un problème est survenu lors du téléchargement de l'image de récupération. ++Cloud Print Proxy ++Une erreur s'est produite lors de la configuration de la synchronisation. ++Fichiers personnalisés ++Impossible de définir le mode une fois la fenêtre créée. ++Date et heure ++Personnaliser les préférences de synchronisation ++Aucune information disponible sur le forfait ++Signaler un problème ++Importer mes favoris et paramètres ++Sélectionnez le menu clé à molette > Paramètres > Options avancées > Modifier les paramètres du proxy et vérifiez que vos paramètres sont définis sur "sans proxy" ou "direct". ++Fermer et annuler les téléchargements ++Autres moteurs de recherche ++ peut maintenant synchroniser vos mots de passe. Pour protéger vos données, vous devez confirmer les informations relatives à votre compte. ++Cette fonctionnalité active les API P2P Pepper et P2P JavaScript. L'API est en cours de développement et n'est pas encore opérationnelle. ++L'identité de ce site Web n'a pas été vérifiée. ++Sessions à l'étranger ++Cette page répertorie tous les modules chargés dans le processus principal et les modules enregistrés de manière à être chargés ultérieurement. ++Afficher les &infos sur le cadre ++Connecté ++Paramètres d'entrée en Chewing ++Conserver sur cette page ++Votre support de récupération est prêt. Vous pouvez le retirer du système. ++Copi&er l'adresse e-mail ++Interdire à tous les sites d'afficher des fenêtres pop-up (recommandé) ++Console &JavaScript ++Empêcher cette page de générer des boîtes de dialogue supplémentaires ++En haut à droite ++Entrez le mot de passe associé à votre application : ++Mode de saisie Google du japonais (pour clavier japonais) ++ est à jour () ++Le serveur a mis fin à la connexion de manière inattendue. ++Il est possible que le serveur hébergeant la page Web soit surchargé ou ait rencontré une erreur. Pour éviter de générer ++ trop de trafic et d'aggraver la situation, ++ a temporairement ++ bloqué l'acceptation des requêtes adressées au serveur. ++ ++ Si vous pensez que ce comportement n'est pas souhaitable, (par exemple, dans le cas où vous déboguez votre propre site Web), vous pouvez ++ consulter la page , ++ sur laquelle vous pourrez trouver plus d'informations ou désactiver cette fonctionnalité. ++Gestionnaire de &fichiers ++Arrêter la synchronisation du compte ++Ajouter ++Sélectionnez le fichier à ouvrir ++Aucun forfait de données ++Créer un compte Google ++Code postal ++&Gestionnaire de tâches ++Téléphone ++Sélectionner l'onglet précédent ++Sélectionner un certificat ++Mots de passe enregistrés ++Autoriser l'accès aux URL de fichier ++Modifi&er les moteurs de recherche... ++Gérer les moteurs de recherche... ++PKCS #7, chaîne de certificats ++Clé pré-partagée : ++Contrôlez et partagez l'accès à vos imprimantes depuis n'importe quel compte Google. ++Ajoute l'option "Utiliser les onglets latéraux" au menu contextuel de la barre d'onglets. Utilisez cette option pour déplacer les onglets du haut de l'écran (affichage par défaut) vers le côté. Particulièrement utile sur les grands écrans. ++S'inscrire ++, ++Saisissez un nouveau nom. ++ ne peut pas être affiché dans cette langue. ++Erreur : impossible de décoder l'extension. ++Clavier bulgare ++Accès aux informations de l'autorité ++Ajouter un réseau privé... ++C&opier l'URL du fichier audio ++Masque de sous-réseau : ++Impossible d'accéder à votre compte ? ++Utiliser les touches - et = pour paginer une liste d'entrées ++Le serveur ne prend pas en charge l'extension de renégociation TLS. ++Résolution de l'hôte... ++Récemment fermés ++Le certificat de sécurité du site a été signé avec un algorithme de signature faible. ++Votre mot de passe a été modifié ++Gérer les paramètres de saisie automatique... ++La page Web n'est pas disponible pour le moment. Cela peut être dû à une surcharge ou à une opération de maintenance. ++Éjecter ++Impossible de lancer le processus de service. ++ Mo restants ++Nouvelle fenêtre ++Sélectionnez ++ ++ Applications > Préférences système > Réseau > Avancé > Proxys ++ ++ et désélectionnez les serveurs proxy sélectionnés. ++Gravure en cours d'initialisation... ++Téléchargement de l'image de récupération... ++il y a  minutes ++Mode de saisie du chinois (cangjie) ++Comté ++Ouvrir l'adresse dans un nouvel onglet ++&Rouvrir l'onglet fermé ++Impossible d'afficher la page Web, car votre ordinateur est passé en mode ++ veille ou hibernation. Dans ce cas, les connexions réseau sont ++ coupées et les requêtes réseau échouent. L'actualisation de la page ++ devrait permettre de résoudre ce problème. ++Certificat utilisateur : ++Autoriser ++Appuyer sur Entrée pour revenir en arrière et sur la touche de menu contextuel pour afficher l'historique ++ZRM ++Cookies et autres données ++Page(s) ne répondant pas ++Paramètres d'entrée hangûl ++Configurer la synchronisation... ++Modules (). Conflits connus : , conflits probables : ++Date de renouvellement du certificat Netscape ++Ouvrir tous les favoris dans une nouvelle fenêtre ++bouton radio concernant l'étendue de pages ++Saisissez votre mot de passe ++ est conçu pour rendre l'impression plus intuitive, accessible et utile. vous permet de rendre vos imprimantes accessibles depuis n'importe quelle application Web ou mobile associée à . ++Dictionnaire de kanji unique ++Rétablir tous les onglets ++Échec de l'installation de l'extension ++En savoir plus sur la manière de se protéger des logiciels malveillants en ligne ++Toujours afficher les fenêtres pop-up de ++Authentification phase 2 : ++Aucun résultat de recherche trouvé ++Ouvrir une fois le téléchargement &terminé ++ cookies ++Mode de saisie du japonais (pour clavier américain) ++Continuer à bloquer les plug-ins ++Épingler sur la barre des tâches ++Les certificats ont une période de validité, comme tous les documents relatifs à votre identité (tel qu'un passeport). Le certificat présenté à votre navigateur n'est pas encore valide ! Lorsqu'un certificat est en dehors de sa période de validité, il n'est pas nécessaire d'assurer la maintenance de certaines informations relatives à son état (s'il a été révoqué ou s'il n'est plus approuvé). Par conséquent, il est impossible de vérifier que le certificat est fiable. Ne poursuivez pas. ++Fermer la session d'invité ++Contrôlez vos tâches d'impression et l'état de connexion de vos imprimantes en ligne. ++Désinstallation ++Empreinte SHA-1 ++Modifier le code PIN de la carte SIM ++État du réseau : ++sans limite ++(Choisir une autre capture d'écran) ++Désactivation ++Aucune erreur n'a été signalée récemment. Les erreurs n'apparaissent ici que lorsque l'envoi de rapports d'erreur est activé. ++Rouvrir les dernières pages ouvertes ++Ouvrir en mode plein écran ++Ajouter une carte de paiement ++Désactivé ++Chargement des informations sur votre forfait Internet mobile, veuillez patienter... ++Acheter un forfait de données... ++Inclure cet e-mail : ++Le titre doit comporter au moins un caractère. ++Espaces de noms réseau ++ n'a pas pu terminer l'installation, mais va poursuivre son exécution à partir de son image disque. ++Gestion des services Internet mobiles ++Utiliser les onglets latéraux ++Non ++Saisir le code PIN de la carte SIM ++&Afficher dans le Finder ++Maintenez la touche Ctrl, Alt ou Maj enfoncée<br>pour afficher le raccourci clavier qui lui est associé. ++Vraiment désolé, aucun prototype n'est disponible pour le moment. ++&Afficher dans le Finder ++Informations relatives au certificat ++/ ++La synchronisation des mots de passe requiert votre attention. ++Veuillez saisir l'ancien et le nouveau code PIN. ++Langue : ++Résultats de recherche ++Serveur SSL avec fonction d'optimisation ++Enregistrer en PDF ++Mémoire USB détectée ++M'avertir lorsque le flux de données est faible ou presque inexistant ++Saisir le mot de passe multiterme ++Clavier lituanien ++Les éléments saisis dans le champ polyvalent peuvent être enregistrés. ++Les informations de connexion à votre compte sont obsolètes. Cliquez ici pour saisir à nouveau votre mot de passe. ++Vietnamien ++feuilles de papier ++URL de mot de passe perdu Netscape ++Rouvrir l'onglet fermé ++Effacer les mots de passe enregistrés ++Créer un nouveau dossier... ++Basculer en mode ponctuation pleine chasse ou demi-chasse ++Gérer les paramètres de localisation... ++Synchronisé... ++Options de recherche par défaut ++Aucune sélection ++Mode de saisie du vietnamien (TELEX) ++ minute restante ++Le nombre maximal d'autorités de certification intermédiaires a été dépassé : ++Saisissez un mot de passe pour chiffrer ce fichier de certificat. ++Organiser ++Votre mot de passe a changé. Veuillez réessayer avec votre nouveau mot de passe. ++PKCS #1 MD5 avec chiffrement RSA ++Utiliser le thème classique ++Échap efface toute la mémoire tampon de pré-édition ++Ajouter aux favoris ++Un incident est survenu sur une partie de cette page (HTML WebWorker). Elle risque de ne pas fonctionner correctement. ++Clavier américain ++Signataire de code ++Adobe Reader n'est pas à jour et risque de ne plus être sécurisé. ++Personnaliser les paramètres de synchronisation... ++Co&ller et rechercher ++Détails du certificat sélectionné : ++Impossible de se connecter ++Activation : ++Système de révocation introuvable dans le certificat du serveur ++Numéro de série ++Afficher la page "Nouvel onglet" ++il y a  heure ++Votre ordinateur redémarrera une fois la mise à jour effectuée. ++Verr. maj. ++L'accès au répertoire de l'hôte de communication à distance a été refusé. Essayez avec un autre compte. ++Accessible aux scripts : ++Cette page place des cookies. ++Proxy ++Avec sous-menu ++Afficher dans le dossier ++il y a  minutes ++<saisir une requête> ++Appuyez sur pour envoyer des commandes à . ++Prévisualiser le rapport ++Activer le dernier onglet ++Lorsque je quitte le navigateur ++Continuer sans mettre à jour Adobe Reader (non recommandé) ++Le champ de mot clé doit être vide ou comporter un mot unique ++Déplacer le curseur automatiquement au caractère suivant ++Enregistrer ++Ouvrir le lien dans un nouvel ongle&t ++Nouvelle fenêtre de navigation privée ++Celtique ++Réinitialiser le zoom ++Prototypes ++Mémoriser mes choix pour tous les liens de ce type ++Les plug-ins de cette page ont été bloqués. ++Site ++Sélectionner ++Couper ++Restaurer toutes les miniatures supprimées ++Utiliser les onglets latéraux ++Se connecter au dispositif de sécurité ++Enregistrer le fichier ++Pages ++Options de ++Barre de lancement rapide ++Annuler ++Choisir un fichier ++&Rechercher avec ++(pas encore valide) ++Mettre à jour le plug-in... ++Police Sans-Serif ++Impossible de charger le JavaScript "" du script de contenu. ++Connexion... ++Mots de passe ++Fichiers PKCS #12 ++Options de saisie automatique de ++Fenêtre précédente ++Astuce ++ / fichiers ++Localisation utilisée, mais les paramètres régionaux par défaut (default_locale) n'ont pas été indiqués dans le manifeste. ++Si vous n'êtes pas à l'origine de cette requête, il s'agit probablement d'une attaque contre votre système. Si vous n'avez pas lancé cette requête de manière intentionnelle, cliquez sur Ne rien faire. ++Votre commentaire a bien été envoyé. ++Fonction d'optimisation internationale Netscape ++Taille de police minimale ++Suivant ++Utilitaire : ++Cette opération peut prendre une minute... ++Le format du mot de passe est incorrect. ++Chargement... ++Ajouter la page... ++Masquer ce plug-in ++&Paramètres linguistiques... ++Créer un support de récupération du système d'exploitation ++Le fichier de clé privée est incorrect. ++Valeur : ++Stable ++Grande ++Certificat serveur invalide ++Jamais enregistrés ++Cette page a été préchargée. ++Google Chrome ne peut pas afficher l'aperçu avant impression lorsque la visionneuse de documents PDF intégrée est désactivée. Pour l'afficher, veuillez accéder à chrome://plugins, activer "Chrome PDF Viewer" et réessayer. ++Nouveau ! ++Vous êtes passé en navigation privée. Les pages que vous consultez dans cette fenêtre n'apparaîtront ni dans l'historique de votre navigateur, ni dans l'historique des recherches, et ne laisseront aucune trace (comme les cookies) sur votre ordinateur une fois que vous aurez fermé la fenêtre de navigation privée. Tous les fichiers téléchargés et les favoris créés seront toutefois conservés. Passer en navigation privée n'a aucun effet sur les autres utilisateurs, serveurs ou logiciels. Méfiez-vous : Des sites Web qui collectent ou partagent des informations vous concernant Des fournisseurs d'accès Internet ou des employeurs qui conservent une trace des pages que vous visitez Des programmes indésirables qui enregistrent vos frappes en échange d'émoticônes gratuites Des personnes qui pourraient surveiller vos activités Des personnes qui se tiennent derrière vous En savoir plus sur la navigation privée ++Le certificat du serveur a été révoqué. ++&Reprendre ++Sélectionnez un réseau : ++Impossible d'extraire les fichiers de l'extension. Pour effectuer cette opération en toute sécurité, vous devez disposer d'un chemin d'accès à votre répertoire de profils ne contenant pas de lien symbolique. Aucun chemin de ce type n'existe pour votre profil. ++Effacer les données de navigation ++Si vous êtes conscient que la visite de ce site peut être préjudiciable à votre ordinateur, vous pouvez . ++Votre périphérique est inscrit pour bénéficier de la gestion d'entreprise. ++Serveur de mise à jour non disponible (erreur : ) ++Module client natif : ++Rechercher sur  : ++Style de symboles ++ hours ++Département ++Continuer à utiliser ++OK ++Essayez de désactiver les prédictions d'actions du réseau en procédant comme suit : ++ Sélectionnez le ++ ++ menu clé à molette > ++ ++ > ++ ++ ++ et désélectionnez "". ++ Si le problème n'est pas résolu, nous vous conseillons de sélectionner de nouveau ++ cette option pour améliorer les performances. ++Date ++Sélectionnez un certificat pour vous authentifier sur . ++Barre latérale ++La clé publique éphémère Diffie-Hellman associée au serveur est peu sûre. ++Rechercher dans Dictionnaire ++Sélectionnez un moteur de recherche ++Clavier russe ++Nom Microsoft principal ++Clavier polonais ++Clavier serbe ++ minute ++Erreur lors de la lecture des données du cache. ++Canary ++Commentaire du certificat Netscape ++Page suivante ++ est à jour. ++Paramètres de saisie automatique... ++Tout ramener au premier plan ++Sélectionner le dossier à ouvrir ++Activer le mode Pinyin fuzzy ++Résolution du proxy... ++Le téléchargement de l'image a été interrompu. ++Eten 26 ++URI ++Clavier Dvorak américain ++Rechercher sur le Web... ++Si vous utilisez un serveur proxy, vérifiez les paramètres associés ou demandez à votre administrateur réseau ++ si ce serveur fonctionne. ++Impossible de charger l'icône de l'extension "". ++Définir un proxy pour se connecter au réseau ++zone de texte concernant l'étendue de pages ++Activation ++Clavier Dvorak britannique ++ jours ++MS-IME ++Aucun forfait de données ++Les fenêtres pop-up suivantes ont été bloquées sur cette page : ++ heures restantes ++Impossible de charger le modèle du favori. ++Échec d'exportation de la clé privée ++Utiliser comme page d'accueil ++Compte ++Plein écran ++Autoriser tous les sites à suivre ma position géographique ++Si la restauration du système d'exploitation de votre ordinateur s'avère nécessaire, une carte SD ou une clé USB de récupération vous sera demandée. ++Les cookies suivants ont été bloqués : ++Inclure les adresses de ma fiche de Carnet d’adresses ++Le certificat de sécurité du site n'est pas approuvé ! ++Votre liste d'applications, d'extensions et de thèmes installés ++Exécuter tous les plug-ins de cette page ++Augmente la taille du texte ++Accepter et continuer » ++Fichiers ++ ++Appliquer uniquement à cette session de navigation privée ++Latin large ++Exécuter ce plug-in ++MasterCard ++Sur le Web, Tab permet de sélectionner les liens, ainsi que les champs de formulaire. ++À propos de ++Paramètres de sécurité du système ++Images ++Cyrillique ++Pas maintenant ++Attendre la fin du téléchargement ++Thème "" installé ++&Supprimer ++Menu Démarrer ++&Zoom ++Transfert en cours ( %)... ++Géré par ++&Rafraîchir ++Configuration du module de plate-forme sécurisée (TPM) en cours. Veuillez patienter, cela peut prendre quelques minutes. ++Vous avez acheté une quantité illimitée de données le . ++Confirmer avant de quitter () ++Mémoire partagée ++Rech. dans les paramètres ++mot de passe d'accès au réseau ++Activer la vérification orthographique ++Types de données ++Bloquer ++Certificat de l'autorité de certification du serveur : ++Clavier grec ++Taille réelle ++Toujours en haut ++Aucun plug-in installé. ++Alerte JavaScript ++Autoriser en mode navigation privée ++Rétablir ++, expire le : ++Confirmer la désinstallation ++Impossible de désactiver les plug-ins ayant été activés par une stratégie d'entreprise. ++Cette fonctionnalité active l'option "Lire en un clic" dans les paramètres de contenu du plug-in. ++Attendre la fin des téléchargements ++Synchronisation ++&Rouvrir l'onglet fermé ++Votre mot de passe de compte Google a changé depuis votre dernière connexion à partir de cet ordinateur. ++Le fichier contenait plusieurs certificats, aucun d'eux n'a été importé : ++Afficher le bouton ++La saisie dans le champ polyvalent d'une URL déjà ouverte dans un autre onglet entraîne l'affichage de l'onglet en question, et non l'affichage de l'URL dans l'onglet actuel. ++Configuration en cours... ++Rechercher dans les téléchargements ++Me demander lorsqu'un site tente de suivre ma position géographique (recommandé) ++La nouvelle version de "" a été désactivée, car elle nécessite davantage d'autorisations. ++Clavier phonétique russe ++American Express ++Ce serveur exige un certificat d'authentification et n'a pas accepté celui envoyé par le navigateur. ++Votre certificat a peut-être expiré ou le serveur n'a pas approuvé l'émetteur. ++Réessayez avec un autre certificat si vous en avez un. ++Sinon, vous devrez en obtenir un nouveau d'un autre émetteur. ++Lorsque vous vous connectez à un site Web sécurisé, le serveur hébergeant ce site présente à votre navigateur un "certificat" afin de vérifier l'identité du site. Ce certificat contient des informations d'identité, telles que l'adresse du site Web, laquelle est vérifiée par un tiers approuvé par votre ordinateur. En vérifiant que l'adresse du certificat correspond à l'adresse du site Web, il est possible de s'assurer que vous êtes connecté de façon sécurisée avec le site Web souhaité et non pas avec un tiers (tel qu'un pirate informatique sur votre réseau). ++À l'instant ++Votre carte SIM sera définitivement désactivée si vous ne saisissez pas correctement la clé de déverrouillage du code PIN. Nombre de tentatives restantes : ++ / octets, Interrompu ++Importés depuis Firefox ++Détection automatique ++&Aide ++Les codes PIN sont différents ! ++Contenu Web ++Vider le cache ++Rétablir le thème par défaut ++Le service de communication à distance a démarré correctement. Vous devriez maintenant pouvoir vous connecter à distance à cet ordinateur. ++Outils de développement ++Police Serif ++Copier ++Adresse e-mail ou mot de passe incorrect. Veuillez réessayer. ++Le plug-in suivant ne répond pas : souhaitez-vous interrompre ? ++Sens ++ secondes ++Clavier tchèque ++Voulez-vous que "" soit considérée comme une autorité de certification fiable ? ++Gestionnaire de sécurité natif du client ++<p>Lorsque vous exécutez dans un environnement de bureau pris en charge, les paramètres proxy du système sont utilisés. Toutefois, soit votre système n'est pas pris en charge, soit un problème est survenu lors du lancement de votre configuration système.</p> ++ ++ <p>Vous avez toujours la possibilité d'effectuer la configuration via la ligne de commande. Pour plus d'informations sur les indicateurs et les variables d'environnement, veuillez vous reporter à <code>man </code>.</p> ++La page Web à l'adresse a déclenché trop de redirections. Pour résoudre le problème, effacez les cookies de ce site ou autorisez les cookies tiers. Si le problème persiste, il peut être dû à une mauvaise configuration du serveur et n'être aucunement lié à votre ordinateur. ++SSID : ++Nom du forfait : ++Adresse X.400 ++Fermer l'onglet ++Impossible de trouver un navigateur pris en charge. ++Le compte associé à la boutique en ligne est le suivant : . L'utilisation d'un autre compte pour la synchronisation provoque des erreurs. ++Enregistrer la p&age sous... ++ importe actuellement les éléments suivants à partir de  : ++Appuyez sur Entrée pour avancer et sur la touche de menu contextuel pour afficher l'historique ++Actualiser le cadre ++Annulé ++Autorités ++Sélectionnez votre clavier : ++Signaler un problème... ++Ignorer ce réseau ++Nouveau matériel détecté ++Vous disposez de certificats qui n'appartiennent à aucune autre catégorie : ++&Profilage activé ++(Navigation privée) ++&Nouveau dossier ++Types MIME : ++Afficher les pages en arrière-plan () ++Fichiers audio ++Plug-ins ++Plus d'informations... ++Se connecter automatiquement à ce réseau ++Titulaire de la carte ++Elle peut désormais accéder à : ++Noir et blanc ++Ignorer la connexion et naviguer en tant qu'invité ++Toutefois, cette page inclut d'autres ressources qui ne sont pas sécurisées. Ces ressources peuvent être consultées par des tiers pendant leur transfert, et modifiées par un pirate informatique dans le but de changer l'aspect et le comportement de cette page. ++Accès réseau interrompu ++La dernière version de l'extension "" requiert d'autres permissions. Elle a donc été désactivée. ++Dans ce cas, le certificat du serveur ou un certificat d'autorité intermédiaire présenté à votre navigateur n'est pas valide. Cela peut signifier que le certificat est incorrect, qu'il contient des champs non valides ou qu'il n'est pas compatible. ++Veuillez saisir la clé de déverrouillage du code PIN à 8 chiffres fournie par . ++Exceptions... ++Connexion à ++Voulez-vous vraiment quitter alors qu'un téléchargement est en cours ? ++Le site Web ne parvient pas à gérer la demande associée à . ++Précédent ++&Arrêter ++Lorsque l'option permettant de bloquer l'enregistrement des cookies tiers est activée, la lecture de ces cookies est également bloquée. ++ : ++Console JavaScript ++Les sites pour lesquels vos mots de passe ne seront jamais enregistrés s'afficheront ici. ++Inconnu ++Mode de saisie du thaï (clavier TIS-820.2538) ++&Favoris ++Désinstaller ++Voulez-vous vraiment quitter alors que  téléchargements sont en cours ? ++Configurer le blocage des cookies... ++ABC ++L'application hébergée par est inaccessible, car vous êtes déconnecté du réseau. Cette page s'affichera dès que la connexion réseau sera rétablie. <br> ++Gestionnaire de favoris ++ secs ago ++Quitter le mode plein écran ++Ouvrir l'&image dans un nouvel onglet ++Favori ajouté ! ++Choisir un autre dossier... ++Kotoeri ++Hier ++Synchroniser automatiquement les éléments suivants : ++Votre ordinateur intègre un périphérique de sécurité TPM (module de plate-forme sécurisée) qui permet de mettre en œuvre plusieurs fonctionnalités de sécurité critiques dans Google Chrome OS. ++Contraintes des stratégies de certificat ++Créer un support de récupération ++Emplacement : ++Toutes les pages que vous consultez apparaîtront ici à moins que vous ne les ouvriez dans une fenêtre en navigation privée. Vous pouvez utiliser le bouton Rechercher de cette page pour rechercher dans toutes les pages de votre historique. ++Options pour les développeurs ++Cookies ++Toujours exécuter pour ce site ++Afficher le dossier ++Autres favoris ++Clavier français ++ ne parvient pas à déterminer ou à définir le navigateur par défaut. ++Sélectionner l'onglet suivant ++Voulez-vous vraiment supprimer ces pages de votre historique ? ++Déverrouiller ++ID de clé : ++Exécuter ce plug-in ++Utilisateurs ++Ajouter un moteur ++Répondeur OCSP : ++Ignorer ++Champs de certificat ++Modules () : aucun conflit détecté. ++Onglet : ++Impossible de charger la page d'options "". ++Coller en adaptant le style ++Veuillez ajouter une autre langue avant de supprimer celle-ci. ++nom du réseau ++ synchronise de manière sécurisée vos données avec votre compte Google. ++Taille ++Activer... ++Recherche ++Poursuivre quand même ++Nouveau code PIN : ++La capacité du périphérique doit être d'au moins 4 Go. ++De droite à gauche ++Activer le mode Pinyin double ++Menu contenant des favoris masqués ++Utiliser le dictionnaire système ++Vous avez choisi de chiffrer les données à l'aide de votre mot de passe Google. Vous pouvez modifier vos paramètres de synchronisation à tout moment, si vous changez d'avis. ++Personnaliser les polices... ++Enregistrement des informations de date ++&Vérifier l'orthographe du texte de ce champ ++Ceci est un modèle expérimental qui permet aux enregistrements DNS (utilisant le protocole de sécurité DNSSEC) d'autoriser ou de refuser des certificats HTTPS. Ce message s'affiche lorsque vous activez des fonctionnalités expérimentales via des options de ligne de commande. Vous pouvez supprimer ces options de ligne de commande pour ignorer cette erreur. ++ minutes restantes ++Île ++Contraintes de base du certificat ++Autres... ++Activer l'onglet 4 ++Données personnelles ++Afficher l'original ++Nom de la société ++Définir Adobe Reader comme visionneuse de documents PDF par défaut ? ++Pour gérer les extensions installées, cliquez sur Extensions dans le menu Fenêtre. ++Accédez à vos imprimantes depuis n'importe quel ordinateur ou smartphone. En savoir plus ++Me &le rappeler plus tard ++Opération réussie ! ++Carte SD détectée. ++ - Propriétaire ++Clavier japonais ++WPA ++janv.^févr.^mars^avr.^mai^juin^juil.^août^sept.^oct.^nov.^déc. ++Sélectionnez ++ ++ Applications > Préférences système > Réseau > Assistant ++ ++ pour tester votre connexion. ++&Afficher le code source de la page ++Micrologiciel : ++Créer un profil ++Date de modification ++Sandbox seccomp ++Signale&r un problème... ++Entrée de symboles simplifiée ++Chinois simplifié ++Hôte SOCKS ++Considérer ce certificat comme fiable pour identifier les sites Web. ++Exceptions de localisation ++Hiragana ++Le mot de passe TPM ci-dessous, généré de façon aléatoire, a été attribué à votre ordinateur : ++Importer mes favoris maintenant... ++ ++Avertissement : Un problème a été détecté sur cette page. ++Avec Google Chrome OS for business, vous pouvez connecter votre périphérique à Google Apps, ce qui vous permet de le rechercher et de le contrôler depuis le panneau de configuration de Google Apps. ++Ajouter tous les onglets aux favoris... ++Émis le ++Lorsque je ferme le navigateur ++Localisation ++Attendre ++Infos sur la clé publique de l'objet ++Plug-in inconnu ++Connexion en mode invité ++Toujours autoriser à paramétrer les cookies ++Résumé ++Le certificat du serveur n'est pas valide. ++Chaîne de certificats codés Base 64 ASCII ++Choisir mon propre mot de passe multiterme ++Certificat de serveur non répertorié ++Rechercher la sélection ++Activer ++L'accès à ce réseau est protégé. ++E-mail ++Erreur () : ++Signature permanente Microsoft ++Sélectionnez ++ ++ Démarrer > Panneau de configuration > Réseau et Internet > Centre Réseau et partage > Résolution des problèmes (en bas) > Connexions Internet. ++ ++Gestionnaire de &fichiers ++Service client ++Impossible de se connecter au réseau "". ++J'accepte ces termes ++Copier l'adr&esse du lien ++Veuillez démarrer en tant qu'utilisateur normal. Pour l'exécuter en tant que root, vous devez indiquer un autre répertoire de données utilisateur pour stocker les informations du profil. ++Le processus du connecteur est bloqué. Voulez-vous le redémarrer ? ++Contenu Web ++Clé compromise ++Supprimer ++Si vous fermez maintenant, ces téléchargements seront annulés. ++Dachen 26 ++Voulez-vous vraiment graver l'image sur le périphérique suivant : ++Mémoire SQLite ++/, ++ est affiché dans cette langue. ++Fenêtre pop-up bloquée ++ : ++Ouvrir tous les favoris ++Effacer les cookies et autres données de site et de plug-in lorsque je ferme le navigateur ++Page d'accueil ++Onglet ++Non configuré ++Opération réussie ! ++Relancez pour terminer la mise à jour. ++Chiffrer toutes mes données ++Veuillez patienter pendant que nous configurons votre réseau pour mobile. ++Points de distribution de listes de révocation des certificats ++Association ++Appuyez sur Maj+Alt pour changer la disposition du clavier. ++Utiliser l'horloge au format 24 heures ++ est prêt à terminer l'installation. ++Lancez votre recherche à partir d'ici ++OK, synchroniser tout ++Afin d'être correctement affichée, cette page requiert des données que vous avez précédemment entrées. Vous pouvez de nouveau transmettre ces données, mais, en procédant ainsi, vous devrez répéter chaque action que cette page a effectuée auparavant. Cliquez sur Rafraîchir pour transmettre de nouveau ces données et pour afficher cette page. ++Cela signifie que le certificat présenté à votre navigateur a été révoqué par son émetteur. L'intégrité de ce certificat a certainement été compromise, et il ne doit donc pas être approuvé. Ne poursuivez pas. ++Clavier slovaque ++Nom de partie EDI ++Vous avez déjà chiffré des données avec un mot de passe multiterme. Saisissez-le ci-dessous. ++Informations sur le site ++Créer un raccourci vers l'application... ++Authentification requise ++ n'est pas parvenu à se connecter à . Sélectionnez un autre réseau ou réessayez. ++Votre compte n'est pas compatible avec . Contactez l'administrateur de votre domaine ou utilisez un compte Google standard pour vous connecter. ++Adresse e-mail ++Client natif ++Chargé depuis : ++Active les balises canvas hautes performances dans un contexte 2D, pour effectuer le rendu via le processeur graphique. ++Cette page ena été traduite en ++Seule une personne en possession de votre mot de passe multiterme peut lire vos données chiffrées. Google ne reçoit ni n'enregistre votre mot de passe multiterme. Si vous oubliez votre mot de passe multiterme, vous devrez ++Autorité de certification SSL ++ contient un logiciel malveillant. Votre ordinateur pourrait être infecté par un virus si vous consultez ce site. ++Aucune donnée disponible. ++Im&primer... ++Description ++Voix non reconnue. ++Aucun fichier sélectionné ++Souhaitez-vous installer  ? ++Activité récente ++de la dernière semaine ++Profil ++Actualiser sans utiliser le cache ++Logiciels malveillants et sites de phishing détectés ! ++Onglet fermé ! ++il y a  jours ++Paramètres ++Ce site exige que vous vous identifiiez avec un certificat : ++Supprimer... ++&Aucune suggestion orthographique ++Clavier franco-canadien ++Clavier étendu américain ++Le serveur a mis fin à la connexion sans envoyer de données. ++Autoriser à afficher des notifications sur le Bureau ? ++Pour gérer les extensions installées, cliquez sur Extensions dans le menu Outils. ++Erreur de synchronisation, veuillez vous connecter à nouveau. ++La liste suivante fait état des éléments dangereux détectés sur la page. Cliquez sur le lien "Diagnostic" pour obtenir plus d'informations sur un élément particulier. ++Émirat ++Synchroniser tous les paramètres et toutes les données\n(peut prendre un certain temps) ++Toujours demander où enregistrer les fichiers ++Créer un raccourci ++Tous les fichiers ++Sebeol-sik No-shift ++Anglais (pleine chasse) ++2D avec canvas et accélération matérielle ++Cette fonctionnalité autorise l'installation d'applications Google Chrome déployées à partir d'un manifeste situé sur une page Web, plutôt qu'avec un fichier crx contenant le manifeste et les icônes. ++Nouvelle connexion ++GPU ++Moins de 1 Mo disponible ++Nouvelle fenêtre de navigation privée ++Europe du Sud ++Sélectionner les éléments à synchroniser ++Attributs du répertoire de l'objet du certificat ++Accédez à vos imprimantes et partagez-les en ligne via . ++&Ajouter... ++Afficher dans cette langue ++il y a  jour ++Police Sans-Serif ++Ne rien faire ++ seconde ++Configurer les mises à jour automatiques pour tous les utilisateurs ++Échec de la création du répertoire des données ++Fermer et annuler le chargement ++ ++Adresse : ++Détails ++Notification : ++Cette opération peut prendre quelques minutes. ++Géré par () ++Type de certificat Netscape ++Impossible d'afficher certaines parties de ce document PDF. Souhaitez-vous installer Adobe Reader ? ++Vos certificats ++Vos données personnelles sur , et ++URL de stratégie de l'autorité de certification Netscape ++Dernier accès : ++Synchroniser les mots de passe ++&Quitter ++&Fermer l'onglet ++, ++Le site Web à l'adresse contient des éléments provenant de sites qui semblent héberger des logiciels malveillants. Ces derniers peuvent nuire à votre ordinateur ou agir à votre insu. Le simple fait de visiter un site hébergeant ce type de logiciels peut infecter votre ordinateur. ++Total : ++Les cookies de plusieurs sites ont été autorisés pour la session uniquement. ++Nom du service : ++Imprimer une page de test ++Aperçu avant impression - ++ ++ ne peut pas à afficher la page Web, car votre ordinateur n'est pas connecté à Internet. ++Exécuter cette fois ++Chiffrement de la clé ++Échec de la vérification AAA ++Ouverture dans ... ++&Copier ++Logiciel ++Moteurs de recherche ++&Méthodes d'entrée ++Jamais enregistrés ++Impossible d'analyser le fichier. ++Subordination qualifiée Microsoft ++Bureau ++Toujours traduire en les pages en ++Thaï ++Activer l'onglet suivant ++: de chargement ++Style de mappage du clavier ++Un problème lié à votre microphone s'est produit. ++ vous permet d'accéder aux imprimantes de cet ordinateur, où que vous soyez. Connectez-vous pour l'activer. ++District ++Ethernet ++Erreur de réseau inconnue. ++Nom du certificat ++Plus d'informations ++Mise à jour du système disponible. Préparation du téléchargement… ++Galerie des thèmes Google Chrome ++Copi&er l'adresse e-mail ++Activer l'onglet 3 ++Adresses ++Plug-in : () ++Pas maintenant ++Pays ++<Ne fait pas partie du certificat> ++il y a  seconde ++Fichiers image ++Europe centrale ++Certificat client SSL ++Pour accélérer l'affichage des pages Web, ++ ++ enregistre temporairement les fichiers téléchargés sur le disque. Si ++ ++ ne s'arrête pas correctement, ces fichiers peuvent être endommagés, ce qui ++ génère cette erreur. L'actualisation de la page devrait permettre de résoudre ++ ce problème ; celui-ci ne se reproduira vraisemblablement plus si l'arrêt s'effectue ++ correctement. ++ ++ Si le problème persiste, essayez de supprimer le contenu du cache. Cette ++ erreur peut aussi indiquer que le matériel est sur le point de tomber ++ en panne. ++Thème créé par ++Données de navigation ++Ajouter cette page aux favoris ++Le serveur a refusé la connexion. ++Module ( bits) :\n\n\nExposant public ( bits) :\n ++ secondes restantes ++Vous utilisez un indicateur de ligne de commande non pris en charge : . La stabilité et la sécurité en seront affectées. ++Emplacement de téléchargement ++À propos de Google Traduction ++Les lettres ne sont pas sensibles à la casse. ++Mot clé ++Connexion ++Redémarrez pour appliquer la mise à jour. ++Sélectionner un carré dans l'image ++Bases de données Web ++Codage ++Mise en route ++Utiliser les pages actuelles ++Signaler une erreur ++Recherche de réseaux en cours ++Effacer les données de navigation ++Ouvrir le lien dans une nouvelle &fenêtre ++Nom d'utilisateur ++Clavier letton ++Forcer l'actualisation de cette page ++Disposition du clavier : ++Non utilisé ++ minutes ++Chiffrement RSA PKCS #1 ++Ce n'est probablement pas le site que vous recherchez ! ++&Général ++Configurer la synchronisation ++État de connexion : ++Ancien code PIN : ++Désactiver le contrôle des liens hypertexte ++&Modifier ++Chinois ++Navigateur par défaut ++Extension en mode navigation privée : ++Mot clé : ++Un problème est survenu lors du téléchargement de l'image de récupération. La connexion réseau a été perdue. ++Votre administrateur a désactivé certaines préférences. ++Forfait de données épuisé ++Veuillez indiquer à quel niveau vous rencontrez des problèmes avant d'envoyer vos commentaires. ++Authentification du serveur WWW TLS ++Le service de synchronisation n'est pas disponible pour votre domaine. ++Modifier les paramètres du proxy... ++Cette fonctionnalité active les API des extensions expérimentales. Notez que vous ne pouvez pas mettre en ligne des extensions qui font appel aux API expérimentales dans la galerie d'extensions. ++Un logiciel malveillant a été détecté ! ++Forfait de données presque épuisé ++des dernières 24 heures ++Une fois activée, la recherche instantanée charge la plupart des pages Web dès que vous saisissez l'URL dans le champ polyvalent, avant même que vous n'appuyiez sur Entrée. Si votre moteur de recherche par défaut est compatible, toute lettre saisie dans ce champ offre de nouveaux résultats et les prédictions intégrées vous guident dans vos recherches.\n\nChaque touche utilisée fait l'objet d'une requête, par conséquent il se peut que les éléments saisies dans le champ polyvalent soient enregistrés par votre moteur de recherche par défaut.\n ++ hours left ++poursuivre quand même ++Autorisé ++Retirer l'onglet ++Moins de ++Impossible de charger l'icône "" d'action du navigateur. ++Consulter Google Dashboard ++Plus d'informations ++Ajoutez des langues puis faites-les glisser pour les classer dans l'ordre souhaité. ++ sera lancé au démarrage du système et continuera de s'exécuter en arrière-plan, même toutes les fenêtres de sont fermées. ++Non (HttpOnly) ++Saisir votre mot de passe multiterme pour la synchronisation ++Police standard ++ (par défaut) ++Cette fonctionnalité active la prise en charge du client natif. ++La puce du module de plate-forme sécurisée (TPM) est désactivée ou inexistante. ++L'index de l'onglet indiqué est incorrect. ++Nom du serveur SSL du certificat Netscape ++Est une autorité de certification ++Wi-Fi ++Connexion à ++Confirmer le mot de passe : ++Aperçu avant impression ++Clavier italien ++Impossible d'établir une connexion sécurisée à cause de l'antivirus ESET. ++(expiré) ++Voulez-vous vraiment quitter cette page ? ++Faire défiler d'une page vers le haut ++Empreintes ++Le plus récent ++ heures ++Agrandir ++La page Web est introuvable dans le cache. Certaines ressources ne sont restituées fidèlement que si elles sont extraites du cache, notamment les pages générées à partir de données que vous avez envoyées. Cette erreur peut également être due à un cache endommagé lors d'une fermeture incorrecte. Si le problème persiste, essayez d'effacer le cache. ++Le plug-in n'est plus à jour. ++Vous avez changé de position. Souhaitez-vous utiliser  ? ++EAP-TLS ++ heures ++Rafraîchir cette page ++Non-répudiation ++Extension : ++Active l'API Web audio. ++Zone de saisie de mot de passe ++Effacer les cookies et autres données de site lorsque je quitte le navigateur ++Ajouter l'option de regroupement au menu contextuel des onglets ++Version ++Latin ++Le connecteur requiert l'installation du pack Microsoft XML Paper Specification Essentials. ++Effacer les cookies et autres données de site lorsque je ferme le navigateur ++Case décochée ++Mise en page ++Saisir un nom ou une adresse ++Choix de l'image du compte ++Me montrer ++ minutes restantes ++De : ++Ouvrir un rapport de phishing ++Page de phishing ++Inspecter le pop-up ++Importer... ++Modifier la carte de paiement ++Cette langue est utilisée pour corriger l'orthographe. ++Le type d'enregistrement indiqué est incorrect. ++Forfait de données arrivé à expiration ++Exporter mes favoris... ++Clavier britannique ++Importer des favoris... ++ ++Nom d'utilisateur ou mot de passe incorrect ++&Tout sélectionner ++Erreur inconnue liée au certificat du serveur. ++Envoyer une capture d'écran enregistrée ++Émis pour : ++Page précédente ++Hsu ++Réduire ++Navigateur par défaut ++Afficher le mot de passe ++Activer les fonctionnalités d'accessibilité ++Inclure la capture d'écran actuelle : ++ - ++(cette extension est gérée et ne peut être désinstallée ni désactivée) ++OID enregistré ++Importés depuis IE ++Fichier de clé privée (facultatif) : ++Autoriser pour la session uniquement ++ mins ++Mise à jour en cours ++Aucun microphone trouvé. ++Connexion à ++ n'est pas votre navigateur par défaut. ++Forfait ++Cette page contient des éléments des sites ci-dessous qui suivent votre position géographique : ++Plusieurs profils ++Plantages ++Par défaut ++ jours ++PKCS #1 MD4 avec chiffrement RSA ++Modifier le moteur de recherche ++ minutes ++Indiquez le mot de passe approprié ci-dessus, puis saisissez les caractères figurant dans l'image ci-dessous. ++Expiration de imminente ++Activer l'onglet précédent ++Désactiver l'accès à distance ++Afficher les incompatibilités ++Carte de débit Solo ++Actualisez cette page Web ultérieurement. ++Pour utiliser cette extension, saisissez "", TAB, puis votre commande ou votre recherche. ++ synchronisera les applications installées, afin que vous puissiez y accéder en vous connectant depuis tout navigateur . ++Langues et paramètres du correcteur orthographique... ++Erreur de sécurité ++Applications ++La ressource demandée n'existe plus et aucune adresse de transfert n'est disponible. Il semble que cet état de fait soit permanent. ++Certificat unique binaire codé DER ++&Plein écran ++Fichiers vidéo ++ indique que ++ NetNanny intercepte les connexions sécurisées. En général, cela ++ ne constitue pas un problème de sécurité, car le logiciel NetNanny s'exécute souvent ++ sur le même ordinateur. Toutefois, en raison de certaines incompatibilités avec ++ les connexions sécurisées Google Chrome, vous devez configurer NetNanny ++ de manière à éviter ces interceptions. Cliquez sur le lien En savoir plus pour obtenir des instructions. ++Vos onglets et activités de navigation ++Créer ++Turc ++Une erreur s'est produite lors de la tentative d'enregistrement du certificat client. Erreur  () ++Bienvenue dans ++Sélectionner ++Nom du modèle de certificat Microsoft ++Configuration de l'adresse IP pour ++Immortalisez votre plus beau sourire et utilisez la photo comme image de compte. ++Extension créée : ++ ++ ++Mot de passe incorrect. Veuillez réessayer. ++LEAP ++Échec de la connexion aux serveurs de reconnaissance vocale. ++Très grande ++Sélectionner le répertoire de l'extension ++&Téléchargements ++Gestionnaire des certificats ++ souhaite suivre votre position géographique ++Quitter ++ sur ++Proposer d'enregistrer les mots de passe ++Modification de l'affiliation ++par exemple : 1-5, 8, 11-13 ++(Activé par une stratégie d'entreprise) ++Qu'est-ce que c'est ? ++Les cookies de plusieurs sites ont été bloqués. ++Serveur DNS spécifié par l'utilisateur et utilisé par Google Chrome, à la place du paramètre système par défaut, pour les résolutions DNS. ++Désactivé ++Annuler ++Répertoire racine de l'extension : ++Mode de saisie du vietnamien (TCVN6064) ++Échec de l'activation ++Ajouter cette page aux favoris ++L'identité de ce site Web a été vérifiée par . ++Adresse e-mail : ++Activation... ++PAP ++Sites de phishing ++ secs ago ++Interdire à tous les sites d'exécuter JavaScript ++Vouliez-vous accéder à  ? ++La connexion avec le service de configuration a été perdue. Veuillez réinitialiser votre périphérique ou contacter votre représentant de l'assistance technique. ++Paramètres des fenêtres pop-up : ++Tout exporter... ++Barre de favoris ++Stocké dans : ++Développer... ++Gin Yieh ++Rechercher sur ++Modifier la carte de paiement ++Au démarrage ++Nous examinons actuellement le problème. ++Notifications ++Navigateur ++Case d'option décochée ++ days ++Anglais ++Modifier le nom du dossier ++Grammaire et orthographe ++Réseaux privés ++Toutes sortes de connexions ++Exceptions liées aux notifications ++Épingler les onglets ++Barre d'onglets ++Activer l'onglet 6 ++Gestionnaire de &tâches ++Paramètres de stockage d'Adobe Flash Player... ++Connexion au réseau ++Mode de saisie du vietnamien (VNI) ++L'application suivante va être lancée si vous acceptez cette requête :\n\n ++Importation... ++N° de carte ++Gérer les moteurs de recherche... ++Utiliser un moniteur externe ++Gravure de l'image en cours... ++État ++Éteindre ++Enregistrer les fichiers dans le dossier : ++Fermer les autres onglets ++Répertoire de fichiers ++Masquer les autres ++Annuler l'épinglage des onglets ++Plus ++Échec de la vérification de la révocation ++Ajouter www. et .com, puis ouvrir la page ++Pour inspecter un pop-up, cliquez avec le bouton droit sur la page ou sur l'icône d'action du navigateur, puis sélectionnez Inspecter le pop-up. ++&Répéter ++ est à présent activé. a enregistré les imprimantes installées sur cette machine en les associant à <b></b>. Vous pouvez désormais utiliser vos imprimantes depuis n'importe quelle application Web ou mobile associée à . ++Le serveur de ++ est introuvable, car la résolution DNS a échoué. DNS est le service Web qui ++ traduit les noms de site Web en adresses Internet. Cette erreur est ++ généralement due à l'absence de connexion Internet ou à une configuration ++ incorrecte du réseau. Cela peut également venir d'un serveur DNS qui ne ++ répond pas ou d'un pare-feu interdisant l'accès de ++ ++ au réseau. ++ZGPY ++Impossible de charger le fichier css "" du script de contenu. ++Créer des raccourcis vers des applications aux emplacements suivants : ++Moyenne ++Envoyé pour : ++Aider Google à détecter les logiciels malveillants en envoyant des données supplémentaires concernant les sites pour lesquels cet avertissement s'affiche. Ces données seront gérées conformément aux règles définies sur la page . ++[répertoire parent] ++Touches de sélection du clavier Hsu ++Copie de l'image de récupération... ++Tout supprimer ++Seule une personne en possession de votre mot de passe multiterme peut lire vos données chiffrées. Google ne reçoit ni n'enregistre votre mot de passe multiterme. Si vous oubliez votre mot de passe multiterme, vous devrez réinitialiser la synchronisation. ++Ouvrir dans une nouvelle fenêtre ++Dommage... Aucune extension n'est installée. :-( ++Style de ponctuation ++Historique de navigation ++Ce site tente de télécharger plusieurs fichiers. Voulez-vous autoriser le chargement ? ++Établissement de la liaison avec le service de gestion des périphériques en attente... ++ heures ++Ne pas utiliser les paramètres du proxy pour les hôtes et domaines suivants : ++&Avancer ++Impossible de charger "" pour le plug-in. ++À propos du système ++Utilisation de la clé du certificat : ++Mode de saisie du chinois (quick) ++Une erreur s'est produite lors de la tentative d'écriture du fichier : . ++Renommer ++La synchronisation requiert votre attention. ++Aujourd'hui ++Imp&rimer le cadre... ++Le site a déjà été informé qu'un logiciel malveillant a été détecté sur ses pages. Pour plus d'informations concernant les problèmes rencontrés sur , consultez notre Google. ++Adresse de serveur DNS spécifiée par l'utilisateur. ++&Rechercher... ++, ++&Afficher dans le dossier ++Non connecté à Internet. ++Sélectionnez ++ ++ Démarrer > Panneau de configuration > Connexions réseau > Assistant Nouvelle connexion ++ ++ pour tester votre connexion. ++Cette icône s'affiche lorsque l'extension peut agir sur la page active. ++Reconnexion ++Réponses OCSP de signature ++Erreur d'importation de l'autorité de certification ++Gravure de l'image terminée. ++&Historique ++Installer ++Ajouter des utilisateurs ++Enregistrer l'authentification et le mot de passe ++Clavier norvégien ++Basculer en mode chinois/anglais ++Traduction de la page en ... ++À propos de & ++ onglets ++il y a  minutes ++Qu'est-ce que c'est ? ++Tout &sélectionner ++&Ajouter au dictionnaire ++Utilisation étendue de la clé ++Le chinois est la langue de saisie initiale ++Agent utilisateur ++Émetteurs de l'autorité de certification : ++ jours ++Code source ++Redémarrer maintenant ++La largeur de caractères initiale est Complète ++Pour masquer l'accès à ce programme, vous devez le désinstaller au moyen de \n du Panneau de configuration.\n\nSouhaitez-vous exécuter  ? ++Paramètres du microphone ++Port ++&Toujours ouvrir les fichiers de ce type ++Uniquement les connexions sécurisées ++Les informations de connexion au compte sont obsolètes. ++La traduction a échoué, car la page est déjà en . ++Sandbox SUID ++(vide) ++Échec de l'authentification basée sur le certificat ++Envoyer le code source de la page actuelle ++Votre administrateur a désactivé certains paramètres. ++Coréen ++Avertissement : Il s'agit peut-être d'un site de phishing ! ++Dvorak ++Étendue de pages incorrecte ++ heures restantes ++Exceptions liées aux cookies et aux données de site ++ n'est pas accessible ++P&lus grand ++Connecté à ++Le certificat de sécurité du site a été révoqué ! ++Désactiver ++ risque de ne pas rester à jour. ++intégré sur tout autre site ++ ++ ne parvient pas à atteindre le site Web. Cela vient probablement d'un problème de réseau, ++ mais peut également être dû à un pare-feu ou à un serveur proxy mal configuré. ++À propos de la reconnaissance vocale ++Langues et paramètres du correcteur orthographique... ++ seconde restante ++Nom d'utilisateur : ++Le stockage des cookies n'est pas autorisé pour cette page. ++JavaScript ++La connexion utilise . ++Échec de l'installation ++Afficher les &infos sur la page ++Serveurs ++Système de fichiers de chiffrement Microsoft ++Un plug-in supplémentaire est requis pour afficher certains éléments sur cette page. ++Appuyez sur Ctrl+Alt+/ ou sur Échap pour masquer ++Cette fonctionnalité effectue des vérifications en arrière-plan et vous avertit en cas d'incompatibilité logicielle (modules tiers bloquant le navigateur, par exemple). ++Connexion avec ++Imprimer depuis la boîte de dialogue système… ++ heure restante ++Échec de l'initialisation de l'appareil photo ++Importés ++Type de fournisseur : ++IP restreinte : ++Refuser ++Démarrage du téléchargement en cours... ++Une nouvelle version de est disponible. ++Clavier hébreu ++Police à largeur fixe ++Safari ++Les champs obligatoires ne doivent pas rester vides. ++Ouvrir une fois le téléchargement &terminé ++Stratégies de certificat ++Pavé tactile ++Aucun ++Activer la barre d'adresse en mode recherche ++Exceptions pour JavaScript ++Ouvrir dans une nouvelle fenêtre ++Veuillez saisir le code PIN. ++Options de saisie automatique... ++Arabe ++Nouveau dossier ++E/S réseau interrompue ++Rechercher le précédent ++Ne jamais enregistrer les mots de passe ++Ouvrir dans un nouvel onglet ++Fenêtre suivante ++&Rechercher le suivant ++JCB ++Signature de liste d'approbation Microsoft ++Gérer les certificats... ++Sélectionnez le fichier de certificat. ++Fabricant : ++Bloquer le contenu inapproprié ++Le fichier contenait plusieurs certificats, dont certains n'ont pas été importés : ++Exceptions pour les images ++Autoriser tous les sites à afficher des fenêtres pop-up ++Vous devez indiquer un chemin valide comme valeur de clé privée. ++Sans mot de passe multiterme, vos mots de passe et autres données chiffrées ne seront pas synchronisés sur cet ordinateur. ++Extensions ou applications ++Ce site recommande Google Chrome Frame (déjà installé). ++Les plus visités ++Vous n'êtes pas autorisé à vous connecter. Consultez le propriétaire de cet ordinateur portable. ++Remarque : Lorsque vous cliquez sur "Envoyer", Google Chrome joint à votre ++ envoi un journal indiquant votre version de Google Chrome et celle du système ++ d'exploitation utilisé, ainsi que l'URL associée à votre rapport. Vous pouvez ++ également joindre une capture d'écran. Ces informations nous ++ permettent de diagnostiquer les problèmes et d'améliorer les performances de ++ Google Chrome. Les informations personnelles fournies sciemment dans vos ++ commentaires ou involontairement dans le journal, l'URL ou la capture ++ d'écran sont protégées conformément à nos règles de ++ confidentialité. Si vous ne souhaitez pas indiquer d'URL et/ou de capture ++ d'écran, décochez les cases "Inclure cette URL" et/ou "Inclure cette capture d'écran". Vous acceptez que Google utilise vos commentaires pour améliorer ses produits ou services. ++Vos modifications seront prises en compte au prochain démarrage de . ++Taille de police minimale ++Entrée directe ++Fermer la fenêtre ++Mode de saisie du japonais (pour clavier japonais) ++Inscription réussie ++Échec de création du fichier zip temporaire lors de la création du pack ++Modifier les paramètres de confiance : ++Votre historique de navigation ++&Masquer le panneau de la vérification orthographique ++Plug-in ne répondant pas ++IBM ++Les paramètres seront effacés lors de la prochaine actualisation. ++ introuvable ++Démarrage... ++Nouvelle fenêtre de nav&igation privée ++Ajouter une adresse postale... ++Authentification en cours... ++Ouvrir dans un nouvel onglet ++Déconnecté ++Action du navigateur ++Le mot de passe multiterme saisi ne peut pas être utilisé, car vous avez déjà chiffré des données avec un mot de passe multiterme. Entrez ci-dessous le mot de passe multiterme actuellement défini pour la synchronisation. ++Ouvrir cette page : ++Voulez-vous vraiment supprimer tous les mots de passe ? ++Sélectionner par domaine ++Ouvrir le lien dans une fenêtre en navi&gation privée ++Émetteur ++Options de saisie automatique ++Les nouveaux paramètres des cookies seront appliqués quand vous aurez actualisé la page. ++Votre connexion à est sécurisée par un chiffrement bits. ++Menu Applications ++Outi&ls ++Onglets latéraux ++Reprendre ++Zoom ++Inspecteur de DOM ++Document sans titre ++Police standard ++Activer ++Opération en cours... ++C&opier l'URL de l'image ++La saisie automatique des numéros de carte de paiement est désactivée, car la connexion utilisée par ce formulaire n'est pas sécurisée. ++Enregistrer le &cadre sous... ++Général ++Défaillance ++Demander ++Coller l'URL et y a&ccéder ++Pour plus de sécurité, va chiffrer vos mots de passe. ++Si vous avez oublié votre mot de passe multiterme, vous devrez arrêter la synchronisation via Google Dashboard. ++ sur  ++Adresse ligne 1 ++Impossible de créer le favori. ++Basculer en mode chinois simplifié/traditionnel ++Votre système Sandbox n'est pas correctement configuré. ++Sélectionnez le menu clé à molette > Préférences > Options avancées > Modifier les paramètres du proxy et vérifiez que vos paramètres sont définis sur "sans proxy" ou "direct". ++Impossible de vérifier si le certificat a été révoqué. ++Stockage des données ++/, Interrompu ++Acheter un forfait ++Installer le plug-in... ++Afficher le code source ++Fermer les onglets sur la droite ++Afficher le bouton "Accueil" ++Version  ++Parenthèse gche ++Microsoft Server Gated Cryptography ++Zoom avant ++Protection du courrier électronique ++Les cookies suivants ont été bloqués (tous les cookies tiers sont bloqués, sans exception) : ++Connectez-vous à pour importer le certificat client de ++La batterie est chargée. ++Créer un nouveau profil... ++Maintenez la touche enfoncée pour quitter. ++Masquer ce plug-in ++Ouvrir le fichier ++Conteneur de barres d'infos ++Le certificat du serveur a expiré. ++Utiliser ++Réduit la taille du texte ++Épingler l'onglet ++Mise à jour du système ++ days left ++Inclure les informations système ++Google Chrome n'avait pas suffisamment de mémoire ou le processus de la page Web a été arrêté pour une autre raison. Pour continuer, actualisez la page ou ouvrez-en une autre. ++Impossible de valider votre mot de passe sur le réseau actuel. Sélectionnez un autre réseau. ++Cette page n'est pas rédigée en  ? Signaler l'erreur ++Certificat unique codé Base 64 ASCII ++Activer le mode plein écran ++Codag&e ++ est déjà utilisé pour gérer les liens ://. ++Touches de sélection ++Clavier international américain ++Je comprends que la visite de ce site peut être préjudiciable à mon ordinateur. ++Ressource cache manquante. ++Impossible d'accéder à mon compte ++C&opier l'URL de la vidéo ++Vous préférez parcourir la galerie ? ++Impossible de vérifier le certificat du serveur. ++Outils de &développement ++Exporter... ++Paramètres de saisie automatique ++Téléchargement de l'image en cours... ++&Options du vérificateur d'orthographe ++Impossible d'ouvrir votre profil correctement.\n\nIl est possible que certaines fonctionnalités ne soient pas disponibles. Vérifiez que ce profil existe et que vous disposez d'une autorisation d'accès à son contenu en lecture et en écriture. ++Vérifier le document maintenant ++Zone de liste ++Clavier slovène ++Sens de l'écriture ++Vos données sur ++Ouvrir une fenêtre du navigateur ++Conversion de la date et de l'heure ++PKCS #1 SHA-512 avec chiffrement RSA ++Clavier coréen ++Dupliquer ++Ne pas conserver sur cette page ++Désactiver ++ATOK ++téléchargement ++E-mail : ++Ouvrir tous les favoris dans une nouvelle &fenêtre ++Rafraîchir la page actuelle ++Accessibilité ++Exceptions pour les plug-ins ++Remplissage automatique des formulaires ++Nom d'utilisateur ++Enregistrer le lie&n sous... ++Réessayer ++Personnaliser et configurer ++Préférences de saisie automatique ++Votre position géographique ++Afficher les pages en arrière-plan () ++Configurer les mises à jour automatiques ++il y a  heures ++Valeur du champ ++Les dernières versions d'Unity et GNOME (ainsi que la prochaine version d'Ubuntu, Natty Narwhal) affichent une barre de menus de type OSX sur toute la largeur supérieure de l'écran. ++Index erroné. ++Préparation du module de plate-forme sécurisée (TPM) en cours. Veuillez patienter, l'opération peut prendre quelques minutes. ++Nombre de copies incorrect ++Personnaliser ++Prédire les actions du réseau pour améliorer les performances de chargement des pages ++Données restantes : ++N'est pas une autorité de certification. ++L'URL doit être valide. ++Envoyer automatiquement les statistiques d'utilisation et les rapports d'erreur à Google ++Cette fonctionnalité active la géolocalisation dans les extensions expérimentales. Cela implique l'utilisation des API de localisation du système d'exploitation (si disponibles) et l'envoi de données sur la configuration réseau locale au service de localisation de Google afin de déterminer une position précise. ++Impossible de charger le profil. ++Toujours exécuter JavaScript sur ++Version PRL : ++Confirmer la réactivation ++Ajouter une adresse postale... ++PKCS #1 MD2 avec chiffrement RSA ++Dim.^Lun.^Mar.^Mer.^Jeu.^Ven.^Sam. ++Zone de saisie ++Trier par nom ++Fenêtre ++Nouvel onglet ++Vous tentez d'accéder au site , mais le certificat présenté par le serveur a été révoqué par son émetteur. Cela signifie que les informations d'identification présentées par le serveur ne sont pas approuvées. Vous communiquez peut-être avec un pirate informatique. Nous vous déconseillons vivement de continuer. ++Composition hors écran ++ mins left ++Technologie : ++Accédez à la page d'accueil du site : ++Configurer la communication à distance ++L'émetteur d'un certificat n'ayant pas expiré est tenu d'assurer la maintenance de ce qui s'appelle "une liste de révocation". Si un certificat est compromis, l'émetteur peut le révoquer en l'ajoutant à la liste de révocation. Ce certificat n'est alors plus approuvé par votre navigateur. Il n'est pas nécessaire d'assurer la maintenance de l'état "révoqué" des certificats expirés. Donc, bien qu'un certificat ait été qualifié de valide pour le site Web que vous visitez actuellement, il est impossible de déterminer s'il a été, depuis, compromis puis révoqué ou s'il est toujours valide. Par conséquent, il n'est pas possible de s'assurer si vous communiquez avec un site Web légitime ou si le certificat a été compromis et se trouve maintenant en la possession d'un pirate informatique avec lequel vous communiquez. Ne poursuivez pas. ++Néanmoins, si vous travaillez dans une entreprise qui génère ses propres certificats, et que vous essayez de vous connecter au site Web interne de l'entreprise avec un certificat de ce type, vous pouvez résoudre ce problème en toute sécurité. Pour ce faire, importez le certificat racine de l'entreprise en tant que "certificat racine". Par la suite, les certificats émis ou vérifiés par votre entreprise seront approuvés et vous ne verrez plus cette erreur lorsque vous tenterez de vous connecter à nouveau au site Web interne. Contactez le support informatique de votre entreprise pour savoir comment ajouter un nouveau certificat racine sur votre ordinateur. ++Définir en tant que navigateur par défaut ++Avertissement ++Préférences de recherche ++Clavier Colemak américain ++Activer la navigation en tant qu'invité ++Utiliser les paramètres par défaut ++Rétablir ++Désinstaller "" ? ++Établissement de la connexion sécurisée... ++Dossier : ++Erreur non reconnue ++Consultez les conflits connus avec des modules tiers. ++Co&ller et rechercher ++&Remonter ++Échec de la traduction en raison d'une erreur de serveur ++Version : ++Polices et codage ++ - ++Signature du code commercial Microsoft ++Sélectionnez les éléments à importer : ++De gauche à droite ++Votre connexion à est sécurisée par le biais d'un faible chiffrement. ++sans objet ++Toujours afficher la barre de favoris ++Activer l'onglet 2 ++Aperçu des onglets ++Redémarrer ++Configuration en cours... ++Une erreur s'est produite lors de la récupération des fonctions de l'imprimante . Cette imprimante n'a pas pu être enregistrée dans . ++Exceptions pour les fenêtres pop-up ++Signataire du certificat ++La page Web n'existe plus. ++Vous n'avez jamais visité ce site auparavant. ++Personnaliser... ++Fe&rmer la fenêtre ++Arrêter le chargement de cette page ++Autres favoris ++ a été mis à jour. ++Mode hors connexion ++Erreur d'importation de fichier PKCS #12 ++Algorithme de clé publique de l'objet ++Le site Web a rencontré une erreur lors de l'extraction de . ++ Cela peut être dû à une opération de maintenance ou à une configuration incorrecte. ++Échec du chargement de la page ++Mot de passe : ++Conserver en tant que moteur de recherche par défaut ++Fichier manifeste absent ou illisible ++La connexion a été réinitialisée. ++Le mot de passe choisi vous sera demandé pour restaurer le fichier. Veillez à le conserver en lieu sûr. ++La vérification de la provenance du certificat DNS est activée, ce qui peut entraîner l'envoi d'informations privées à Google. ++À propos de la reconnaissance vocale ++Aller à la sélection ++Ajouter un certificat ++Espaces de noms PID ++Préférences de saisie automatique ++Activer l'onglet 8 ++Le certificat "" représente une autorité de certification. ++Envoyer par e-mail l'emplacement de la page ++Enregistrement des informations de date Microsoft ++Validité ++&Traduire en ++Batterie :  % ++Désactivé ++Japonais ++ () ++L'application est actuellement inaccessible. ++Lecteur du certificat : ++ jour restant ++Gestionnaire de tâches ++Gérer les extensions... ++Continuer ++Synchronisation avec effectuée. Dernière synchronisation : ++Le certificat de sécurité du site n'est pas encore valide ! ++Ouverture de session par carte à puce Microsoft ++Format ++Tapez votre requête ou saisissez une URL pour commencer la navigation : c'est à vous de choisir. ++Enregistrer &sous... ++Le serveur requiert un nom d'utilisateur et un mot de passe. ++Supprimer tous les mots de passe ++Le certificat du serveur contient des erreurs. ++Recherche de réseaux Wi-Fi... ++Description : ++Séparateur ++Si vous supprimez l'un de vos propres certificats, vous ne pouvez plus l'utiliser pour vous identifier. ++Rafraîchir cette page ++État d'activation : ++Créer des raccourcis vers des applications ++Clavier franco-suisse ++GUID de domaine Microsoft ++Entrer ++Supprimer ++Échec de l'enregistrement de cet ordinateur pour l'accès à distance. ++Ouvrir l'&image dans un nouvel onglet ++Préférences... ++L'administrateur a désactivé les mises à jour. ++À propos de la version ++Veuillez nous indiquer ce qu'il se passe avant d'envoyer votre rapport. ++Connectez-vous à afin de générer une clé pour . ++Clavier roumain ++Autres ++Sécurité : ++Imprimer ++Mode de saisie standard ++Signature ++Erreur lors de la connexion ++Pour cette session uniquement ++Une erreur s'est produite. ++(Désactivé par une stratégie d'entreprise) ++Erreur lors de la tentative d'impression. Vérifiez votre imprimante et réessayez. ++Grec ++Ignorer les exceptions et bloquer l'enregistrement des cookies tiers ++Cet outil vous permet de sélectionner une capture d'écran enregistrée. Aucune capture d'écran n'est disponible pour le moment. Appuyez simultanément sur Ctrl et sur la touche "Mode Présentation" pour enregistrer une capture d'écran. Vos trois dernières captures apparaissent ici. ++Activation effectuée ++Aucun système de révocation trouvé ++Bouton ++Interrompu ++Dictionnaire de symboles ++Technologie EvDo requise ++Internet mobile ++Envoyer le commentaire ++Associé au profil Chrome . Dernière synchronisation : ++Carte de crédit (autre) ++Langues et saisie ++Utiliser la barre de titre et les bordures de fenêtre du système ++Ann&uler ++ () ++Le serveur a refusé d'exécuter la demande. ++ Ko ++ a été mis à jour vers la version . ++Navigateur de contenu ++&Rouvrir la fenêtre fermée ++Se connecter directement à Internet ++Émis pour ++Ouverture de en cours ++Cibles disponibles pour l'image ++Signaler un problème ++Taille de police : ++Aide pour la configuration de proxy ++Petite ++ hours ago ++Rester sur cette page ++Type de bug : ++Inclure cette URL : ++Cookies et données de site... ++Police Serif ++Avertissement : ne peut pas empêcher les extensions d'enregistrer votre historique de navigation. Pour désactiver cette extension en mode navigation privée, désélectionnez-la. ++ChromiumOs Image Burn ++Services ++Paramètres du proxy... ++1 onglet ++Vous naviguez en tant qu'invité. Les pages que vous consultez dans cette fenêtre n'apparaîtront pas dans l'historique de votre navigateur ni dans votre historique des recherches. Les autres traces telles que les cookies seront supprimées de l'ordinateur à la fin de votre session. En revanche, les fichiers téléchargés et les favoris créés seront conservés. ++ ++ En savoir plus sur le mode invité ++Chargement des pages impossible ++Inclure cette capture d'écran : ++Certificat ++&Effacer les données de navigation... ++Valeur de signature du certificat ++URL de renouvellement du certificat Netscape ++Afficher la s&ource ++ - , ++Reprendre ++ secs ago ++Activé ++Carte SIM désactivée ++Compatibilité avec VPN ++Développement - Instable ++Échec de création du raccourci vers l'application ++Barre de favoris ++Le serveur est en mesure de répondre à la demande. ++Modifier les paramètres du proxy... ++(non empaquetée) ++Rechercher le suivant ++Paramètres réseau ++Votre service Internet mobile est activé et prêt à l'emploi. ++Modifier la police et la langue par défaut des pages Web ++Composition graphique avec accélération matérielle ++Autre nom de l'émetteur du certificat ++ ++&Afficher le code source du cadre ++Mode de saisie du persan (clavier ISIRI 2901) ++OpenVPN ++Arrêter le processus ++Votre compte a peut-être été supprimé ou désactivé. Veuillez vous déconnecter. ++Authentification anonyme : ++Bases de données indexées ++En savoir plus sur les escroqueries par phishing ++Page à l'apparence anormale ++Adresse e-mail ou mot de passe incorrect. Essayez tout d'abord de vous connecter à un réseau. ++Périphérique ++Informations sur la connexion ++Confirmer la navigation ++Nom du point d'accès : ++Rechercher ++Au démarrage ++Paramètres... ++Lire en un clic ++Connectez-vous à pour vous authentifier auprès de avec votre certificat. ++Votre administrateur informatique a désactivé certaines options. ++Supprimer le certificat de serveur ""? ++Configurer la synchronisation... ++Valider automatiquement une chaîne ++Empreinte SHA-256 ++Retour ++Réseau domestique, sans itinérance ++ - ++Gérer les mots de passe enregistrés... ++Sélectionnez ++ ++ Menu clé à molette > Options > Options avancées > Modifier les paramètres du proxy > Paramètres réseau ++ ++ et désélectionnez l'option "Utiliser un serveur proxy pour votre réseau local". ++Ne jamais traduire ce site ++(suite) ++Trop de redirections ++Ces paramètres ne peuvent être modifiés que par le propriétaire : ++Active la protection XSS Auditor de WebKit (protection contre le Cross-site Scripting), une fonctionnalité qui vous protège de certaines attaques de sites malveillants et offre une sécurité accrue, mais qui n'est pas compatible avec tous les sites Web. ++Clavier latino-américain ++Phishing détecté ! ++Voulez-vous utiliser () pour gérer les liens :// à partir de maintenant ? ++ (Navigation privée) ++Prendre une photo ++Non merci ++Ne pas afficher les images ++Toujours autoriser ces plug-ins sur ++Sélectionner un dossier ++&Paramètres ++Informations sur l'erreur : ++Toujours autoriser les plug-ins sur ++Effacer les données de saisie automatique enregistrées ++Changer de moteur de recherche ++En attente du tunnel proxy... ++Veuillez ajouter un autre mode de saisie avant de supprimer celui-ci. ++ secondes ++Paramètres de contenu ++Impossible d'extraire les fichiers de l'extension. Pour effectuer cette opération en toute sécurité, vous devez disposer d'un chemin d'accès à votre répertoire de profils commençant par une lettre de lecteur et ne contenant ni jonction, ni point de montage, ni lien symbolique. Aucun chemin de ce type n'existe pour votre profil. ++ va être installé. ++Code postal ++En bas à droite ++&Ouvrir ++ téléchargé(s) sur ++Commentaires d'ordre général/Autres ++Ou&vrir la vidéo dans un nouvel onglet ++Identité : ++Échec de l'opération OTASP ++Action sur la page ++Modifier des éléments... ++Le répertoire d'extensions est obligatoire. ++ Mo disponibles ++Ancien ++ fournit du contenu provenant de , un site connu pour distribuer des logiciels malveillants. Votre ordinateur pourrait être infecté par un virus si vous consultez ce site. ++Ces fonctionnalités expérimentales sont susceptibles d'être modifiées, interrompues ou supprimées à tout moment. Nous ne fournissons aucune garantie quant aux effets de leur activation. Votre navigateur pourrait bien prendre feu. Trêve de plaisanterie, il est possible que votre navigateur supprime toutes vos données ou que votre sécurité et votre vie privée soient compromises de manière inattendue. Nous vous prions d'agir avec précaution. ++Configuration manuelle du proxy ++Mettre à jour Adobe Reader maintenant ++ days ago ++Désactiver les plug-ins individuels... ++Envoyer une capture d'écran de la page en cours ++Point d'exclamation ++ n'est plus à jour, car il n'a pas été relancé depuis quelque temps. La mise à jour disponible sera installée dès que vous le relancerez. ++Petit problème... Tentons de le résoudre. ++Cette fonctionnalité permet d'établir des correspondances entre les sous-chaînes et plusieurs fragments d'URL figurant dans l'historique. ++Page "Nouvel onglet" expérimentale ++Les cookies suivants étaient autorisés lorsque vous avez consulté cette page : ++votre opérateur ++Activer ces fonctionnalités... ++Quitter Firefox avant l'importation ++Ajouter un nouveau téléphone ++Proxy HTTP sécurisé ++Accès à refusé. ++Finalisation de la mise à jour du système... ++Voulez-vous continuer ? ++ Ko ( Ko effectifs) ++Autre réseau Wi-Fi... ++Choisir un autre répertoire... ++L'extension indiquée est déjà associée à une clé privée. Utilisez cette clé ou supprimez-la. ++Ajouter une adresse ++Stockage local ++Afficher tous les téléchargements ++Navigateur de contenu ++Magasin de certificats ++Émis par ++Quitter le mode plein écran () ++Le certificat du serveur a été signé avec un algorithme de signature faible. ++Ajouter un utilisateur ++Me proposer de traduire les pages qui sont écrites dans une langue que je ne sais pas lire ++Récemment fermés ++Saisir la clé de déverrouillage du code PIN ++ jours ++Rechercher du texte ++Sans-Serif ++Zoom &avant ++Confirmer le nouvel envoi du formulaire ++ heure ++Cet élément doit être installé depuis . ++Mise en veille ou reprise ++Mettre à jour maintenant ++Ajouter une page ++Chiffrer seulement ++Ne jamais intervertir les touches de modification ++Conversion des numéros spéciaux ++Relancer maintenant ++Synchronisation avec effectuée ++il y a  minute ++Édition ++Préférences synchronisées ++ hours ago ++Personnalisé ++Rechercher à partir de la barre d'adresse ++Ouvrir ++Inspecter les vues actives : ++Contraintes de nom du certificat ++Ajouter une adresse ++Mot de passe incorrect. ++Statistiques avancées ++Clavier espagnol ++Sélectionnez votre réseau ++ jour ++Le serveur de synchronisation est occupé. Veuillez réessayer ultérieurement. ++Quitter cette page ++Naviguer en tant qu'invité ++Discover ++&Toujours afficher la barre de favoris ++Options de recherche ++Taille : ++il y a  secondes ++La liste suivante fait état des éléments dangereux détectés sur la page. Cliquez sur le lien "Diagnostic" pour obtenir plus d'informations sur une ressource particulière. Si une ressource a été signalée comme site de phishing alors que vous êtes certain de sa fiabilité, cliquez sur le lien "Signaler une erreur". ++Cette page rédigée dans une langue non identifiée a été traduite en . ++Les exceptions ci-dessous s'appliquent uniquement à la session de navigation privée actuelle. ++Ne plus afficher la boîte de dialogue pour les liens de ce type ++ secondes restantes ++Insérez dans l'URL où les termes de recherche devraient apparaître. ++En&registrer la vidéo sous... ++Nom : ++Si vous rencontrez des problèmes fréquents avec ce module, vous pouvez tenter d'y remédier en suivant la procédure ci-après : ++Informations relatives au certificat ++Activer l'onglet 7 ++En savoir plus sur ce problème. ++Version du matériel : ++Le site Web à l'adresse contient des éléments provenant de sites qui semblent héberger des logiciels malveillants. Ces derniers peuvent nuire à votre ordinateur ou agir à votre insu. Le simple fait de visiter un site hébergeant ce type de logiciels peut infecter votre ordinateur. Ce site héberge également des informations provenant de sites signalés comme étant des sites de phishing. Ces derniers incitent les internautes à divulguer des informations personnelles en se faisant passer pour des institutions de confiance, telles que des banques. ++Afficher la liste ++Désactivez l'affichage des messages de confirmation et le blocage de l'envoi des formulaires. ++Ce cadre a été bloqué, car il contient des éléments non sécurisés. ++Tout ++Kana ++Gérer les mots de passe enregistrés... ++Boîte de dialogue "Effacer les données de navigation" ++Mettre à jour les extensions maintenant ++Nouvelle application en arrière-plan installée ++Envoyer une capture d'écran de la page actuelle ++L'URL indiquée est incorrecte. ++Un problème est survenu lors de l'affichage de la liste des imprimantes. Certaines de vos imprimantes ne sont peut-être pas correctement enregistrées dans . ++Actuellement connecté ++La page que vous recherchez a utilisé des informations que vous avez envoyées. Si vous revenez sur cette page, chaque action précédemment effectuée sera répétée. Souhaitez-vous continuer ? ++Cette fonctionnalité indique la vitesse d'affichage réelle d'une page, en images par seconde, lorsque l'accélération matérielle est active. ++E&xporter... ++&Ouvrir un fichier... ++Configurer le contrôle d'accès pour vos périphériques ++Ouvrir un rapport de phishing ++Activer la barre d'adresse ++ secs ago ++Cartes de paiement ++Code opérateur : ++Erreur de connexion ++Vous avez la possibilité de désactiver ces services. ++Essayer d'afficher la page malgré tout ++Impossible d'établir une connexion sécurisée avec le serveur. Le serveur a peut-être rencontré un problème ou exige un certificat d'authentification du client dont vous ne disposez pas. ++Ajouter un nouveau nom ++Obtenir d'autres thèmes ++Rétablir les valeurs par défaut ++Aucun Plug-in installé. ++Action ++Extensions de fichier ++Les plus visités ++&Gestionnaire de favoris ++Caches des applications ++Cette langue est actuellement utilisée par . ++ % ++Empaqueter l'extension ++Activer l'onglet 5 ++Sélectionner le mode de saisie précédent ++Configurer le blocage de JavaScript... ++Réseaux mémorisés ++Impossible de se connecter à Internet. ++URL incorrecte ++Informations sur la sécurité ++Impossible d'installer l'application, car elle est en conflit avec "", qui est déjà installé. ++Votre périphérique n'est pas connecté. ++Fermer ++Accord de la clé ++ mins ago ++Vous ne trouvez pas ce que vous recherchez ? ++Désactivez l'envoi des pings de contrôle des liens hypertexte. ++En&registrer le fichier audio sous... ++Accédez rapidement à vos favoris en les ajoutant à la barre de favoris. ++Vérifier la grammaire et l'orthographe ++Épingler les onglets ++Sélectionner par type d'application ++assembler ++ souhaite devenir votre moteur de recherche. ++Utiliser l'historique d'entrée ++Fermer les onglets ++Voici quelques suggestions : ++Sélectionnez un ou plusieurs fichiers ++Afficher le panneau de la &vérification orthographique ++Veuillez relancer . ++Sans titre ++Pour saisir du texte, sélectionnez une langue et consultez la liste des modes de saisie disponibles. ++Ville ++Modifier... ++Réinitialiser la synchronisation ++Inclure une capture d'écran enregistrée : ++Tout supprimer ++Passer automatiquement en demi-chasse ++&Accéder à ++La capacité de ce périphérique de stockage est de . Veuillez insérer une carte SD ou une clé USB d'au moins 4 Go. ++Rouvrir le dernier onglet fermé ++(blocage) ++Erreurs () ++Traitement de la sélection... ++Aide ++Désolé ! La visionneuse de documents PDF intégrée à Google Chrome, nécessaire à l'affichage de l'aperçu avant impression, n'est pas incluse dans Chromium. ++Impossible d'ouvrir , car vous êtes déconnecté du réseau. Cette page s'affichera dès que la connexion réseau sera rétablie. <br> ++Télécopie ++version ++La passerelle ou le serveur proxy a reçu une réponse incorrecte d'un serveur en amont. ++Nouvelle fenêtre ouverte dans la session du navigateur ++Réessayer ++ peut maintenant synchroniser vos mots de passe. Vos données seront chiffrées avec le mot de passe de votre compte Google ou le mot de passe multiterme de votre choix. ++Les paramètres réseau de votre proxy sont gérés par une extension. ++Retirer l'onglet ++Valable du au ++Case cochée ++Mode de saisie ++AVERTISSEMENT ++Clavier estonien ++Ajout de bordures aux couches de rendu composées ++Imp&rimer... ++Paramètres de saisie automatique ++Rafraîchir ++Barre d'outils ++Nom de la base de données : ++Certificat du répondeur d'état ++Utiliser le mot de passe de mon compte Google ++Vos favoris sont maintenant synchronisés avec Google Documents ! ++Pour fusionner et synchroniser vos favoris dans sur un autre ordinateur, procédez de la même manière que précédemment sur l'ordinateur voulu. ++Renommer... ++ a été désactivé. Si vous arrêtez la synchronisation des favoris, vous pouvez la réactiver sur la page des extensions, via le menu Outils. ++Affichage des pages impossible ++Utiliser par défaut ++La carte SIM est verrouillée. Veuillez saisir votre code PIN. Nombre de tentatives restantes : ++Point-virgule ++Réseau domestique requis ++PKCS #7, certificat unique ++Langues baltes ++Vous avez saisi un trop grand nombre de clés de verrouillage du code PIN incorrectes. Votre carte SIM est définitivement désactivée. ++Données de diagnostic système ++Page Web, contenu HTML uniquement ++Continuer » ++Gérez vos imprimantes. ++(Choisir un problème dans la liste ci-dessous) ++&Afficher le code source du cadre ++Authentification du client WWW TLS ++Les cookies de plusieurs sites sont autorisés. ++Impossible d'afficher la page de la barre latérale "". ++Vous avez acheté de données le . ++Enregistrer le mot de passe ++Configurer... ++Mode de saisie du pinyin ++Intervertir les touches Ctrl et Alt de gauche ++Confirmer le mot de passe multiterme ++Activer ++Ajouter... ++Voulez-vous que Google Chrome enregistre ces informations de carte de paiement pour le remplissage de formulaires Web ? ++Continuer à bloquer les fenêtres pop-up ++Échec de la vérification DHCP ++Choisir un autre dossier... ++Le profil semble être utilisé par le processus sur l'hôte . Si vous êtes certain qu'aucun autre processus n'utilise ce profil, supprimez le fichier et relancez . ++Chinois traditionnel ++Effacer les données de navigation... ++Ré&activer le son ++Aucun réseau trouvé. ++&Ouvrir le fichier audio dans un nouvel onglet ++&Méthodes d'entrée ++Onglets ou fenêtres ++Toutefois, cette page inclut d'autres ressources qui ne sont pas sécurisées. Ces ressources peuvent être consultées par des tiers pendant leur transfert, et modifiées par un pirate informatique dans le but de changer le comportement de cette page. ++Automatique ++&Extensions ++Roumain ++Paramètres du réseau... ++Changer... ++Clé privée ++Format : ++Se connecter ++ : ++Vous avez tenté de contacter , mais le certificat présenté par le serveur est incorrect. ++Nouvelle fenêtre de nav&igation privée ++La page à l'adresse indique : ++Le serveur associé à n'a pas répondu à temps. Cela peut être dû à une surcharge. ++L2TP/IPSec + Clé pré-partagée ++XSS Auditor ++Durée de validité ++WebGL ++Mot de passe multiterme erroné ++Corriger automatiquement la saisie ++Unité d'organisation ++Compte Google ++&Aide ++Utiliser un service de prédiction afin de compléter les recherches et les URL saisies dans la barre d'adresse ++Certificat du signataire de courrier électronique ++En savoir plus ++Vous avez enregistré vos imprimantes sur via le compte . ++il y a  jours ++: restantes ++Cette page est enVoulez-vous la traduire ? ++Saisie automatique des formulaires ++Clavier ukrainien ++Ouvrir tous les favoris dans une fenêtre de navigation privée ++Ctrl ++ minutes ++Le certificat de sécurité du serveur contient des erreurs ! ++avec votre compte Google ++Rechercher dans les favoris ++MSCHAPv2 ++Avertissement utilisateur ++&Options du vérificateur d'orthographe ++Échec de la connexion ++Identifiant de l'erreur ++ jours restants ++Émis par : ++Mode de saisie du thaï (clavier Kesmanee) ++Passerelle : ++Chiffrement ++Autre... ++Pas avant le ++ n'a pas pu synchroniser vos données, car la connexion avec le serveur de synchronisation n'a pas pu être établie. Nouvel essai... ++Me demander lorsqu'un site souhaite afficher des notifications sur le Bureau (recommandé) ++Source : ++Erreur de lecture du cache ++Raccourci de sélection ++Vérifier la révocation du certificat serveur ++Vous rencontrez des problèmes lors de l'installation ? ++Bêta ++Pointeur de la déclaration CPS (Certification Practice Statement) ++Le , vous avez reçu à utiliser librement. ++Nom complet ++Inscription d'entreprise ++Clavier allemand ++Impossible de lancer l'impression. ++&Lire ++Récent ++Cette page Web présente une boucle de redirection. ++Supprimer le certificat "" émis par l'autorité de certification ? ++Mots de passe enregistrés ++Moins ++Options avancées ++Vérifiez vos paramètres DNS. Contactez votre administrateur réseau si vous n'êtes pas sûr de vous. ++Une erreur inconnue s'est produite. ++Émetteur : ++Passer d'un mode de saisie à l'autre ++Organisation (O) ++PKCS #1 SHA-1 avec chiffrement RSA ++Entrez la requête de recherche ici. ++Application en mode navigation privée : ++La largeur de ponctuation initiale est Complète ++Installer  ? ++Installation d'une nouvelle version... ++Ouvrir le lien dans un nouvel ongle&t ++Pour accéder aux paramètres de sécurité, saisissez le code PIN de la carte SIM. ++Jamais ++Impossible d'accéder au réseau. ++Effacer le formulaire ++Échec de la mise à jour du système ++Saisissez le mot de passe utilisé pour chiffrer ce fichier de certificat. ++CHAP ++Enregistrer le lie&n sous... ++Effacer les données de navigation... ++Options de reconnaissance vocale ++Réseau câblé ++Nouvel ongle&t ++R&etour ++Téléchargement suspendu ++Ouvrir la page d'accueil ++Connexion ++L'installation de est terminée. ++&Outils ++Page d'accueil ++Clavier phonétique bulgare ++Cookies et données de site... ++Batterie faible ++Commentaires ++Package incorrect : "". ++ heures restantes ++Configurer les paramètres de blocage des images... ++Options ++ hours ago ++&Détails ++Masquer la barre de titre du système et utiliser les bordures ++Elle peut accéder aux éléments suivants : ++Confidentialité ++Objets : ++Paramètres d'entrée du japonais ++Sebeol-sik Final ++Veuillez vous connecter à Internet pour continuer. ++Afficher les &infos sur le cadre ++Fichier ++Cop&ier l'image ++Utiliser le même proxy pour tous les protocoles ++Masquer ++Requête de protocole externe ++Afficher ++Certains de vos certificats enregistrés identifient ces serveurs : ++Vous avez visité ce site pour la première fois le . ++Cliquer pour avancer, maintenir pour voir l'historique ++La dernière version de l'application "" requiert d'autres autorisations. Elle a donc été désactivée. ++ secondes ++Vous avez choisi d'ouvrir automatiquement certains types de fichiers après leur téléchargement. ++EAP-MD5 ++&Nouvelle fenêtre +++ ++Vous avez essayé d'accéder au site , mais le serveur a présenté un certificat signé avec un algorithme de signature faible. Il se peut que les informations d'identification fournies par le serveur aient été falsifiées. Le serveur n'est peut-être pas celui auquel vous souhaitez accéder (il peut s'agir d'une tentative de piratage). Nous nous déconseillons vivement de continuer. ++L'envoi de rapports d'erreur est désactivé. ++Clé WEP incorrecte ++Date d'expiration : ++URL de base du certificat Netscape ++Réduire... ++Rechercher dans l'historique ++Ouvrir le lien dans la fenêtre de navi&gation privée ++ secondes ++Historique avancé pour le champ polyvalent ++Active l'utilisation de graphismes 3D dans les éléments canvas via l'API WebGL. ++Occident ++État non reconnu ++ ++Impossible de vérifier si le certificat du serveur a été révoqué. ++Se connecter ++Fuseau horaire : ++Cette option est soumise à une stratégie d'entreprise. Contactez votre administrateur pour plus d'informations. ++Résultats de recherche pour "" ++Revenir à "" (redémarrage requis) ++ va exécuter les tâches suivantes : ++Ajouter la page ++Changement de mode via la touche Maj ++Options de date et d'heure... ++Nom DNS ++Build de développement ++ sur ... ++Verrouiller la carte SIM (code PIN obligatoire pour utiliser les données mobiles) ++Sélectionnez le répertoire racine de l'extension. ++Les cookies de sont autorisés uniquement pour cette session. ++Confirmer les préférences de synchronisation ++RSN ++Ajuster la conversion en fonction de l'entrée précédente ++Afficher le panneau de la &vérification orthographique ++(Revenir à la capture d'écran d'origine) ++Mettre à jour & ++SSID ++- ++Les informations de connexion au compte n'ont pas encore été saisies. ++URL de configuration automatique ++URL : ++Avancer ++ jours restants ++Vous avez choisi de ne pas synchroniser les mots de passe. Vous pouvez à tout moment modifier vos paramètres de synchronisation, si vous changez d'avis. ++Lancer ++ ++ ne parvient pas à accéder au réseau. ++ ++ Il est possible que votre pare-feu ou votre antivirus considère ++ ++ comme un intrus dans votre ordinateur et qu'il bloque ses tentatives de connexion à Internet. ++Ce certificat a été vérifié pour les utilisations suivantes : ++Petit problème ! Une erreur est survenue lors de l'inscription de ce périphérique. Veuillez réessayer ou contacter votre représentant de l'assistance technique. ++Ajouter aux favoris ++Gérer les certificats... ++Analyse du périphérique... ++PYJJ ++Web Store ++Annuler l'épinglage des onglets ++Favori ++Sélectionnez votre langue : ++Réessayer le téléchargement ++Configurer la synchronisation des mots de passe ++Nom d'utilisateur : ++Enregistrer la p&age sous... ++Vos données sur tous les sites Web ++Un problème est survenu lors de l'extraction de l'image sur l'ordinateur. ++Lancer l'application ++Dubeol-sik ++Remplacé ++Afficher les cookies et autres données de site... ++Si vous pensez avoir cerné les risques, vous pouvez . ++Apparence ++Créer des raccourci&s vers des applications... ++Exécuter le flash PPAPI dans le processus du moteur de rendu ++Définir en tant que navigateur par défaut ++Veuillez choisir un nouveau code PIN. ++ () ++Autre ++&Options ++Impossible de charger la page d'arrière-plan "". ++À quel niveau rencontrez-vous des problèmes ? (Champ obligatoire) ++Retour à la sécurité ++Eten ++Ce site répertorie tous ses certificats valides dans le système DNS. Un certificat non répertorié a cependant été utilisé par le serveur. ++Options de reconnaissance vocale ++Tout sélectionner ++Impossible de charger le fichier "" pour le script de contenu, car ce fichier n'est pas codé en UTF-8. ++&Annuler ++Désactiver temporairement la personnalisation des conversions, les suggestions basées sur l'historique et le dictionnaire utilisateur ++Les cookies de sont autorisés. ++Au fil du temps, la zone ci-dessous affichera les huit sites que vous avez le plus visités. ++Le plug-in a besoin de votre autorisation pour s'exécuter. ++Échec de création de clé privée ++Ouvrir tous les favoris dans une fenêtre de navigation privée ++Placer dans la file d'attente ++Erreur de certificat serveur inconnue ++Mode de saisie du coréen ++&Plein écran ++ ++ ++ Vous pouvez essayer de diagnostiquer le problème en procédant comme suit : ++ ++ ++Bienvenue sur votre page d'accueil ! ++Vos modifications seront prises en compte au prochain démarrage de . ++Adresse du matériel : ++Lecture seule ++Erreur d'importation du certificat serveur ++Données stockées localement ++Tous les fichiers de vont être effacés. ++Modèle du périphérique : ++Afficher dans le Finder ++Nom X.500 ++Vous devez sélectionner au moins un type de données à synchroniser. ++Tout afficher ++Ouvrir tous les favoris ++Clavier danois ++Cette fonctionnalité permet de réaliser un rendu hors écran de la texture, au lieu d'un affichage direct. ++Partiellement activé ++Votre système Sandbox est correctement configuré. ++Ne pas installer ++Activer la recherche instantanée pour accélérer la recherche et la navigation ++Utiliser par défaut ++Non essentielle ++Fenêtres pop-up ++Dernière modification : ++Désélectionné ++Sécurité ++Rechercher... ++Le script de la page utilisait trop de mémoire. Rafraîchissez la page pour réactiver le script. ++Signature du code individuel Microsoft ++Mozilla Firefox ++Page Web inaccessible ++Recadrer l'image ++Si vous fermez maintenant, le téléchargement sera annulé. ++Coller ++Retour ++Impossible de graver l'image. ++Mode de saisie du Chewing ++Province ++JavaScript a été bloqué sur cette page. ++Remarque : Lorsque vous cliquez sur "Envoyer", Google Chrome OS ++ joint à votre envoi un journal des événements système de ++ votre périphérique. Ces informations nous permettent de diagnostiquer les ++ problèmes, de comprendre comment vous interagissez avec votre ++ périphérique et d'améliorer les performances de ce dernier. Les ++ informations personnelles fournies sciemment dans vos commentaires ou ++ involontairement dans les journaux système et la capture d'écran sont ++ protégées conformément à nos Règles de confidentialité. ++ Si vous ne souhaitez pas envoyer de journaux système, décochez la case ++ "Inclure les informations système". ++Interdire à tous les sites de stocker des données ++Trier par nom ++Afficher un aperçu des onglets... ++Annuler l'importation ++Ce serveur envoie des données que ne comprend pas. Veuillez signaler un bug et inclure la liste des raw. ++Calcul de la durée restante ++Mode de saisie Google du japonais (pour clavier américain) ++Envoi de la requête... ++Parlez maintenant ++Impossible d'installer le package : "" ++Modèle : ++Bloquer tous les cookies tiers ++Remplacer par ++Espace ++Arrêt du fonctionnement ++Préférences ++Nom inconnu ++Nom ++Choisir un nouveau code PIN ++ [] ++Erreur d'exportation de fichier PKCS #12 ++Le répertoire racine de l'extension doit être indiqué. ++Miniature supprimée ++Tout développer... ++Aie aie aie ++Choisir les expressions en arrière-plan, sans déplacer le pointeur ++Plu&s petit ++Afficher le clavier en superposition ++C&opier l'URL de l'image ++OK ++Aucun réseau détecté ++Charger l'extension non empaquetée... ++page ++Active l'interface utilisateur et le code de support pour le processus du service de communication à distance, de même que le plug-in client. Avertissement : ce service n'est actuellement disponible que pour les tests de développeurs. Si vous ne faites pas partie de l'équipe de développement et ne figurez pas sur la liste blanche, aucun élément de l'interface utilisateur activée ne fonctionnera. ++Clavier turc ++Modifier le favori ++Couleur ++Personnaliser les paramètres de synchronisation... ++Activation de votre service Internet mobile ++ ++Ouvrir dans un onglet standard ++ - ++Portrait ++ days ago ++Active un service en arrière-plan qui connecte le service aux éventuelles imprimantes installées sur cet ordinateur. Une fois ce labo activé, vous pouvez lancer en vous connectant à votre compte Google via Options/Préférences dans la section Options avancées. ++Outils de &développement ++Le répertoire racine de l'extension est incorrect. ++ID de clé de l'objet du certificat ++Téléchargements ++Le stockage du certificat client généré par a réussi. ++Sélectionnée ++Suspendre ++Taille sur le disque : ++ID du processus ++Réduire ++Expire le ++Votre administrateur a désactivé l'accès aux fichiers locaux sur votre ordinateur. ++Erreur de connexion SSL ++Envoyer ++Virgule ++&Pause ++Parcourir... ++Mode de saisie Google du japonais (pour clavier Dvorak américain) ++Police à largeur fixe ++Stockage de session ++Page en arrière-plan : ++Le serveur a renvoyé un certificat client incorrect. Erreur  () ++Signature de document Microsoft ++Bloqué ++Gérer les paramètres d'impression... ++Cette page Web a désactivé la saisie automatique dans ce formulaire. ++Clavier hongrois ++Les versions en développement permettent de tester de nouvelles idées, mais elles peuvent s'avérer très instables. Nous vous prions d'agir avec précaution. ++Ajouter un dossier... ++Mode de saisie du japonais (pour clavier Dvorak américain) ++Signaler un bug ++&Toujours ouvrir les fichiers de ce type ++Disque optique ++Nom commun ++Très grande ++Modification terminée ++Objet ++Opérateur : ++Algorithme de signature du certificat ++Cette fonctionnalité permet d'afficher un onglet d'aperçu avant de lancer une impression. ++Autre nom de l'objet du certificat ++Activer la saisie automatique pour remplir les formulaires Web d'un simple clic ++Le site Web à l'adresse a été signalé comme étant un site de phishing. Ces sites tentent d'amener les internautes à divulguer leurs informations personnelles en se faisant passer pour des institutions de confiance, telles que des banques. ++Rechercher directement sur ++Connectez-vous à pour exporter le certificat client. ++Créer un compte Google maintenant ++État Sandbox ++Retirer de la liste ++rapide ++&Effacer les données de navigation… ++Vérification des mises à jour... ++Télécharger les mises à jour de sécurité essentielles ++Package incorrect. Détails : "". ++Continuer à bloquer les cookies ++Ligne de commande ++Coller l'URL et y a&ccéder ++Désactiver ++Build officiel ++Se connecter à un réseau Wi-Fi ++Périphérique inconnu ++Supprimer les cookies et autres données de site ++URL saisies ++Utiliser les touches , et . pour paginer une liste d'entrées ++Vider la mémoire ++Supprimer les éléments sélectionnés ++Toujours ++de moins d'une heure ++Aucun réseau n'est disponible. ++Supprimer les cookies et autres données de site et de plug-in ++Intervertir les touches Rechercher et Ctrl gauche ++Faites glisser trois doigts sur la surface de votre trackpad pour afficher un aperçu de tous vos onglets. Cliquez sur une vignette pour la sélectionner. Idéal en mode plein écran. ++Nouveau ! Configurer la synchronisation des mots de passe ++Échec de la tentative de connexion au serveur ++Désactiver les notifications de ++Les fichiers suivants ont été créés : ++ ++Extension : ++Fichier de clé : ++ ++Conservez votre fichier de clé en lieu sûr. Vous en aurez besoin lors de la création de nouvelles versions de l'extension. ++&Oui ++Ouvrir les fichiers ++Clavier suédois ++Mémoire JavaScript ++Quitter le mode plein écran ++Hiérarchie des certificats ++Afficher l'onglet existant si l'URL associée est demandée dans un autre ++&Afficher ++Vos données personnelles sur , et sur  autres sites Web ++SMS de ++Afficher la s&ource ++Zoom arrière ++C&opier l'URL du fichier audio ++Importer et associer au périphérique... ++() () ++Plug-ins (par ex. Adobe Flash Player, QuickTime, etc.) ++Empaqueter l'extension... ++Vérifier l'orthographe lors de la frappe ++Échec de la traduction en raison d'un problème de connexion réseau ++Code PIN incorrect. Veuillez réessayer. Nombre de tentatives restantes : ++Vous pouvez effectuer une recherche directement à partir du champ ci-dessus. ++Ajouter les expressions au premier plan ++Lorem ipsum dolor sit amet, consectetur adipiscing elit. ++Opérateur ++Confirmer l'installation ++(Mot clé : ) ++Sensibilité : ++ +diff --git a/tools/grit/grit/testdata/generated_resources_iw.xtb b/tools/grit/grit/testdata/generated_resources_iw.xtb +new file mode 100644 +index 0000000000..86b55334c0 +--- /dev/null ++++ b/tools/grit/grit/testdata/generated_resources_iw.xtb +@@ -0,0 +1,4 @@ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/generated_resources_no.xtb b/tools/grit/grit/testdata/generated_resources_no.xtb +new file mode 100644 +index 0000000000..913638ba4e +--- /dev/null ++++ b/tools/grit/grit/testdata/generated_resources_no.xtb +@@ -0,0 +1,4 @@ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/grit_part.grdp b/tools/grit/grit/testdata/grit_part.grdp +new file mode 100644 +index 0000000000..c8e9d92692 +--- /dev/null ++++ b/tools/grit/grit/testdata/grit_part.grdp +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/header.html b/tools/grit/grit/testdata/header.html +new file mode 100644 +index 0000000000..8e9d10ec50 +--- /dev/null ++++ b/tools/grit/grit/testdata/header.html +@@ -0,0 +1,39 @@ ++ ++[$~TITLE~$] ++ ++ ++ ++ ++[EXTRA_META] ++ ++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/homepage.html b/tools/grit/grit/testdata/homepage.html +new file mode 100644 +index 0000000000..cce4f2cf35 +--- /dev/null ++++ b/tools/grit/grit/testdata/homepage.html +@@ -0,0 +1,37 @@ ++ ++Google Desktop Search ++ ++ ++ ++ ++ ++ ++ ++ ++
++ ++
Google Desktop Search

++
++ ++ ++ ++
++[$~LINKS~$] ++
++ ++ ++ ++ ++ ++
 
  Desktop Preferences
++

Search your own computer.

++[$~MESSAGE~$]
++
[$~SETHOMEPAGE~$][$~BOTTOMLINE~$]

++

©2005 Google - Searching [NUM_ITEMS] items

+\ No newline at end of file +diff --git a/tools/grit/grit/testdata/hover.html b/tools/grit/grit/testdata/hover.html +new file mode 100644 +index 0000000000..b8f9ce0200 +--- /dev/null ++++ b/tools/grit/grit/testdata/hover.html +@@ -0,0 +1,177 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
++Sidebar ++Minibar ++Close ++
++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
++ ++
++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
  
++
++ ++ ++
++ ++
++
++ ++ ++ +diff --git a/tools/grit/grit/testdata/include_test.html b/tools/grit/grit/testdata/include_test.html +new file mode 100644 +index 0000000000..e08f2e2e8a +--- /dev/null ++++ b/tools/grit/grit/testdata/include_test.html +@@ -0,0 +1,31 @@ ++ ++ ++should be kept ++ ++in the middle... ++ ++should be removed ++ ++ ++ ++should be removed ++ ++ should be removed because outer expr is False ++ ++should be removed ++ ++ ++ ++ ++ ++ nested true should be kept ++ ++ ++ should be removed ++ ++ ++ ++ silbing true should be kept ++ ++ ++at the end... +diff --git a/tools/grit/grit/testdata/included_sample.html b/tools/grit/grit/testdata/included_sample.html +new file mode 100644 +index 0000000000..7150ffcbea +--- /dev/null ++++ b/tools/grit/grit/testdata/included_sample.html +@@ -0,0 +1 @@ ++Hello Include! +diff --git a/tools/grit/grit/testdata/indexing_speed.html b/tools/grit/grit/testdata/indexing_speed.html +new file mode 100644 +index 0000000000..db1787b0e2 +--- /dev/null ++++ b/tools/grit/grit/testdata/indexing_speed.html +@@ -0,0 +1,58 @@ ++ ++Google Desktop Search Index Speed ++ ++ ++ ++ ++ ++ ++ ++ ++
++ Go to Google Desktop Search  ++ ++ ++ ++ ++
++ ++ ++ ++ ++
 Index SpeedIndex Speed ++ Help | About Google Desktop Search
++ ++

++To make your emails, files, and previously viewed web pages searchable, Google Desktop Search ++needs to index them. This indexing process is currently occuring in the background ++and your computer performance is minimally impacted. ++

++You have the option of speeding up this process. ++

Warning: Speeding up indexing will cause your computer ++to become unusable for many minutes, depending on how many items need to be indexed. FAST INDEXING IS NOT ++RECOMMENDED. ++
 
++

++ ++
++

++ ++
++
++ ++

 
++ ++ ++ ++
++ ++ ++ ++ ++
Google Desktop Search Home - Status - About Google Desktop Search - [$~BUILDNUMBER~$] - ©2005 Google

++ ++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/install_prefs.html b/tools/grit/grit/testdata/install_prefs.html +new file mode 100644 +index 0000000000..eca0b56de5 +--- /dev/null ++++ b/tools/grit/grit/testdata/install_prefs.html +@@ -0,0 +1,92 @@ ++ ++Google Desktop Search: Initial Preferences ++ ++ ++ ++ ++ ++ ++ ++

++ ++
++
To continue, please set these initial preferences:

++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
 
 
  ++
++ ++ ++ ++ ++ ++ ++ ++ ++
++ ++ ++
Deskbar
++ ++ ++
++
  ++
You can change these and other preferences at any time.
++


++

++
++[SCRIPT] ++ ++ ++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/install_prefs2.html b/tools/grit/grit/testdata/install_prefs2.html +new file mode 100644 +index 0000000000..18380397c2 +--- /dev/null ++++ b/tools/grit/grit/testdata/install_prefs2.html +@@ -0,0 +1,52 @@ ++ ++Indexing has Started ++ ++ ++ ++ ++ ++ ++ ++
++

++
++
++One-time indexing has started.

++An index is being prepared on your computer to allow you ++to search your information as fast as you can search the web.

++
  • This is a one-time process that may take several hours. ++
  • You may continue to use your computer as usual and it is safe to shut down your computer. ++
  • Indexing will be performed only when your computer is idle. ++ ++ ++


    ++ ++

  • ++ ++
    ++ ++[SCRIPT] ++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/klonk-alternate-skeleton.rc b/tools/grit/grit/testdata/klonk-alternate-skeleton.rc +new file mode 100644 +index 0000000000000000000000000000000000000000..5f2c82a55469ddaab246c095826ad9e6743c0015 +GIT binary patch +literal 1088 +zcmbW0Pfr3t48`AhKZV)z#sGrI5!gjnU?DC>IT2z!82=r_L=!)}zjnmk5b$6oGo9&7 +z+t=4lu9UG-Ujxl_t%b{59ih$9PSBn!lW7`iGrKMm&Q10vTRK5!yRJHlRN`fcWril@ +zv|?uHM))d_NBa7`nW9TQ&PZ3tsax6ojav@U&9TYdHduz6k{G4GFTfpX_hk&`!z0F` +z!gJ>6WBh&UO&i_oS+VOvUfcD9JR=y&;3OxP2%KT$#JB9W=UtgQpDT@>(E^#^A;oG% +z4omjIK7rLXcRgmyS+%u_Gl2`MhOxMB{GGM&5o6cXFE~=G +z`!#F5=z%_bq95y7+aIx?IdcSN`A)xX^vZjCS7lnS#=iZ)E7W%eX8!kr-#RDO36^!o +Qqn&wY8qX0d7T}2V4SbP+*8l(j + +literal 0 +HcmV?d00001 + +diff --git a/tools/grit/grit/testdata/klonk.ico b/tools/grit/grit/testdata/klonk.ico +new file mode 100644 +index 0000000000000000000000000000000000000000..d371b214dc366249870efccc5da278d023aa91f1 +GIT binary patch +literal 766 +zcmeH_F%H5o5CqSFL>Ve71Sxq1;TtsMEB*!Fv6LbmDQFSUL1mXjO7OC0gpl|G?B1ML +zXS=a1V(2`di0U>FnQ~o{oUDnF5j(}bxAgSuhE8lMu~rkI8Ju%mb%Im^Xd<+ZwEgwd +zFTg+WQOj5lfvO*4mbEA^bCj9KHh65vjx^zvsKW{eA8|Ah`w&r;%!`QgmEiG3hXCcC +L+@V2V6oA7MJIRBx + +literal 0 +HcmV?d00001 + +diff --git a/tools/grit/grit/testdata/klonk.rc b/tools/grit/grit/testdata/klonk.rc +new file mode 100644 +index 0000000000000000000000000000000000000000..35652c4e6dd7cf7b7f62f637e191acf66f487235 +GIT binary patch +literal 9824 +zcmeI2+j1L48poSUd1!LS!j6*Z-q>7MTIeClrf{=b{yW=KLKoQA`29(tkA +z?@<`g*P*W;F2X@LqqP?P!IgxQa2&e)&gmcUJfiQMr{-PocF21|OVCckGsY~31#sNt +zeuJJaU(OhLWaHAYxy#{kNExfq8uQ5J2xc`jLo2kyURV$HuoL#fZm7|_&ii)Q3SZFE +z;@$|W^lb4S@e23#yIdxsED4)%Ix5vi$fg&b@^yerB!M>k-sfJ2-!(XtBx>~E;y0>; +zywqpO@eUBz4c2yv49m3k+_Z88eb3Rg>+A-4?GCk8rmyLEuD7;k@iyBQuQz|u4r}P| +z1pk!hKgO!w#>STMq~-8ViH-G#etL?RCgF{OzaBBS8aA-k=%+1wau1JP!(#WbwJk2e +z{FW=3II|6mUA$wTS=-Ei$KrzUMVn6ea?kwXHeRp*%qrtH8Cm5n-|(IYVUuHA@wRN;~7h6y+xyz_&R~;+XxM^eZ-_q~|%%b86_{3Asa-8FBk+Z7c-kJgN>UjHR +zv*J6C_vNv`hUxGkXMvL0T0vKhVQf$p6QjfeUR}fgl_wW2W!gk%O?IOa`tbcYLDwE{AY?>BR88vkIj3pcp9ftwy~b;A8i-;T|_p=$nY5yWU!`jTE^ib +ze*F+mE-Vf$>e;=5g*fg0^w_NUeElxZA2EAWiGRui^1Zl<=<)P1 +zF&Y;=yo$%KVIA>VGwa=@)kgQbrt31jq~WuvvL2VO`$zNqGSmHCaU;Y2q0yQ$JF7mTwL~ub{sOMb^Vh8GFZ(K1F-x>#wroJR +z&tF1@??TN-{BD^HbgJ;mLeTx&a +ztSZO1p-!t5NvMLINn_JEi1N%h$mrKfeZ%Sxtv*(Sq%E`|5` +zMQa!2rJ*fu!l%|$%^a7pE^XVFE$AM-((pNcct~BK8YqR1Sd~Aqmi*&@D)rQ&bN`YW +zMPvC%+;<0?G_uSf2bldXz_x`Rp$tXUa07m0#5g^O>n*TJE4PW#|}5_jztxOjO*+fAM}< +zk=Lii5sD#879SKTSIp++>5AlgXumxIv246U-XKqCe;}^ATDIP+P{%8`Yynw2Uilpc +z$xha}X;{ahB+#YVajq(xJ|2|kCBqoURxZc-PCWGR&NeH+c%h>-Yw>z7_{+>=5WWql;yg~F}V-&+XR>jna$uG|ylUKW)Rw*m^ +z_oOjp@vHny>%lMrW)jt@&DG$}J`tOC!twxncz`|R{U9wplS^%1SD7h)zLPS$9KxSJ +z^(luqF00#DmestFZxDq%2fL5@KE>#HI|)#R(g69An@YFD|(_t^K?Y(=LYvGR$s)LKbvaYc(JPp$Xb2G?a>eC9KE-cEhZ +zHSZ3+_C$Rze-w`BSsn7ZgI%TJO=9FfdDBy)V;pqaYpnOHjNdZ)cZhIWOV;71NPE_b +z5ZwYd@EV=tI))^?mN>3>KBO~=3-s|NvQu_bO!m`Xy&s`1RS8A9bec9lO`@(ym$)sX +zMVVq?wjta)kvTJp%Bk>bSh}4@HcmwuW}T<$ta~!gT03ja*d|hI1w9*Uk>}TwPvL12 +z=Q{J$UgQ8RXmu+(2GDd)J#{>6mrEh;W{57|8=6JgB)U>?#`vQXEaBEZgsP}6H0c~I +zlTn_wQLB~3>U1IQ2y}Rh=cM|##66Rnd!p7F(K=LbM6B`LtO3?OS3Ko>03~gD6g5tu +zOSRooa>4*SqvO;gSO;d)IuFc4e&rSY3#4arR~e}tmqXie5w!0rzg2#y{KWm2%CD85 +zD?e8LTlv1?UR>st9pKlDtGM^mfuA&df=7MIT`QQ#k8mnxoriygx5#|&^UZ&6F?Nx! +z2jMH^+zTJm>H?vU#6L!6XLz9~{RHheL_xo4SVUcx*(c|e8ZfVRzJC37^PM7DoUXW9 +zRu0v_b;|ztF`73W!u5N4HWX!l^ZH1;i+3m{&0Ya4gg*c` +C>9bG( + +literal 0 +HcmV?d00001 + +diff --git a/tools/grit/grit/testdata/ko_oem_enable_bug.html b/tools/grit/grit/testdata/ko_oem_enable_bug.html +new file mode 100644 +index 0000000000..f2c199cc15 +--- /dev/null ++++ b/tools/grit/grit/testdata/ko_oem_enable_bug.html +@@ -0,0 +1 @@ ++아웃룩 +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/ko_oem_non_admin_bug.html b/tools/grit/grit/testdata/ko_oem_non_admin_bug.html +new file mode 100644 +index 0000000000..b9e8a1f288 +--- /dev/null ++++ b/tools/grit/grit/testdata/ko_oem_non_admin_bug.html +@@ -0,0 +1 @@ ++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/mini.html b/tools/grit/grit/testdata/mini.html +new file mode 100644 +index 0000000000..8ac0a231a0 +--- /dev/null ++++ b/tools/grit/grit/testdata/mini.html +@@ -0,0 +1,36 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++ ++ ++ ++ ++ ++ ++ ++ ++
      
    ++
    ++
    +diff --git a/tools/grit/grit/testdata/oem_enable.html b/tools/grit/grit/testdata/oem_enable.html +new file mode 100644 +index 0000000000..db6b85eca6 +--- /dev/null ++++ b/tools/grit/grit/testdata/oem_enable.html +@@ -0,0 +1,106 @@ ++ ++Google Desktop Search Download ++ ++ ++ ++ ++ ++
    ++ ++ ++ ++ ++ ++
    ++
    Google Desktop Search
                Search your own ++computer.

    ++ ++ ++ ++ ++ ++
    ++
  • Find your email, files, web history and chats instantly ++
  • View web pages you've seen, even when you're not online ++
  • Search as easily as you do on Google ++

    Google Desktop Search finds:

    ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    Outlook  Email from Outlook, Outlook Express, & ++ Thunderbird
    Internet Explorer  Web history ++ from IE/Firefox/Mozilla/Netscape
    Text  Files in Word, ++ Excel, Powerpoint, PDF, & media formats
    AOL IM  Chats from AOL ++ Instant Messenger
     
     About Desktop ++ Search   Screenshots   ++ Help   Contact ++ Us
  •     ++ ++ ++ ++

    ++
    By using, you agree to our
    Terms & ++ Conditions
    and Privacy ++ Policy
    ++

    ++
    ++

    ++

    * Automatically starts when you turn on ++ your computer
    ++

    ++

    ++
    ©2005 Google ++

    +diff --git a/tools/grit/grit/testdata/oem_non_admin.html b/tools/grit/grit/testdata/oem_non_admin.html +new file mode 100644 +index 0000000000..8b7ca13e21 +--- /dev/null ++++ b/tools/grit/grit/testdata/oem_non_admin.html +@@ -0,0 +1,39 @@ ++ ++Google Desktop Search Preferences ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++
    ++


    We're sorry, but you need administrator access to ++enable Desktop Search.

    ++

    To install or run Google Desktop Search you need administrator access on this ++computer. Please try installing again once you have administrator ++access.

    ++


    ++
    +diff --git a/tools/grit/grit/testdata/onebox.html b/tools/grit/grit/testdata/onebox.html +new file mode 100644 +index 0000000000..c24ff043a5 +--- /dev/null ++++ b/tools/grit/grit/testdata/onebox.html +@@ -0,0 +1,21 @@ ++Google Desktop Search Results ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/oneclick.html b/tools/grit/grit/testdata/oneclick.html +new file mode 100644 +index 0000000000..32dc6459dd +--- /dev/null ++++ b/tools/grit/grit/testdata/oneclick.html +@@ -0,0 +1,34 @@ ++[HEADER] ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++ [EMAIL_TOP_CHROME] ++ ++

    ++ ++ [EMAIL] ++
    ++

    ++ [FREQ_TOP_CHROME] ++

    ++ ++ [$~FREQ~$] ++
    ++

    ++ [RECENT_TOP_CHROME] ++ ++ [$~RECENT~$] ++
    ++

    ++

    ++ ++ ++[FOOTER] +diff --git a/tools/grit/grit/testdata/password.html b/tools/grit/grit/testdata/password.html +new file mode 100644 +index 0000000000..16007a1ac0 +--- /dev/null ++++ b/tools/grit/grit/testdata/password.html +@@ -0,0 +1,37 @@ ++ ++Password Required ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++ ++
    Google Desktop Search

    ++
    ++ ++ ++
    ++ ++ ++ ++
    Password required:   ++ ++   ++
    ++ ++
    ++
    [$~BOTTOMLINE~$]

    ++

    ©2005 Google

    +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/preferences.html b/tools/grit/grit/testdata/preferences.html +new file mode 100644 +index 0000000000..b37412436b +--- /dev/null ++++ b/tools/grit/grit/testdata/preferences.html +@@ -0,0 +1,234 @@ ++ ++Google Desktop Search Preferences ++ ++ ++ ++ ++ ++
    ++ ++ ++ ++ ++
    ++Go to Google Desktop Search  ++ ++ ++ ++ ++
    Preferences ++Preferences Help ++
    ++ ++
    ++ ++ ++ ++ ++
    ++Save your preferences when finished.
    ++ ++[STATUS-MESSAGE] ++ ++ ++
    Preferences (changes apply to Google Desktop Search application)
    ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    Search types
    Index the following items so that you can ++search for them:
     
    ++
    ++ ++ ++ ++ ++ ++
    ++
    ++
    ++ ++ ++
    ++ ++ ++
    ++ ++
    ++ ++
    ++
    ++ ++
    ++ ++
    ++

    ++ ++
    ++
    ++
    Plug-ins
    Index these additional items:

    ++[ADDIN-DO] ++[ADDIN-OPTIONS]

    ++To install plug-ins to index other items, visit the ++Plug-ins Download page.
    ++
    Don't search these items
    ++
    ++c:\Documents and Settings\username\Private Stuff
    ++http://www.domain.com/
    ++
     
    ++
    ++
    Search Box Display ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++ ++ ++
    Deskbar
    ++ ++ ++
    ++ ++ ++ ++
    ++ ++
    Number of Results ++
    Google integration ++ ++ ++ ++
    ++ Your personal results are private from Google. ++
    ++
    Help us improve ++ ++
    ++ ++ ++ ++ ++
    Save your preferences ++when finished.
    ++ ++

    [$~BOTTOMLINE~$]
    ++
    ©2005 Google
    ++
    +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/preprocess_test.html b/tools/grit/grit/testdata/preprocess_test.html +new file mode 100644 +index 0000000000..13ece9a9f6 +--- /dev/null ++++ b/tools/grit/grit/testdata/preprocess_test.html +@@ -0,0 +1,7 @@ ++ ++should be kept ++ ++in the middle... ++ ++should be removed ++ +diff --git a/tools/grit/grit/testdata/privacy.html b/tools/grit/grit/testdata/privacy.html +new file mode 100644 +index 0000000000..1d45f4a539 +--- /dev/null ++++ b/tools/grit/grit/testdata/privacy.html +@@ -0,0 +1,35 @@ ++[!] ++title Privacy and Google Desktop Search ++template ++privacy_bottomline ++hp_image ++ ++ ++ ++
    ++

    Privacy and Google Desktop Search

    ++ ++

    Google is committed to making search on your desktop as easy ++as searching the web. We recognize that privacy is an important issue, ++so we designed and built Google Desktop Search with respect for your privacy. ++

    ++So that you can easily search your computer, the Google Desktop Search application indexes ++and stores versions of your files and other computer activity, ++such as email, chats, and web history. These versions may also be mixed ++with your Web search results to produce ++results pages for you that integrate relevant content from your computer and ++information from the Web. ++

    ++Your computer's content is not made accessible to Google or anyone else without your explicit permission. ++ ++

    You can read the ++Privacy Policy ++and Privacy FAQ online. ++ ++

    ++ ++

    ++ ++
    ++[$~PRIVACY_BOTTOMLINE~$] - ©2005 Google ++
    +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/quit_apps.html b/tools/grit/grit/testdata/quit_apps.html +new file mode 100644 +index 0000000000..a501b0e2bf +--- /dev/null ++++ b/tools/grit/grit/testdata/quit_apps.html +@@ -0,0 +1,49 @@ ++ ++Google Desktop Search Preferences ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++
    ++


    To start using Google Desktop Search, we may need to close the following programs if they are running:

    ++

    You can start these programs once Google Desktop Search is running.

    ++ ++
  • AOL Instant Messenger ++
  • Firefox ++
  • Internet Explorer ++
  • Microsoft Excel ++
  • Microsoft Outlook ++
  • Microsoft Word ++
  • Mozilla ++
  • Mozilla Thunderbird ++
  • Netscape ++
  • Opera ++
  • Other web browsers ++ ++

    This will take only a few seconds to complete.

  • ++

    ++

    ++
    +diff --git a/tools/grit/grit/testdata/recrawl.html b/tools/grit/grit/testdata/recrawl.html +new file mode 100644 +index 0000000000..0401e7c2b0 +--- /dev/null ++++ b/tools/grit/grit/testdata/recrawl.html +@@ -0,0 +1,30 @@ ++ ++Refresh index ++ ++ ++ ++ ++ ++ ++ ++
    ++ ++ ++ ++ ++
    Google Desktop Search ++
    ++
    ++
    Google Desktop Search is now recrawling your drive to index new files.
    ++
    Note that new files are indexed automatically, and this step is generally not needed.
    ++
    Click here to continue.
    ++ ++
    ++[$~BOTTOMLINE~$] ++

    ©2005 Google

    ++
    ++ ++ +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/resource_ids b/tools/grit/grit/testdata/resource_ids +new file mode 100644 +index 0000000000..d5d440d57f +--- /dev/null ++++ b/tools/grit/grit/testdata/resource_ids +@@ -0,0 +1,13 @@ ++{ ++ "SRCDIR": ".", ++ "test.grd": { ++ "messages": [100, 10000], ++ }, ++ "substitute_no_ids.grd": { ++ "messages": [10000, 20000], ++ }, ++ "<(FOO)/file.grd": { ++ }, ++ "<(SHARED_INTERMEDIATE_DIR)/devtools/devtools.grd": { ++ }, ++} +diff --git a/tools/grit/grit/testdata/script.html b/tools/grit/grit/testdata/script.html +new file mode 100644 +index 0000000000..f177d9c30e +--- /dev/null ++++ b/tools/grit/grit/testdata/script.html +@@ -0,0 +1,38 @@ ++ +diff --git a/tools/grit/grit/testdata/searchbox.html b/tools/grit/grit/testdata/searchbox.html +new file mode 100644 +index 0000000000..9eccba99a5 +--- /dev/null ++++ b/tools/grit/grit/testdata/searchbox.html +@@ -0,0 +1,22 @@ ++ ++ ++ ++ ++ ++
    Go to Google Desktop Search   ++ ++ ++ ++ ++
    ++ ++ ++
    ++[$~LINKS~$] ++
    ++
    ++[$~FLAGS~$]
      Desktop Preferences
      [DELETE_NAME]
    ++ ++ ++
     
    ++
    +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/sidebar_h.html b/tools/grit/grit/testdata/sidebar_h.html +new file mode 100644 +index 0000000000..e103e8f8db +--- /dev/null ++++ b/tools/grit/grit/testdata/sidebar_h.html +@@ -0,0 +1,82 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++ ++
    ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
     Google Desktop Search
    ++
    ++ ++
    ++ ++[HEADER_SECTION1] ++[CONTENT_INBOX] ++ ++ ++ ++[HEADER_SECTION2] ++[CONTENT_HIST] ++ ++ ++ ++[CONTENT_NEWS] ++[CONTENT_OTHER] ++ ++ ++ ++ ++ ++
    ++ ++ ++ ++[SCRIPT] ++ +diff --git a/tools/grit/grit/testdata/sidebar_v.html b/tools/grit/grit/testdata/sidebar_v.html +new file mode 100644 +index 0000000000..e040d8ec59 +--- /dev/null ++++ b/tools/grit/grit/testdata/sidebar_v.html +@@ -0,0 +1,267 @@ ++ ++Google Desktop Search Sidebar ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++ ++ ++ ++ ++
    ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++ ++
    ++ ++ ++ ++ ++ ++ ++
    Google Desktop Search  Web 
    ++
    ++ ++

    ++
    ++
     News
    ++
    ++ ++ ++[CONTENT_NEWS] ++

    ++ ++ ++
    ++
     Email
    ++
    ++ ++ ++[CONTENT_INBOX] ++

    ++ ++ ++
    ++
     Related History
    ++
    ++ ++ ++[CONTENT_HIST] ++

    ++ ++ ++ ++
    ++
     Recent
    ++
    ++ ++ ++[CONTENT_RECENT] ++

    ++ ++ ++ ++
    ++
     Frequently Visited
    ++
    ++ ++ ++[CONTENT_POPULAR] ++

    ++ ++ ++ ++
    ++
     Implicit Query Debug
    ++
    ++ ++ ++[CONTENT_QUIB_DEBUG] ++ ++ ++ ++ ++[CONTENT_OTHER] ++ ++[SCRIPT] ++ ++ +diff --git a/tools/grit/grit/testdata/simple-input.xml b/tools/grit/grit/testdata/simple-input.xml +new file mode 100644 +index 0000000000..92827fa4b5 +--- /dev/null ++++ b/tools/grit/grit/testdata/simple-input.xml +@@ -0,0 +1,52 @@ ++ ++ ++ ++ ++ Hello earthlings! ++ ++ ++ ++ ++ ++ ++ ++ ++ Go! ++ ++ Hello %sJoi, how are you doing today? ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/simple.html b/tools/grit/grit/testdata/simple.html +new file mode 100644 +index 0000000000..4392d23e98 +--- /dev/null ++++ b/tools/grit/grit/testdata/simple.html +@@ -0,0 +1,3 @@ ++

    ++ Hello! ++

    +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/source.rc b/tools/grit/grit/testdata/source.rc +new file mode 100644 +index 0000000000..fbc72284e9 +--- /dev/null ++++ b/tools/grit/grit/testdata/source.rc +@@ -0,0 +1,57 @@ ++IDC_KLONKMENU MENU ++BEGIN ++ POPUP "&File" ++ BEGIN ++ MENUITEM "E&xit", IDM_EXIT ++ MENUITEM "This be ""Klonk"" me like", ID_FILE_THISBE ++ POPUP "gonk" ++ BEGIN ++ MENUITEM "Klonk && is [good]", ID_GONK_KLONKIS ++ END ++ END ++ POPUP "&Help" ++ BEGIN ++ MENUITEM "&About ...", IDM_ABOUT ++ END ++END ++ ++IDD_ABOUTBOX DIALOGEX 22, 17, 230, 75 ++STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU ++CAPTION "About" ++FONT 8, "System", 0, 0, 0x0 ++BEGIN ++ ICON IDI_KLONK,IDC_MYICON,14,9,20,20 ++ LTEXT "klonk Version ""yibbee"" 1.0",IDC_STATIC,49,10,119,8, ++ SS_NOPREFIX ++ LTEXT "Copyright (C) 2005",IDC_STATIC,49,20,119,8 ++ DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP ++ CONTROL "Jack ""Black"" Daniels",IDC_RADIO1,"Button", ++ BS_AUTORADIOBUTTON,46,51,84,10 ++END ++ ++IDD_DIFFERENT_LENGTH_IN_TRANSL DIALOGEX 22, 17, 230, 75 ++STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU ++CAPTION "Bingobobbi" ++FONT 8, "System", 0, 0, 0x0 ++BEGIN ++ LTEXT "Howdie dodie!",IDC_STATIC,49,10,119,8,SS_NOPREFIX ++ LTEXT "Yo froodie!",IDC_STATIC,49,20,119,8 ++END ++ ++STRINGTABLE ++BEGIN ++ IDS_SIMPLE "One" ++ IDS_PLACEHOLDER "%s birds" ++ IDS_PLACEHOLDERS "%d of %d" ++ IDS_REORDERED_PLACEHOLDERS "$1 of $2" ++ // Won't be in translations list because it has changed ++ IDS_CHANGED "This was the old version" ++ IDS_TWIN_1 "Hello" ++ IDS_TWIN_2 "Hello" ++ IDS_NOT_TRANSLATEABLE ":" ++ IDS_LONGER_TRANSLATED "Removed document $1" ++ // Won't appear in the list of translations because it's not in the .grd file ++ IDS_NO_LONGER_USED "Not used" ++ IDS_DIFFERENT_TWIN_1 "Howdie" ++ IDS_DIFFERENT_TWIN_2 "Howdie" ++END +diff --git a/tools/grit/grit/testdata/special_100_percent/a.png b/tools/grit/grit/testdata/special_100_percent/a.png +new file mode 100644 +index 0000000000000000000000000000000000000000..5d5089038ca71172e95db9e7aae1e1fa5cebd505 +GIT binary patch +literal 159 +zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>0wld=oSO}#(mY)pLnNjq|2Y3)zGGzYPN&L+ +zMSC}CcCfp=Dtxv4%6W%G#Q=|R|L;6pCCLUWO)Z<5eoL%TkDTw=s4X!^d(Qa<2khAN +zZPy!XToBAic1Ss}vcWiD27B3&`Zj^H6CO>7R1{ToQ;=ggdEYbV=IISvfHpFCy85}S +Ib4q9e0O9jEh5!Hn + +literal 0 +HcmV?d00001 + +diff --git a/tools/grit/grit/testdata/status.html b/tools/grit/grit/testdata/status.html +new file mode 100644 +index 0000000000..6b997b9369 +--- /dev/null ++++ b/tools/grit/grit/testdata/status.html +@@ -0,0 +1,44 @@ ++[HEADER] ++ ++ ++
    ++ ++ ++
     Desktop Search Status
    ++
    ++
    ++[$~MESSAGE~$] ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
     Number of itemsTime of newest item
      Total searchable items[TOTAL_COUNT][TOTAL_TIME]
           Emails[EMAIL_COUNT][EMAIL_TIME]
           Chats[IM_COUNT][IM_TIME]
           Web history[WEB_COUNT][WEB_TIME]
           Files[FILE_COUNT][FILE_TIME]
    ++
    ++[FOOTER] +\ No newline at end of file +diff --git a/tools/grit/grit/testdata/structure_variables.html b/tools/grit/grit/testdata/structure_variables.html +new file mode 100644 +index 0000000000..2a15de8072 +--- /dev/null ++++ b/tools/grit/grit/testdata/structure_variables.html +@@ -0,0 +1,4 @@ ++

    [GREETING]!

    ++Some cool things are [THINGS]. ++Did you know that [EQUATION]? ++ +diff --git a/tools/grit/grit/testdata/substitute.grd b/tools/grit/grit/testdata/substitute.grd +new file mode 100644 +index 0000000000..95dcc56e1d +--- /dev/null ++++ b/tools/grit/grit/testdata/substitute.grd +@@ -0,0 +1,31 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Copyright 2008 Google Inc. All Rights Reserved. ++ ++ ++ Google Desktop News gadget ++[IDS_COPYRIGHT_GOOGLE_LONG] ++View news that is personalized based on the articles you read. ++ ++For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles. ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/substitute.xmb b/tools/grit/grit/testdata/substitute.xmb +new file mode 100644 +index 0000000000..e592069c8b +--- /dev/null ++++ b/tools/grit/grit/testdata/substitute.xmb +@@ -0,0 +1,10 @@ ++ ++ ++ ++© 2008 Google Inc. Med ensamrätt. ++Google Desktop News gadget ++ ++Se nyheter som är anpassade till dig, baserat på de artiklar du läser. ++ ++Om du t.ex. läser massor av sportnyheter kommer du att se fler sportartiklar. Om du inte läser tekniknyheter lika ofta ser du färre av dessa artiklar. ++ +diff --git a/tools/grit/grit/testdata/substitute_no_ids.grd b/tools/grit/grit/testdata/substitute_no_ids.grd +new file mode 100644 +index 0000000000..d569d1cacd +--- /dev/null ++++ b/tools/grit/grit/testdata/substitute_no_ids.grd +@@ -0,0 +1,31 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Copyright 2008 Google Inc. All Rights Reserved. ++ ++ ++ Google Desktop News gadget ++[IDS_COPYRIGHT_GOOGLE_LONG] ++View news that is personalized based on the articles you read. ++ ++For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles. ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/substitute_tmpl.grd b/tools/grit/grit/testdata/substitute_tmpl.grd +new file mode 100644 +index 0000000000..be7b601707 +--- /dev/null ++++ b/tools/grit/grit/testdata/substitute_tmpl.grd +@@ -0,0 +1,31 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Copyright 2008 Google Inc. All Rights Reserved. ++ ++ ++ Google Desktop News gadget ++[IDS_COPYRIGHT_GOOGLE_LONG] ++View news that is personalized based on the articles you read. ++ ++For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles. ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/test_css.css b/tools/grit/grit/testdata/test_css.css +new file mode 100644 +index 0000000000..55d5dd1770 +--- /dev/null ++++ b/tools/grit/grit/testdata/test_css.css +@@ -0,0 +1 @@ ++This is a test! +diff --git a/tools/grit/grit/testdata/test_html.html b/tools/grit/grit/testdata/test_html.html +new file mode 100644 +index 0000000000..55d5dd1770 +--- /dev/null ++++ b/tools/grit/grit/testdata/test_html.html +@@ -0,0 +1 @@ ++This is a test! +diff --git a/tools/grit/grit/testdata/test_js.js b/tools/grit/grit/testdata/test_js.js +new file mode 100644 +index 0000000000..55d5dd1770 +--- /dev/null ++++ b/tools/grit/grit/testdata/test_js.js +@@ -0,0 +1 @@ ++This is a test! +diff --git a/tools/grit/grit/testdata/test_svg.svg b/tools/grit/grit/testdata/test_svg.svg +new file mode 100644 +index 0000000000..55d5dd1770 +--- /dev/null ++++ b/tools/grit/grit/testdata/test_svg.svg +@@ -0,0 +1 @@ ++This is a test! +diff --git a/tools/grit/grit/testdata/test_text.txt b/tools/grit/grit/testdata/test_text.txt +new file mode 100644 +index 0000000000..55d5dd1770 +--- /dev/null ++++ b/tools/grit/grit/testdata/test_text.txt +@@ -0,0 +1 @@ ++This is a test! +diff --git a/tools/grit/grit/testdata/time_related.html b/tools/grit/grit/testdata/time_related.html +new file mode 100644 +index 0000000000..ee64b1665e +--- /dev/null ++++ b/tools/grit/grit/testdata/time_related.html +@@ -0,0 +1,11 @@ ++[HEADER] ++[CHROME] ++[NAV_PRE_POST] ++[$~MESSAGE~$]
    ++ ++[CONTENTS] ++

    ++ ++[NAV_PRE_POST] ++[FOOTER] ++ +diff --git a/tools/grit/grit/testdata/toolbar_about.html b/tools/grit/grit/testdata/toolbar_about.html +new file mode 100644 +index 0000000000..bb4b0eb355 +--- /dev/null ++++ b/tools/grit/grit/testdata/toolbar_about.html +@@ -0,0 +1,138 @@ ++ ++ ++ ++About Google Toolbar ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    ++ ++ ++ ++ ++ ++ ++
    ++
    Google Toolbar
    ++
    ++
    ++ ++ ++
    ++
    ++ ++
    ++
    ++
    ++ ++ ++ De parvis grandis acervus erit ++ ++ ++
    ++ ++ © 2006 Google ++ ++ ++
    ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/tools/grit/resource_ids b/tools/grit/grit/testdata/tools/grit/resource_ids +new file mode 100644 +index 0000000000..8a2b608df1 +--- /dev/null ++++ b/tools/grit/grit/testdata/tools/grit/resource_ids +@@ -0,0 +1,176 @@ ++# Copyright (c) 2011 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++# ++# This file is used to assign starting resource ids for resources and strings ++# used by Chromium. This is done to ensure that resource ids are unique ++# across all the grd files. If you are adding a new grd file, please add ++# a new entry to this file. ++# ++# The first entry in the file, SRCDIR, is special: It is a relative path from ++# this file to the base of your checkout. ++# ++# http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx says that the ++# range for IDR_ is 1 to 28,671 and the range for IDS_ is 1 to 32,767 and ++# common convention starts practical use of IDs at 100 or 101. ++{ ++ "SRCDIR": "../..", ++ ++ "chrome/browser/browser_resources.grd": { ++ "includes": [500], ++ }, ++ "chrome/browser/resources/component_extension_resources.grd": { ++ "includes": [1000], ++ }, ++ "chrome/browser/resources/net_internals_resources.grd": { ++ "includes": [1500], ++ }, ++ "chrome/browser/resources/shared_resources.grd": { ++ "includes": [2000], ++ }, ++ "chrome/common/common_resources.grd": { ++ "includes": [2500], ++ }, ++ "chrome/default_plugin/default_plugin_resources.grd": { ++ "includes": [3000], ++ }, ++ "chrome/renderer/renderer_resources.grd": { ++ "includes": [3500], ++ }, ++ "net/base/net_resources.grd": { ++ "includes": [4000], ++ }, ++ "webkit/glue/webkit_resources.grd": { ++ "includes": [4500], ++ }, ++ "webkit/tools/test_shell/test_shell_resources.grd": { ++ "includes": [5000], ++ }, ++ "ui/resources/ui_resources.grd": { ++ "includes": [5500], ++ }, ++ "chrome/app/theme/theme_resources.grd": { ++ "includes": [6000], ++ }, ++ "chrome_frame/resources/chrome_frame_resources.grd": { ++ "includes": [6500], ++ }, ++ # WebKit.grd can be in two different places depending on whether we are ++ # in a chromium checkout or a webkit-only checkout. ++ "third_party/WebKit/Source/WebKit/chromium/WebKit.grd": { ++ "includes": [7000], ++ }, ++ "WebKit.grd": { ++ "includes": [7000], ++ }, ++ ++ "ui/base/strings/app_locale_settings.grd": { ++ "META": {"join": 2}, ++ "messages": [7500], ++ }, ++ "chrome/app/resources/locale_settings.grd": { ++ "includes": [8000], ++ "messages": [8500], ++ }, ++ # These each start with the same resource id because we only use one ++ # file for each build (cros, linux, mac, or win). ++ "chrome/app/resources/locale_settings_cros.grd": { ++ "messages": [9000], ++ }, ++ "chrome/app/resources/locale_settings_linux.grd": { ++ "messages": [9000], ++ }, ++ "chrome/app/resources/locale_settings_mac.grd": { ++ "messages": [9000], ++ }, ++ "chrome/app/resources/locale_settings_win.grd": { ++ "messages": [9000], ++ }, ++ ++ "ui/base/strings/ui_strings.grd": { ++ "META": {"join": 4}, ++ "messages": [9500], ++ }, ++ # Chromium strings and Google Chrome strings must start at the same id. ++ # We only use one file depending on whether we're building Chromium or ++ # Google Chrome. ++ "chrome/app/chromium_strings.grd": { ++ "messages": [10000], ++ }, ++ "chrome/app/google_chrome_strings.grd": { ++ "messages": [10000], ++ }, ++ # Leave lots of space for generated_resources since it has most of our ++ # strings. ++ "chrome/app/generated_resources.grd": { ++ "META": {"join": 2}, ++ "structures": [10500], ++ "messages": [11000], ++ }, ++ # The chrome frame dialogs are also in generated_resources.grd so they ++ # get included by the translation console. We make sure that the ids ++ # for structures here are the same as for generated_resources.grd. ++ "chrome_frame/resources/chrome_frame_dialogs.grd": { ++ "structures": [10500], ++ "includes": [10750], ++ }, ++ "webkit/glue/inspector_strings.grd": { ++ "messages": [16000], ++ }, ++ "webkit/glue/webkit_strings.grd": { ++ "messages": [16500], ++ }, ++ ++ "chrome_frame/resources/chrome_frame_resources.grd": { ++ "includes": [17500], ++ "structures": [18000], ++ }, ++ ++ "ui/gfx/gfx_resources.grd": { ++ "includes": [18500], ++ }, ++ ++ "chrome/app/policy/policy_templates.grd": { ++ "structures": [19000], ++ "messages": [19010], ++ }, ++ ++ "chrome/browser/autofill/autofill_resources.grd": { ++ "messages": [19500], ++ }, ++ "chrome/browser/resources/sync_internals_resources.grd": { ++ "includes": [20000], ++ }, ++ # This file is generated during the build. ++ "<(SHARED_INTERMEDIATE_DIR)/devtools/devtools_resources.grd": { ++ "includes": [20500], ++ }, ++ # All standard and large theme resources should have the same IDs. ++ "chrome/app/theme/theme_resources_standard.grd": { ++ "includes": [21000], ++ }, ++ "chrome/app/theme/theme_resources_large.grd": { ++ "includes": [21000], ++ }, ++ # This file is generated during the build. ++ "chrome/browser/debugger/frontend/devtools_frontend_resources.grd": { ++ "META": {"join": 2}, ++ "includes": [21500], ++ }, ++ "cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd": { ++ "messages": [22500], ++ }, ++ "chrome/browser/resources/quota_internals_resources.grd": { ++ "includes": [23000], ++ }, ++ "chrome/browser/resources/workers_resources.grd": { ++ "includes": [23500], ++ }, ++ # All standard and large theme resources should have the same IDs. ++ "ui/resources/ui_resources_standard.grd": { ++ "includes": [24000], ++ }, ++ "ui/resources/ui_resources_large.grd": { ++ "includes": [24000], ++ }, ++} +diff --git a/tools/grit/grit/testdata/transl.rc b/tools/grit/grit/testdata/transl.rc +new file mode 100644 +index 0000000000..2f2595db3f +--- /dev/null ++++ b/tools/grit/grit/testdata/transl.rc +@@ -0,0 +1,56 @@ ++IDC_KLONKMENU MENU ++BEGIN ++ POPUP "&Skra" ++ BEGIN ++ MENUITEM "&Haetta", IDM_EXIT ++ MENUITEM "Thetta er ""Klonk"" sem eg fyla", ID_FILE_THISBE ++ POPUP "gonkurinn" ++ BEGIN ++ MENUITEM "Klonk && er [good]", ID_GONK_KLONKIS ++ END ++ END ++ POPUP "&Hjalp" ++ BEGIN ++ MENUITEM "&Um...", IDM_ABOUT ++ END ++END ++ ++IDD_ABOUTBOX DIALOGEX 22, 17, 230, 75 ++STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU ++CAPTION "Um Klonk" ++FONT 8, "System", 0, 0, 0x0 ++BEGIN ++ ICON IDI_KLONK,IDC_MYICON,14,9,20,20 ++ LTEXT "klonk utgafa ""jibbi"" 1.0",IDC_STATIC,49,10,119,8, ++ SS_NOPREFIX ++ LTEXT "Hofundarrettur (C) 2005",IDC_STATIC,49,20,119,8 ++ DEFPUSHBUTTON "I lagi",IDOK,195,6,30,11,WS_GROUP ++ CONTROL "Jack ""Black"" Daniels",IDC_RADIO1,"Button", ++ BS_AUTORADIOBUTTON,46,51,84,10 ++END ++ ++IDD_DIFFERENT_LENGTH_IN_TRANSL DIALOGEX 22, 17, 230, 75 ++STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU ++CAPTION "Bingobobbi" ++FONT 8, "System", 0, 0, 0x0 ++BEGIN ++ LTEXT "Howdie dodie!",IDC_STATIC,49,10,119,8,SS_NOPREFIX ++END ++ ++STRINGTABLE ++BEGIN ++ IDS_SIMPLE "Ein" ++ IDS_PLACEHOLDER "%s Vogeln" ++ IDS_PLACEHOLDERS "%d von %d" ++ // Shouldn't be part of translations list because the translation is ++ // reordered so placeholder fixup fails ++ IDS_REORDERED_PLACEHOLDERS "$2 auf $1" ++ IDS_CHANGED "Dass war die alte Version" ++ IDS_TWIN_1 "Hallo" ++ IDS_TWIN_2 "Hallo" ++ IDS_NOT_TRANSLATEABLE ":" ++ IDS_LONGER_TRANSLATED "Dokument $1 ist entfernt worden" ++ IDS_NO_LONGER_USED "Nicht verwendet" ++ IDS_DIFFERENT_TWIN_1 "Howdie" ++ IDS_DIFFERENT_TWIN_2 "Hallo sagt man" ++END +diff --git a/tools/grit/grit/testdata/versions.html b/tools/grit/grit/testdata/versions.html +new file mode 100644 +index 0000000000..d1f40d8d72 +--- /dev/null ++++ b/tools/grit/grit/testdata/versions.html +@@ -0,0 +1,7 @@ ++[HEADER] ++ ++[TOP_CHROME] ++[CONTENTS] ++ ++[NEXT_PREV] ++[FOOTER] +diff --git a/tools/grit/grit/testdata/whitelist.txt b/tools/grit/grit/testdata/whitelist.txt +new file mode 100644 +index 0000000000..5b3aca40b5 +--- /dev/null ++++ b/tools/grit/grit/testdata/whitelist.txt +@@ -0,0 +1,4 @@ ++IDS_MESSAGE_WHITELISTED ++IDR_STRUCTURE_WHITELISTED ++IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED ++IDR_INCLUDE_WHITELISTED +diff --git a/tools/grit/grit/testdata/whitelist_resources.grd b/tools/grit/grit/testdata/whitelist_resources.grd +new file mode 100644 +index 0000000000..9925688ff5 +--- /dev/null ++++ b/tools/grit/grit/testdata/whitelist_resources.grd +@@ -0,0 +1,54 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tools/grit/grit/testdata/whitelist_strings.grd b/tools/grit/grit/testdata/whitelist_strings.grd +new file mode 100644 +index 0000000000..df80f5fd32 +--- /dev/null ++++ b/tools/grit/grit/testdata/whitelist_strings.grd +@@ -0,0 +1,23 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Whitelisted. ++ ++ ++ Not whitelisted. ++ ++ ++ ++ +diff --git a/tools/grit/grit/tool/__init__.py b/tools/grit/grit/tool/__init__.py +new file mode 100644 +index 0000000000..cc455b36e7 +--- /dev/null ++++ b/tools/grit/grit/tool/__init__.py +@@ -0,0 +1,8 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Package grit.tool ++''' ++ ++pass +diff --git a/tools/grit/grit/tool/android2grd.py b/tools/grit/grit/tool/android2grd.py +new file mode 100644 +index 0000000000..005297bafe +--- /dev/null ++++ b/tools/grit/grit/tool/android2grd.py +@@ -0,0 +1,484 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""The 'grit android2grd' tool.""" ++ ++from __future__ import print_function ++ ++import getopt ++import os.path ++import sys ++from xml.dom import Node ++import xml.dom.minidom ++ ++import six ++from six import StringIO ++ ++import grit.node.empty ++from grit.node import node_io ++from grit.node import message ++ ++from grit.tool import interface ++ ++from grit import grd_reader ++from grit import lazy_re ++from grit import tclib ++ ++ ++# The name of a string in strings.xml ++_STRING_NAME = lazy_re.compile(r'[a-z0-9_]+\Z') ++ ++# A string's character limit in strings.xml ++_CHAR_LIMIT = lazy_re.compile(r'\[CHAR-LIMIT=(\d+)\]') ++ ++# Finds String.Format() style format specifiers such as "%-5.2f". ++_FORMAT_SPECIFIER = lazy_re.compile( ++ r'%' ++ r'([1-9][0-9]*\$|<)?' # argument_index ++ r'([-#+ 0,(]*)' # flags ++ r'([0-9]+)?' # width ++ r'(\.[0-9]+)?' # precision ++ r'([bBhHsScCdoxXeEfgGaAtT%n])') # conversion ++ ++ ++class Android2Grd(interface.Tool): ++ """Tool for converting Android string.xml files into chrome Grd files. ++ ++Usage: grit [global options] android2grd [OPTIONS] STRINGS_XML ++ ++The Android2Grd tool will convert an Android strings.xml file (whose path is ++specified by STRINGS_XML) and create a chrome style grd file containing the ++relevant information. ++ ++Because grd documents are much richer than strings.xml documents we supplement ++the information required by grds using OPTIONS with sensible defaults. ++ ++OPTIONS may be any of the following: ++ ++ --name FILENAME Specify the base FILENAME. This should be without ++ any file type suffix. By default ++ "chrome_android_strings" will be used. ++ ++ --languages LANGUAGES Comma separated list of ISO language codes (e.g. ++ en-US, en-GB, ru, zh-CN). These codes will be used ++ to determine the names of resource and translations ++ files that will be declared by the output grd file. ++ ++ --grd-dir GRD_DIR Specify where the resultant grd file ++ (FILENAME.grd) should be output. By default this ++ will be the present working directory. ++ ++ --header-dir HEADER_DIR Specify the location of the directory where grit ++ generated C++ headers (whose name will be ++ FILENAME.h) will be placed. Use an empty string to ++ disable rc generation. Default: empty. ++ ++ --rc-dir RC_DIR Specify the directory where resource files will ++ be located relative to grit build's output ++ directory. Use an empty string to disable rc ++ generation. Default: empty. ++ ++ --xml-dir XML_DIR Specify where to place localized strings.xml files ++ relative to grit build's output directory. For each ++ language xx a values-xx/strings.xml file will be ++ generated. Use an empty string to disable ++ strings.xml generation. Default: '.'. ++ ++ --xtb-dir XTB_DIR Specify where the xtb files containing translations ++ will be located relative to the grd file. Default: ++ '.'. ++""" ++ ++ _NAME_FLAG = 'name' ++ _LANGUAGES_FLAG = 'languages' ++ _GRD_DIR_FLAG = 'grd-dir' ++ _RC_DIR_FLAG = 'rc-dir' ++ _HEADER_DIR_FLAG = 'header-dir' ++ _XTB_DIR_FLAG = 'xtb-dir' ++ _XML_DIR_FLAG = 'xml-dir' ++ ++ def __init__(self): ++ self.name = 'chrome_android_strings' ++ self.languages = [] ++ self.grd_dir = '.' ++ self.rc_dir = None ++ self.xtb_dir = '.' ++ self.xml_res_dir = '.' ++ self.header_dir = None ++ ++ def ShortDescription(self): ++ """Returns a short description of the Android2Grd tool. ++ ++ Overridden from grit.interface.Tool ++ ++ Returns: ++ A string containing a short description of the android2grd tool. ++ """ ++ return 'Converts Android string.xml files into Chrome grd files.' ++ ++ def ParseOptions(self, args): ++ """Set this objects and return all non-option arguments.""" ++ flags = [ ++ Android2Grd._NAME_FLAG, ++ Android2Grd._LANGUAGES_FLAG, ++ Android2Grd._GRD_DIR_FLAG, ++ Android2Grd._RC_DIR_FLAG, ++ Android2Grd._HEADER_DIR_FLAG, ++ Android2Grd._XTB_DIR_FLAG, ++ Android2Grd._XML_DIR_FLAG, ] ++ (opts, args) = getopt.getopt( ++ args, None, ['%s=' % o for o in flags] + ['help']) ++ ++ for key, val in opts: ++ # Get rid of the preceding hypens. ++ k = key[2:] ++ if k == Android2Grd._NAME_FLAG: ++ self.name = val ++ elif k == Android2Grd._LANGUAGES_FLAG: ++ self.languages = val.split(',') ++ elif k == Android2Grd._GRD_DIR_FLAG: ++ self.grd_dir = val ++ elif k == Android2Grd._RC_DIR_FLAG: ++ self.rc_dir = val ++ elif k == Android2Grd._HEADER_DIR_FLAG: ++ self.header_dir = val ++ elif k == Android2Grd._XTB_DIR_FLAG: ++ self.xtb_dir = val ++ elif k == Android2Grd._XML_DIR_FLAG: ++ self.xml_res_dir = val ++ elif k == 'help': ++ self.ShowUsage() ++ sys.exit(0) ++ return args ++ ++ def Run(self, opts, args): ++ """Runs the Android2Grd tool. ++ ++ Inherited from grit.interface.Tool. ++ ++ Args: ++ opts: List of string arguments that should be parsed. ++ args: String containing the path of the strings.xml file to be converted. ++ """ ++ args = self.ParseOptions(args) ++ if len(args) != 1: ++ print('Tool requires one argument, the path to the Android ' ++ 'strings.xml resource file to be converted.') ++ return 2 ++ self.SetOptions(opts) ++ ++ android_path = args[0] ++ ++ # Read and parse the Android strings.xml file. ++ with open(android_path) as android_file: ++ android_dom = xml.dom.minidom.parse(android_file) ++ ++ # Do the hard work -- convert the Android dom to grd file contents. ++ grd_dom = self.AndroidDomToGrdDom(android_dom) ++ grd_string = six.text_type(grd_dom) ++ ++ # Write the grd string to a file in grd_dir. ++ grd_filename = self.name + '.grd' ++ grd_path = os.path.join(self.grd_dir, grd_filename) ++ with open(grd_path, 'w') as grd_file: ++ grd_file.write(grd_string) ++ ++ def AndroidDomToGrdDom(self, android_dom): ++ """Converts a strings.xml DOM into a DOM representing the contents of ++ a grd file. ++ ++ Args: ++ android_dom: A xml.dom.Document containing the contents of the Android ++ string.xml document. ++ Returns: ++ The DOM for the grd xml document produced by converting the Android DOM. ++ """ ++ ++ # Start with a basic skeleton for the .grd file. ++ root = grd_reader.Parse(StringIO( ++ ''' ++ ++ ++ ++ ++ ++ ++ '''), dir='.') ++ outputs = root.children[0] ++ translations = root.children[1] ++ messages = root.children[2].children[0] ++ assert (isinstance(messages, grit.node.empty.MessagesNode) and ++ isinstance(translations, grit.node.empty.TranslationsNode) and ++ isinstance(outputs, grit.node.empty.OutputsNode)) ++ ++ if self.header_dir: ++ cpp_header = self.__CreateCppHeaderOutputNode(outputs, self.header_dir) ++ for lang in self.languages: ++ # Create an output element for each language. ++ if self.rc_dir: ++ self.__CreateRcOutputNode(outputs, lang, self.rc_dir) ++ if self.xml_res_dir: ++ self.__CreateAndroidXmlOutputNode(outputs, lang, self.xml_res_dir) ++ if lang != 'en': ++ self.__CreateFileNode(translations, lang) ++ # Convert all the strings.xml strings into grd messages. ++ self.__CreateMessageNodes(messages, android_dom.documentElement) ++ ++ return root ++ ++ def __CreateMessageNodes(self, messages, resources): ++ """Creates the elements and adds them as children of . ++ ++ Args: ++ messages: the element in the strings.xml dom. ++ resources: the element in the grd dom. ++ """ ++ # elements contain the definition of the resource. ++ # The description of a element is contained within the comment ++ # node element immediately preceeding the string element in question. ++ description = '' ++ for child in resources.childNodes: ++ if child.nodeType == Node.COMMENT_NODE: ++ # Remove leading/trailing whitespace; collapse consecutive whitespaces. ++ description = ' '.join(child.data.split()) ++ elif child.nodeType == Node.ELEMENT_NODE: ++ if child.tagName != 'string': ++ print('Warning: ignoring unknown tag <%s>' % child.tagName) ++ else: ++ translatable = self.IsTranslatable(child) ++ raw_name = child.getAttribute('name') ++ if not _STRING_NAME.match(raw_name): ++ print('Error: illegal string name: %s' % raw_name) ++ grd_name = 'IDS_' + raw_name.upper() ++ # Transform the node contents into a tclib.Message, taking ++ # care to handle whitespace transformations and escaped characters, ++ # and coverting placeholders into placeholders. ++ msg = self.CreateTclibMessage(child) ++ msg_node = self.__CreateMessageNode(messages, grd_name, description, ++ msg, translatable) ++ messages.AddChild(msg_node) ++ # Reset the description once a message has been parsed. ++ description = '' ++ ++ def CreateTclibMessage(self, android_string): ++ """Transforms a element from strings.xml into a tclib.Message. ++ ++ Interprets whitespace, quotes, and escaped characters in the android_string ++ according to Android's formatting and styling rules for strings. Also ++ converts placeholders into placeholders, e.g.: ++ ++ %s ++ becomes ++ google.com%s ++ ++ Returns: ++ The tclib.Message. ++ """ ++ msg = tclib.Message() ++ current_text = '' # Accumulated text that hasn't yet been added to msg. ++ nodes = android_string.childNodes ++ ++ for i, node in enumerate(nodes): ++ # Handle text nodes. ++ if node.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): ++ current_text += node.data ++ ++ # Handle and other tags. ++ elif node.nodeType == Node.ELEMENT_NODE: ++ if node.tagName == 'xliff:g': ++ assert node.hasAttribute('id'), 'missing id: ' + node.data() ++ placeholder_id = node.getAttribute('id') ++ placeholder_text = self.__FormatPlaceholderText(node) ++ placeholder_example = node.getAttribute('example') ++ if not placeholder_example: ++ print('Info: placeholder does not contain an example: %s' % ++ node.toxml()) ++ placeholder_example = placeholder_id.upper() ++ msg.AppendPlaceholder(tclib.Placeholder(placeholder_id, ++ placeholder_text, placeholder_example)) ++ else: ++ print('Warning: removing tag <%s> which must be inside a ' ++ 'placeholder: %s' % (node.tagName, node.toxml())) ++ msg.AppendText(self.__FormatPlaceholderText(node)) ++ ++ # Handle other nodes. ++ elif node.nodeType != Node.COMMENT_NODE: ++ assert False, 'Unknown node type: %s' % node.nodeType ++ ++ is_last_node = (i == len(nodes) - 1) ++ if (current_text and ++ (is_last_node or nodes[i + 1].nodeType == Node.ELEMENT_NODE)): ++ # For messages containing just text and comments (no xml tags) Android ++ # strips leading and trailing whitespace. We mimic that behavior. ++ if not msg.GetContent() and is_last_node: ++ current_text = current_text.strip() ++ msg.AppendText(self.__FormatAndroidString(current_text)) ++ current_text = '' ++ ++ return msg ++ ++ def __FormatAndroidString(self, android_string, inside_placeholder=False): ++ r"""Returns android_string formatted for a .grd file. ++ ++ * Collapses consecutive whitespaces, except when inside double-quotes. ++ * Replaces \\, \n, \t, \", \' with \, newline, tab, ", '. ++ """ ++ backslash_map = {'\\' : '\\', 'n' : '\n', 't' : '\t', '"' : '"', "'" : "'"} ++ is_quoted_section = False # True when we're inside double quotes. ++ is_backslash_sequence = False # True after seeing an unescaped backslash. ++ prev_char = '' ++ output = [] ++ for c in android_string: ++ if is_backslash_sequence: ++ # Unescape \\, \n, \t, \", and \'. ++ assert c in backslash_map, 'Illegal escape sequence: \\%s' % c ++ output.append(backslash_map[c]) ++ is_backslash_sequence = False ++ elif c == '\\': ++ is_backslash_sequence = True ++ elif c.isspace() and not is_quoted_section: ++ # Turn whitespace into ' ' and collapse consecutive whitespaces. ++ if not prev_char.isspace(): ++ output.append(' ') ++ elif c == '"': ++ is_quoted_section = not is_quoted_section ++ else: ++ output.append(c) ++ prev_char = c ++ output = ''.join(output) ++ ++ if is_quoted_section: ++ print('Warning: unbalanced quotes in string: %s' % android_string) ++ ++ if is_backslash_sequence: ++ print('Warning: trailing backslash in string: %s' % android_string) ++ ++ # Check for format specifiers outside of placeholder tags. ++ if not inside_placeholder: ++ format_specifier = _FORMAT_SPECIFIER.search(output) ++ if format_specifier: ++ print('Warning: format specifiers are not inside a placeholder ' ++ ' tag: %s' % output) ++ ++ return output ++ ++ def __FormatPlaceholderText(self, placeholder_node): ++ """Returns the text inside of an placeholder node.""" ++ text = [] ++ for childNode in placeholder_node.childNodes: ++ if childNode.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): ++ text.append(childNode.data) ++ elif childNode.nodeType != Node.COMMENT_NODE: ++ assert False, 'Unknown node type in ' + placeholder_node.toxml() ++ return self.__FormatAndroidString(''.join(text), inside_placeholder=True) ++ ++ def __CreateMessageNode(self, messages_node, grd_name, description, msg, ++ translatable): ++ """Creates and initializes a element. ++ ++ Message elements correspond to Android elements in that they ++ declare a string resource along with a programmatic id. ++ """ ++ if not description: ++ print('Warning: no description for %s' % grd_name) ++ # Check that we actually fit within the character limit we've specified. ++ match = _CHAR_LIMIT.search(description) ++ if match: ++ char_limit = int(match.group(1)) ++ msg_content = msg.GetRealContent() ++ if len(msg_content) > char_limit: ++ print('Warning: char-limit for %s is %d, but length is %d: %s' % ++ (grd_name, char_limit, len(msg_content), msg_content)) ++ return message.MessageNode.Construct(parent=messages_node, ++ name=grd_name, ++ message=msg, ++ desc=description, ++ translateable=translatable) ++ ++ def __CreateFileNode(self, translations_node, lang): ++ """Creates and initializes the elements. ++ ++ File elements provide information on the location of translation files ++ (xtbs) ++ """ ++ xtb_file = os.path.normpath(os.path.join( ++ self.xtb_dir, '%s_%s.xtb' % (self.name, lang))) ++ fnode = node_io.FileNode() ++ fnode.StartParsing(u'file', translations_node) ++ fnode.HandleAttribute('path', xtb_file) ++ fnode.HandleAttribute('lang', lang) ++ fnode.EndParsing() ++ translations_node.AddChild(fnode) ++ return fnode ++ ++ def __CreateCppHeaderOutputNode(self, outputs_node, header_dir): ++ """Creates the element corresponding to the generated c header.""" ++ header_file_name = os.path.join(header_dir, self.name + '.h') ++ header_node = node_io.OutputNode() ++ header_node.StartParsing(u'output', outputs_node) ++ header_node.HandleAttribute('filename', header_file_name) ++ header_node.HandleAttribute('type', 'rc_header') ++ emit_node = node_io.EmitNode() ++ emit_node.StartParsing(u'emit', header_node) ++ emit_node.HandleAttribute('emit_type', 'prepend') ++ emit_node.EndParsing() ++ header_node.AddChild(emit_node) ++ header_node.EndParsing() ++ outputs_node.AddChild(header_node) ++ return header_node ++ ++ def __CreateRcOutputNode(self, outputs_node, lang, rc_dir): ++ """Creates the element corresponding to various rc file output.""" ++ rc_file_name = self.name + '_' + lang + ".rc" ++ rc_path = os.path.join(rc_dir, rc_file_name) ++ node = node_io.OutputNode() ++ node.StartParsing(u'output', outputs_node) ++ node.HandleAttribute('filename', rc_path) ++ node.HandleAttribute('lang', lang) ++ node.HandleAttribute('type', 'rc_all') ++ node.EndParsing() ++ outputs_node.AddChild(node) ++ return node ++ ++ def __CreateAndroidXmlOutputNode(self, outputs_node, locale, xml_res_dir): ++ """Creates the element corresponding to various rc file output.""" ++ # Need to check to see if the locale has a region, e.g. the GB in en-GB. ++ # When a locale has a region Android expects the region to be prefixed ++ # with an 'r'. For example for en-GB Android expects a values-en-rGB ++ # directory. Also, Android expects nb, tl, in, iw, ji as the language ++ # codes for Norwegian, Tagalog/Filipino, Indonesian, Hebrew, and Yiddish: ++ # http://developer.android.com/reference/java/util/Locale.html ++ if locale == 'es-419': ++ android_locale = 'es-rUS' ++ else: ++ android_lang, dash, region = locale.partition('-') ++ lang_map = {'no': 'nb', 'fil': 'tl', 'id': 'in', 'he': 'iw', 'yi': 'ji'} ++ android_lang = lang_map.get(android_lang, android_lang) ++ android_locale = android_lang + ('-r' + region if region else '') ++ values = 'values-' + android_locale if android_locale != 'en' else 'values' ++ xml_path = os.path.normpath(os.path.join( ++ xml_res_dir, values, 'strings.xml')) ++ ++ node = node_io.OutputNode() ++ node.StartParsing(u'output', outputs_node) ++ node.HandleAttribute('filename', xml_path) ++ node.HandleAttribute('lang', locale) ++ node.HandleAttribute('type', 'android') ++ node.EndParsing() ++ outputs_node.AddChild(node) ++ return node ++ ++ def IsTranslatable(self, android_string): ++ """Determines if a element is a candidate for translation. ++ ++ A element is by default translatable unless otherwise marked. ++ """ ++ if android_string.hasAttribute('translatable'): ++ value = android_string.getAttribute('translatable').lower() ++ if value not in ('true', 'false'): ++ print('Warning: translatable attribute has invalid value: %s' % value) ++ return value == 'true' ++ else: ++ return True +diff --git a/tools/grit/grit/tool/android2grd_unittest.py b/tools/grit/grit/tool/android2grd_unittest.py +new file mode 100644 +index 0000000000..a6934a707c +--- /dev/null ++++ b/tools/grit/grit/tool/android2grd_unittest.py +@@ -0,0 +1,181 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grit.tool.android2grd''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++import xml.dom.minidom ++ ++from grit import util ++from grit.node import empty ++from grit.node import message ++from grit.node import misc ++from grit.node import node_io ++from grit.tool import android2grd ++ ++ ++class Android2GrdUnittest(unittest.TestCase): ++ ++ def __Parse(self, xml_string): ++ return xml.dom.minidom.parseString(xml_string).childNodes[0] ++ ++ def testCreateTclibMessage(self): ++ tool = android2grd.Android2Grd() ++ msg = tool.CreateTclibMessage(self.__Parse(r''' ++ A simple string''')) ++ self.assertEqual(msg.GetRealContent(), 'A simple string') ++ msg = tool.CreateTclibMessage(self.__Parse(r''' ++ ++ Strip leading/trailing whitespace ++ ''')) ++ self.assertEqual(msg.GetRealContent(), 'Strip leading/trailing whitespace') ++ msg = tool.CreateTclibMessage(self.__Parse(r''' ++ Fold multiple spaces''')) ++ self.assertEqual(msg.GetRealContent(), 'Fold multiple spaces') ++ msg = tool.CreateTclibMessage(self.__Parse(r''' ++ Retain \n escaped\t spaces''')) ++ self.assertEqual(msg.GetRealContent(), 'Retain \n escaped\t spaces') ++ msg = tool.CreateTclibMessage(self.__Parse(r''' ++ " Quotes preserve ++ whitespace" but only for "enclosed elements " ++ ''')) ++ self.assertEqual(msg.GetRealContent(), ''' Quotes preserve ++ whitespace but only for enclosed elements ''') ++ msg = tool.CreateTclibMessage(self.__Parse( ++ r'''Escaped characters: \"\'\\\t\n''' ++ '')) ++ self.assertEqual(msg.GetRealContent(), '''Escaped characters: "'\\\t\n''') ++ msg = tool.CreateTclibMessage(self.__Parse( ++ '' ++ 'Open %s?' ++ '')) ++ self.assertEqual(msg.GetRealContent(), 'Open %s?') ++ self.assertEqual(len(msg.GetPlaceholders()), 1) ++ self.assertEqual(msg.GetPlaceholders()[0].presentation, 'FILENAME') ++ self.assertEqual(msg.GetPlaceholders()[0].original, '%s') ++ self.assertEqual(msg.GetPlaceholders()[0].example, 'internet.html') ++ msg = tool.CreateTclibMessage(self.__Parse(r''' ++ Contains a comment ++ ''')) ++ self.assertEqual(msg.GetRealContent(), 'Contains a comment') ++ ++ def testIsTranslatable(self): ++ tool = android2grd.Android2Grd() ++ string_el = self.__Parse('Hi') ++ self.assertTrue(tool.IsTranslatable(string_el)) ++ string_el = self.__Parse( ++ 'Hi') ++ self.assertTrue(tool.IsTranslatable(string_el)) ++ string_el = self.__Parse( ++ 'Hi') ++ self.assertFalse(tool.IsTranslatable(string_el)) ++ ++ def __ParseAndroidXml(self, options = []): ++ tool = android2grd.Android2Grd() ++ ++ tool.ParseOptions(options) ++ ++ android_path = util.PathFromRoot('grit/testdata/android.xml') ++ with open(android_path) as android_file: ++ android_dom = xml.dom.minidom.parse(android_file) ++ ++ grd = tool.AndroidDomToGrdDom(android_dom) ++ self.assertTrue(isinstance(grd, misc.GritNode)) ++ ++ return grd ++ ++ def testAndroidDomToGrdDom(self): ++ grd = self.__ParseAndroidXml(['--languages', 'en-US,en-GB,ru']) ++ ++ # Check that the structure of the GritNode is as expected. ++ messages = grd.GetChildrenOfType(message.MessageNode) ++ translations = grd.GetChildrenOfType(empty.TranslationsNode) ++ files = grd.GetChildrenOfType(node_io.FileNode) ++ ++ self.assertEqual(len(translations), 1) ++ self.assertEqual(len(files), 3) ++ self.assertEqual(len(messages), 5) ++ ++ # Check that a message node is constructed correctly. ++ msg = [x for x in messages if x.GetTextualIds()[0] == 'IDS_PLACEHOLDERS'] ++ self.assertTrue(msg) ++ msg = msg[0] ++ ++ self.assertTrue(msg.IsTranslateable()) ++ self.assertEqual(msg.attrs["desc"], "A string with placeholder.") ++ ++ def testTranslatableAttribute(self): ++ grd = self.__ParseAndroidXml([]) ++ messages = grd.GetChildrenOfType(message.MessageNode) ++ msgs = [x for x in messages if x.GetTextualIds()[0] == 'IDS_CONSTANT'] ++ self.assertTrue(msgs) ++ self.assertFalse(msgs[0].IsTranslateable()) ++ ++ def testTranslations(self): ++ grd = self.__ParseAndroidXml(['--languages', 'en-US,en-GB,ru,id']) ++ ++ files = grd.GetChildrenOfType(node_io.FileNode) ++ us_file = [x for x in files if x.attrs['lang'] == 'en-US'] ++ self.assertTrue(us_file) ++ self.assertEqual(us_file[0].GetInputPath(), ++ 'chrome_android_strings_en-US.xtb') ++ ++ id_file = [x for x in files if x.attrs['lang'] == 'id'] ++ self.assertTrue(id_file) ++ self.assertEqual(id_file[0].GetInputPath(), ++ 'chrome_android_strings_id.xtb') ++ ++ def testOutputs(self): ++ grd = self.__ParseAndroidXml(['--languages', 'en-US,ru,id', ++ '--rc-dir', 'rc/dir', ++ '--header-dir', 'header/dir', ++ '--xtb-dir', 'xtb/dir', ++ '--xml-dir', 'xml/dir']) ++ ++ outputs = grd.GetChildrenOfType(node_io.OutputNode) ++ self.assertEqual(len(outputs), 7) ++ ++ header_outputs = [x for x in outputs if x.GetType() == 'rc_header'] ++ rc_outputs = [x for x in outputs if x.GetType() == 'rc_all'] ++ xml_outputs = [x for x in outputs if x.GetType() == 'android'] ++ ++ self.assertEqual(len(header_outputs), 1) ++ self.assertEqual(len(rc_outputs), 3) ++ self.assertEqual(len(xml_outputs), 3) ++ ++ # The header node should have an "" child and the proper filename. ++ self.assertTrue(header_outputs[0].GetChildrenOfType(node_io.EmitNode)) ++ self.assertEqual(util.normpath(header_outputs[0].GetFilename()), ++ util.normpath('header/dir/chrome_android_strings.h')) ++ ++ id_rc = [x for x in rc_outputs if x.GetLanguage() == 'id'] ++ id_xml = [x for x in xml_outputs if x.GetLanguage() == 'id'] ++ self.assertTrue(id_rc) ++ self.assertTrue(id_xml) ++ self.assertEqual(util.normpath(id_rc[0].GetFilename()), ++ util.normpath('rc/dir/chrome_android_strings_id.rc')) ++ self.assertEqual(util.normpath(id_xml[0].GetFilename()), ++ util.normpath('xml/dir/values-in/strings.xml')) ++ ++ us_rc = [x for x in rc_outputs if x.GetLanguage() == 'en-US'] ++ us_xml = [x for x in xml_outputs if x.GetLanguage() == 'en-US'] ++ self.assertTrue(us_rc) ++ self.assertTrue(us_xml) ++ self.assertEqual(util.normpath(us_rc[0].GetFilename()), ++ util.normpath('rc/dir/chrome_android_strings_en-US.rc')) ++ self.assertEqual(util.normpath(us_xml[0].GetFilename()), ++ util.normpath('xml/dir/values-en-rUS/strings.xml')) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py +new file mode 100644 +index 0000000000..204592bf0d +--- /dev/null ++++ b/tools/grit/grit/tool/build.py +@@ -0,0 +1,556 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''The 'grit build' tool. ++''' ++ ++from __future__ import print_function ++ ++import codecs ++import filecmp ++import getopt ++import gzip ++import os ++import shutil ++import sys ++ ++import six ++ ++from grit import grd_reader ++from grit import shortcuts ++from grit import util ++from grit.format import minifier ++from grit.node import brotli_util ++from grit.node import include ++from grit.node import message ++from grit.node import structure ++from grit.tool import interface ++ ++ ++# It would be cleaner to have each module register itself, but that would ++# require importing all of them on every run of GRIT. ++'''Map from node types to modules under grit.format.''' ++_format_modules = { ++ 'android': 'android_xml', ++ 'c_format': 'c_format', ++ 'chrome_messages_json': 'chrome_messages_json', ++ 'chrome_messages_json_gzip': 'chrome_messages_json', ++ 'data_package': 'data_pack', ++ 'policy_templates': 'policy_templates_json', ++ 'rc_all': 'rc', ++ 'rc_header': 'rc_header', ++ 'rc_nontranslateable': 'rc', ++ 'rc_translateable': 'rc', ++ 'resource_file_map_source': 'resource_map', ++ 'resource_map_header': 'resource_map', ++ 'resource_map_source': 'resource_map', ++} ++ ++def GetFormatter(type): ++ modulename = 'grit.format.' + _format_modules[type] ++ __import__(modulename) ++ module = sys.modules[modulename] ++ try: ++ return module.Format ++ except AttributeError: ++ return module.GetFormatter(type) ++ ++ ++class RcBuilder(interface.Tool): ++ '''A tool that builds RC files and resource header files for compilation. ++ ++Usage: grit build [-o OUTPUTDIR] [-D NAME[=VAL]]* ++ ++All output options for this tool are specified in the input file (see ++'grit help' for details on how to specify the input file - it is a global ++option). ++ ++Options: ++ ++ -a FILE Assert that the given file is an output. There can be ++ multiple "-a" flags listed for multiple outputs. If a "-a" ++ or "--assert-file-list" argument is present, then the list ++ of asserted files must match the output files or the tool ++ will fail. The use-case is for the build system to maintain ++ separate lists of output files and to catch errors if the ++ build system's list and the grit list are out-of-sync. ++ ++ --assert-file-list Provide a file listing multiple asserted output files. ++ There is one file name per line. This acts like specifying ++ each file with "-a" on the command line, but without the ++ possibility of running into OS line-length limits for very ++ long lists. ++ ++ -o OUTPUTDIR Specify what directory output paths are relative to. ++ Defaults to the current directory. ++ ++ -p FILE Specify a file containing a pre-determined mapping from ++ resource names to resource ids which will be used to assign ++ resource ids to those resources. Resources not found in this ++ file will be assigned ids normally. The motivation is to run ++ your app's startup and have it dump the resources it loads, ++ and then pass these via this flag. This will pack startup ++ resources together, thus reducing paging while all other ++ resources are unperturbed. The file should have the format: ++ RESOURCE_ONE_NAME 123 ++ RESOURCE_TWO_NAME 124 ++ ++ -D NAME[=VAL] Specify a C-preprocessor-like define NAME with optional ++ value VAL (defaults to 1) which will be used to control ++ conditional inclusion of resources. ++ ++ -E NAME=VALUE Set environment variable NAME to VALUE (within grit). ++ ++ -f FIRSTIDSFILE Path to a python file that specifies the first id of ++ value to use for resources. A non-empty value here will ++ override the value specified in the node's ++ first_ids_file. ++ ++ -w WHITELISTFILE Path to a file containing the string names of the ++ resources to include. Anything not listed is dropped. ++ ++ -t PLATFORM Specifies the platform the build is targeting; defaults ++ to the value of sys.platform. The value provided via this ++ flag should match what sys.platform would report for your ++ target platform; see grit.node.base.EvaluateCondition. ++ ++ --whitelist-support ++ Generate code to support extracting a resource whitelist ++ from executables. ++ ++ --write-only-new flag ++ If flag is non-0, write output files to a temporary file ++ first, and copy it to the real output only if the new file ++ is different from the old file. This allows some build ++ systems to realize that dependent build steps might be ++ unnecessary, at the cost of comparing the output data at ++ grit time. ++ ++ --depend-on-stamp ++ If specified along with --depfile and --depdir, the depfile ++ generated will depend on a stampfile instead of the first ++ output in the input .grd file. ++ ++ --js-minifier A command to run the Javascript minifier. If not set then ++ Javascript won't be minified. The command should read the ++ original Javascript from standard input, and output the ++ minified Javascript to standard output. A non-zero exit ++ status will be taken as indicating failure. ++ ++ --css-minifier A command to run the CSS minifier. If not set then CSS won't ++ be minified. The command should read the original CSS from ++ standard input, and output the minified CSS to standard ++ output. A non-zero exit status will be taken as indicating ++ failure. ++ ++ --brotli The full path to the brotli executable generated by ++ third_party/brotli/BUILD.gn, required if any entries use ++ compress="brotli". ++ ++Conditional inclusion of resources only affects the output of files which ++control which resources get linked into a binary, e.g. it affects .rc files ++meant for compilation but it does not affect resource header files (that define ++IDs). This helps ensure that values of IDs stay the same, that all messages ++are exported to translation interchange files (e.g. XMB files), etc. ++''' ++ ++ def ShortDescription(self): ++ return 'A tool that builds RC files for compilation.' ++ ++ def Run(self, opts, args): ++ brotli_util.SetBrotliCommand(None) ++ os.environ['cwd'] = os.getcwd() ++ self.output_directory = '.' ++ first_ids_file = None ++ predetermined_ids_file = None ++ whitelist_filenames = [] ++ assert_output_files = [] ++ target_platform = None ++ depfile = None ++ depdir = None ++ whitelist_support = False ++ write_only_new = False ++ depend_on_stamp = False ++ js_minifier = None ++ css_minifier = None ++ replace_ellipsis = True ++ (own_opts, args) = getopt.getopt( ++ args, 'a:p:o:D:E:f:w:t:', ++ ('depdir=', 'depfile=', 'assert-file-list=', 'help', ++ 'output-all-resource-defines', 'no-output-all-resource-defines', ++ 'no-replace-ellipsis', 'depend-on-stamp', 'js-minifier=', ++ 'css-minifier=', 'write-only-new=', 'whitelist-support', 'brotli=')) ++ for (key, val) in own_opts: ++ if key == '-a': ++ assert_output_files.append(val) ++ elif key == '--assert-file-list': ++ with open(val) as f: ++ assert_output_files += f.read().splitlines() ++ elif key == '-o': ++ self.output_directory = val ++ elif key == '-D': ++ name, val = util.ParseDefine(val) ++ self.defines[name] = val ++ elif key == '-E': ++ (env_name, env_value) = val.split('=', 1) ++ os.environ[env_name] = env_value ++ elif key == '-f': ++ # TODO(joi@chromium.org): Remove this override once change ++ # lands in WebKit.grd to specify the first_ids_file in the ++ # .grd itself. ++ first_ids_file = val ++ elif key == '-w': ++ whitelist_filenames.append(val) ++ elif key == '--no-replace-ellipsis': ++ replace_ellipsis = False ++ elif key == '-p': ++ predetermined_ids_file = val ++ elif key == '-t': ++ target_platform = val ++ elif key == '--depdir': ++ depdir = val ++ elif key == '--depfile': ++ depfile = val ++ elif key == '--write-only-new': ++ write_only_new = val != '0' ++ elif key == '--depend-on-stamp': ++ depend_on_stamp = True ++ elif key == '--js-minifier': ++ js_minifier = val ++ elif key == '--css-minifier': ++ css_minifier = val ++ elif key == '--whitelist-support': ++ whitelist_support = True ++ elif key == '--brotli': ++ brotli_util.SetBrotliCommand([os.path.abspath(val)]) ++ elif key == '--help': ++ self.ShowUsage() ++ sys.exit(0) ++ ++ if len(args): ++ print('This tool takes no tool-specific arguments.') ++ return 2 ++ self.SetOptions(opts) ++ self.VerboseOut('Output directory: %s (absolute path: %s)\n' % ++ (self.output_directory, ++ os.path.abspath(self.output_directory))) ++ ++ if whitelist_filenames: ++ self.whitelist_names = set() ++ for whitelist_filename in whitelist_filenames: ++ self.VerboseOut('Using whitelist: %s\n' % whitelist_filename); ++ whitelist_contents = util.ReadFile(whitelist_filename, 'utf-8') ++ self.whitelist_names.update(whitelist_contents.strip().split('\n')) ++ ++ if js_minifier: ++ minifier.SetJsMinifier(js_minifier) ++ ++ if css_minifier: ++ minifier.SetCssMinifier(css_minifier) ++ ++ self.write_only_new = write_only_new ++ ++ self.res = grd_reader.Parse(opts.input, ++ debug=opts.extra_verbose, ++ first_ids_file=first_ids_file, ++ predetermined_ids_file=predetermined_ids_file, ++ defines=self.defines, ++ target_platform=target_platform) ++ ++ # Set an output context so that conditionals can use defines during the ++ # gathering stage; we use a dummy language here since we are not outputting ++ # a specific language. ++ self.res.SetOutputLanguage('en') ++ self.res.SetWhitelistSupportEnabled(whitelist_support) ++ self.res.RunGatherers() ++ ++ # Replace ... with the single-character version. http://crbug.com/621772 ++ if replace_ellipsis: ++ for node in self.res: ++ if isinstance(node, message.MessageNode): ++ node.SetReplaceEllipsis(True) ++ ++ self.Process() ++ ++ if assert_output_files: ++ if not self.CheckAssertedOutputFiles(assert_output_files): ++ return 2 ++ ++ if depfile and depdir: ++ self.GenerateDepfile(depfile, depdir, first_ids_file, depend_on_stamp) ++ ++ return 0 ++ ++ def __init__(self, defines=None): ++ # Default file-creation function is codecs.open(). Only done to allow ++ # overriding by unit test. ++ self.fo_create = codecs.open ++ ++ # key/value pairs of C-preprocessor like defines that are used for ++ # conditional output of resources ++ self.defines = defines or {} ++ ++ # self.res is a fully-populated resource tree if Run() ++ # has been called, otherwise None. ++ self.res = None ++ ++ # The set of names that are whitelisted to actually be included in the ++ # output. ++ self.whitelist_names = None ++ ++ # Whether to compare outputs to their old contents before writing. ++ self.write_only_new = False ++ ++ @staticmethod ++ def AddWhitelistTags(start_node, whitelist_names): ++ # Walk the tree of nodes added attributes for the nodes that shouldn't ++ # be written into the target files (skip markers). ++ for node in start_node: ++ # Same trick data_pack.py uses to see what nodes actually result in ++ # real items. ++ if (isinstance(node, include.IncludeNode) or ++ isinstance(node, message.MessageNode) or ++ isinstance(node, structure.StructureNode)): ++ text_ids = node.GetTextualIds() ++ # Mark the item to be skipped if it wasn't in the whitelist. ++ if text_ids and text_ids[0] not in whitelist_names: ++ node.SetWhitelistMarkedAsSkip(True) ++ ++ @staticmethod ++ def ProcessNode(node, output_node, outfile): ++ '''Processes a node in-order, calling its formatter before and after ++ recursing to its children. ++ ++ Args: ++ node: grit.node.base.Node subclass ++ output_node: grit.node.io.OutputNode ++ outfile: open filehandle ++ ''' ++ base_dir = util.dirname(output_node.GetOutputFilename()) ++ ++ formatter = GetFormatter(output_node.GetType()) ++ formatted = formatter(node, output_node.GetLanguage(), output_dir=base_dir) ++ # NB: Formatters may be generators or return lists. The writelines API ++ # accepts iterables as a shortcut to calling write directly. That means ++ # you can pass strings (iteration yields characters), but not bytes (as ++ # iteration yields integers). Python 2 worked due to its quirks with ++ # bytes/string implementation, but Python 3 fails. It's also a bit more ++ # inefficient to call write once per character/byte. Handle all of this ++ # ourselves by calling write directly on strings/bytes before falling back ++ # to writelines. ++ if isinstance(formatted, (six.string_types, six.binary_type)): ++ outfile.write(formatted) ++ else: ++ outfile.writelines(formatted) ++ if output_node.GetType() == 'data_package': ++ with open(output_node.GetOutputFilename() + '.info', 'w') as infofile: ++ if node.info: ++ # We terminate with a newline so that when these files are ++ # concatenated later we consistently terminate with a newline so ++ # consumers can account for terminating newlines. ++ infofile.writelines(['\n'.join(node.info), '\n']) ++ ++ @staticmethod ++ def _EncodingForOutputType(output_type): ++ # Microsoft's RC compiler can only deal with single-byte or double-byte ++ # files (no UTF-8), so we make all RC files UTF-16 to support all ++ # character sets. ++ if output_type in ('rc_header', 'resource_file_map_source', ++ 'resource_map_header', 'resource_map_source'): ++ return 'cp1252' ++ if output_type in ('android', 'c_format', 'plist', 'plist_strings', 'doc', ++ 'json', 'android_policy', 'chrome_messages_json', ++ 'chrome_messages_json_gzip', 'policy_templates'): ++ return 'utf_8' ++ # TODO(gfeher) modify here to set utf-8 encoding for admx/adml ++ return 'utf_16' ++ ++ def Process(self): ++ for output in self.res.GetOutputFiles(): ++ output.output_filename = os.path.abspath(os.path.join( ++ self.output_directory, output.GetOutputFilename())) ++ ++ # If there are whitelisted names, tag the tree once up front, this way ++ # while looping through the actual output, it is just an attribute check. ++ if self.whitelist_names: ++ self.AddWhitelistTags(self.res, self.whitelist_names) ++ ++ for output in self.res.GetOutputFiles(): ++ self.VerboseOut('Creating %s...' % output.GetOutputFilename()) ++ ++ # Set the context, for conditional inclusion of resources ++ self.res.SetOutputLanguage(output.GetLanguage()) ++ self.res.SetOutputContext(output.GetContext()) ++ self.res.SetFallbackToDefaultLayout(output.GetFallbackToDefaultLayout()) ++ self.res.SetDefines(self.defines) ++ ++ # Assign IDs only once to ensure that all outputs use the same IDs. ++ if self.res.GetIdMap() is None: ++ self.res.InitializeIds() ++ ++ # Make the output directory if it doesn't exist. ++ self.MakeDirectoriesTo(output.GetOutputFilename()) ++ ++ # Write the results to a temporary file and only overwrite the original ++ # if the file changed. This avoids unnecessary rebuilds. ++ out_filename = output.GetOutputFilename() ++ tmp_filename = out_filename + '.tmp' ++ tmpfile = self.fo_create(tmp_filename, 'wb') ++ ++ output_type = output.GetType() ++ if output_type != 'data_package': ++ encoding = self._EncodingForOutputType(output_type) ++ tmpfile = util.WrapOutputStream(tmpfile, encoding) ++ ++ # Iterate in-order through entire resource tree, calling formatters on ++ # the entry into a node and on exit out of it. ++ with tmpfile: ++ self.ProcessNode(self.res, output, tmpfile) ++ ++ if output_type == 'chrome_messages_json_gzip': ++ gz_filename = tmp_filename + '.gz' ++ with open(tmp_filename, 'rb') as tmpfile, open(gz_filename, 'wb') as f: ++ with gzip.GzipFile(filename='', mode='wb', fileobj=f, mtime=0) as fgz: ++ shutil.copyfileobj(tmpfile, fgz) ++ os.remove(tmp_filename) ++ tmp_filename = gz_filename ++ ++ # Now copy from the temp file back to the real output, but on Windows, ++ # only if the real output doesn't exist or the contents of the file ++ # changed. This prevents identical headers from being written and .cc ++ # files from recompiling (which is painful on Windows). ++ if not os.path.exists(out_filename): ++ os.rename(tmp_filename, out_filename) ++ else: ++ # CHROMIUM SPECIFIC CHANGE. ++ # This clashes with gyp + vstudio, which expect the output timestamp ++ # to change on a rebuild, even if nothing has changed, so only do ++ # it when opted in. ++ if not self.write_only_new: ++ write_file = True ++ else: ++ files_match = filecmp.cmp(out_filename, tmp_filename) ++ write_file = not files_match ++ if write_file: ++ shutil.copy2(tmp_filename, out_filename) ++ os.remove(tmp_filename) ++ ++ self.VerboseOut(' done.\n') ++ ++ # Print warnings if there are any duplicate shortcuts. ++ warnings = shortcuts.GenerateDuplicateShortcutsWarnings( ++ self.res.UberClique(), self.res.GetTcProject()) ++ if warnings: ++ print('\n'.join(warnings)) ++ ++ # Print out any fallback warnings, and missing translation errors, and ++ # exit with an error code if there are missing translations in a non-pseudo ++ # and non-official build. ++ warnings = (self.res.UberClique().MissingTranslationsReport(). ++ encode('ascii', 'replace')) ++ if warnings: ++ self.VerboseOut(warnings) ++ if self.res.UberClique().HasMissingTranslations(): ++ print(self.res.UberClique().missing_translations_) ++ sys.exit(-1) ++ ++ ++ def CheckAssertedOutputFiles(self, assert_output_files): ++ '''Checks that the asserted output files are specified in the given list. ++ ++ Returns true if the asserted files are present. If they are not, returns ++ False and prints the failure. ++ ''' ++ # Compare the absolute path names, sorted. ++ asserted = sorted([os.path.abspath(i) for i in assert_output_files]) ++ actual = sorted([ ++ os.path.abspath(os.path.join(self.output_directory, ++ i.GetOutputFilename())) ++ for i in self.res.GetOutputFiles()]) ++ ++ if asserted != actual: ++ missing = list(set(asserted) - set(actual)) ++ extra = list(set(actual) - set(asserted)) ++ error = '''Asserted file list does not match. ++ ++Expected output files: ++%s ++Actual output files: ++%s ++Missing output files: ++%s ++Extra output files: ++%s ++''' ++ print(error % ('\n'.join(asserted), '\n'.join(actual), '\n'.join(missing), ++ ' \n'.join(extra))) ++ return False ++ return True ++ ++ ++ def GenerateDepfile(self, depfile, depdir, first_ids_file, depend_on_stamp): ++ '''Generate a depfile that contains the imlicit dependencies of the input ++ grd. The depfile will be in the same format as a makefile, and will contain ++ references to files relative to |depdir|. It will be put in |depfile|. ++ ++ For example, supposing we have three files in a directory src/ ++ ++ src/ ++ blah.grd <- depends on input{1,2}.xtb ++ input1.xtb ++ input2.xtb ++ ++ and we run ++ ++ grit -i blah.grd -o ../out/gen \ ++ --depdir ../out \ ++ --depfile ../out/gen/blah.rd.d ++ ++ from the directory src/ we will generate a depfile ../out/gen/blah.grd.d ++ that has the contents ++ ++ gen/blah.h: ../src/input1.xtb ../src/input2.xtb ++ ++ Where "gen/blah.h" is the first output (Ninja expects the .d file to list ++ the first output in cases where there is more than one). If the flag ++ --depend-on-stamp is specified, "gen/blah.rd.d.stamp" will be used that is ++ 'touched' whenever a new depfile is generated. ++ ++ Note that all paths in the depfile are relative to ../out, the depdir. ++ ''' ++ depfile = os.path.abspath(depfile) ++ depdir = os.path.abspath(depdir) ++ infiles = self.res.GetInputFiles() ++ ++ # We want to trigger a rebuild if the first ids change. ++ if first_ids_file is not None: ++ infiles.append(first_ids_file) ++ ++ if (depend_on_stamp): ++ output_file = depfile + ".stamp" ++ # Touch the stamp file before generating the depfile. ++ with open(output_file, 'a'): ++ os.utime(output_file, None) ++ else: ++ # Get the first output file relative to the depdir. ++ outputs = self.res.GetOutputFiles() ++ output_file = os.path.join(self.output_directory, ++ outputs[0].GetOutputFilename()) ++ ++ output_file = os.path.relpath(output_file, depdir) ++ # The path prefix to prepend to dependencies in the depfile. ++ prefix = os.path.relpath(os.getcwd(), depdir) ++ deps_text = ' '.join([os.path.join(prefix, i) for i in infiles]) ++ ++ depfile_contents = output_file + ': ' + deps_text ++ self.MakeDirectoriesTo(depfile) ++ outfile = self.fo_create(depfile, 'w', encoding='utf-8') ++ outfile.write(depfile_contents) ++ ++ @staticmethod ++ def MakeDirectoriesTo(file): ++ '''Creates directories necessary to contain |file|.''' ++ dir = os.path.split(file)[0] ++ if not os.path.exists(dir): ++ os.makedirs(dir) +diff --git a/tools/grit/grit/tool/build_unittest.py b/tools/grit/grit/tool/build_unittest.py +new file mode 100644 +index 0000000000..c4a2f2752b +--- /dev/null ++++ b/tools/grit/grit/tool/build_unittest.py +@@ -0,0 +1,341 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for the 'grit build' tool. ++''' ++ ++from __future__ import print_function ++ ++import codecs ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++from grit import util ++from grit.tool import build ++ ++ ++class BuildUnittest(unittest.TestCase): ++ ++ # IDs should not change based on whitelisting. ++ # Android WebView currently relies on this. ++ EXPECTED_ID_MAP = { ++ 'IDS_MESSAGE_WHITELISTED': 6889, ++ 'IDR_STRUCTURE_WHITELISTED': 11546, ++ 'IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED': 11548, ++ 'IDR_INCLUDE_WHITELISTED': 15601, ++ } ++ ++ def testFindTranslationsWithSubstitutions(self): ++ # This is a regression test; we had a bug where GRIT would fail to find ++ # messages with substitutions e.g. "Hello [IDS_USER]" where IDS_USER is ++ # another . ++ output_dir = util.TempDir({}) ++ builder = build.RcBuilder() ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/substitute.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ builder.Run(DummyOpts(), ['-o', output_dir.GetPath()]) ++ output_dir.CleanUp() ++ ++ def testGenerateDepFile(self): ++ output_dir = util.TempDir({}) ++ builder = build.RcBuilder() ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/depfile.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ expected_dep_file = output_dir.GetPath('substitute.grd.d') ++ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), ++ '--depdir', output_dir.GetPath(), ++ '--depfile', expected_dep_file]) ++ ++ self.failUnless(os.path.isfile(expected_dep_file)) ++ with open(expected_dep_file) as f: ++ line = f.readline() ++ (dep_output_file, deps_string) = line.split(': ') ++ deps = deps_string.split(' ') ++ ++ self.failUnlessEqual("default_100_percent.pak", dep_output_file) ++ self.failUnlessEqual(deps, [ ++ util.PathFromRoot('grit/testdata/default_100_percent/a.png'), ++ util.PathFromRoot('grit/testdata/grit_part.grdp'), ++ util.PathFromRoot('grit/testdata/special_100_percent/a.png'), ++ ]) ++ output_dir.CleanUp() ++ ++ def testGenerateDepFileWithResourceIds(self): ++ output_dir = util.TempDir({}) ++ builder = build.RcBuilder() ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/substitute_no_ids.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ expected_dep_file = output_dir.GetPath('substitute_no_ids.grd.d') ++ builder.Run(DummyOpts(), ++ ['-f', util.PathFromRoot('grit/testdata/resource_ids'), ++ '-o', output_dir.GetPath(), ++ '--depdir', output_dir.GetPath(), ++ '--depfile', expected_dep_file]) ++ ++ self.failUnless(os.path.isfile(expected_dep_file)) ++ with open(expected_dep_file) as f: ++ line = f.readline() ++ (dep_output_file, deps_string) = line.split(': ') ++ deps = deps_string.split(' ') ++ ++ self.failUnlessEqual("resource.h", dep_output_file) ++ self.failUnlessEqual(2, len(deps)) ++ self.failUnlessEqual(deps[0], ++ util.PathFromRoot('grit/testdata/substitute.xmb')) ++ self.failUnlessEqual(deps[1], ++ util.PathFromRoot('grit/testdata/resource_ids')) ++ output_dir.CleanUp() ++ ++ def testAssertOutputs(self): ++ output_dir = util.TempDir({}) ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/substitute.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ ++ # Incomplete output file list should fail. ++ builder_fail = build.RcBuilder() ++ self.failUnlessEqual(2, ++ builder_fail.Run(DummyOpts(), [ ++ '-o', output_dir.GetPath(), ++ '-a', os.path.abspath( ++ output_dir.GetPath('en_generated_resources.rc'))])) ++ ++ # Complete output file list should succeed. ++ builder_ok = build.RcBuilder() ++ self.failUnlessEqual(0, ++ builder_ok.Run(DummyOpts(), [ ++ '-o', output_dir.GetPath(), ++ '-a', os.path.abspath( ++ output_dir.GetPath('en_generated_resources.rc')), ++ '-a', os.path.abspath( ++ output_dir.GetPath('sv_generated_resources.rc')), ++ '-a', os.path.abspath(output_dir.GetPath('resource.h'))])) ++ output_dir.CleanUp() ++ ++ def testAssertTemplateOutputs(self): ++ output_dir = util.TempDir({}) ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/substitute_tmpl.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ ++ # Incomplete output file list should fail. ++ builder_fail = build.RcBuilder() ++ self.failUnlessEqual(2, ++ builder_fail.Run(DummyOpts(), [ ++ '-o', output_dir.GetPath(), ++ '-E', 'name=foo', ++ '-a', os.path.abspath(output_dir.GetPath('en_foo_resources.rc'))])) ++ ++ # Complete output file list should succeed. ++ builder_ok = build.RcBuilder() ++ self.failUnlessEqual(0, ++ builder_ok.Run(DummyOpts(), [ ++ '-o', output_dir.GetPath(), ++ '-E', 'name=foo', ++ '-a', os.path.abspath(output_dir.GetPath('en_foo_resources.rc')), ++ '-a', os.path.abspath(output_dir.GetPath('sv_foo_resources.rc')), ++ '-a', os.path.abspath(output_dir.GetPath('resource.h'))])) ++ output_dir.CleanUp() ++ ++ def _verifyWhitelistedOutput(self, ++ filename, ++ whitelisted_ids, ++ non_whitelisted_ids, ++ encoding='utf8'): ++ self.failUnless(os.path.exists(filename)) ++ whitelisted_ids_found = [] ++ non_whitelisted_ids_found = [] ++ with codecs.open(filename, encoding=encoding) as f: ++ for line in f.readlines(): ++ for whitelisted_id in whitelisted_ids: ++ if whitelisted_id in line: ++ whitelisted_ids_found.append(whitelisted_id) ++ if filename.endswith('.h'): ++ numeric_id = int(line.split()[2]) ++ expected_numeric_id = self.EXPECTED_ID_MAP.get(whitelisted_id) ++ self.assertEqual( ++ expected_numeric_id, numeric_id, ++ 'Numeric ID for {} was {} should be {}'.format( ++ whitelisted_id, numeric_id, expected_numeric_id)) ++ for non_whitelisted_id in non_whitelisted_ids: ++ if non_whitelisted_id in line: ++ non_whitelisted_ids_found.append(non_whitelisted_id) ++ self.longMessage = True ++ self.assertEqual(whitelisted_ids, ++ whitelisted_ids_found, ++ '\nin file {}'.format(os.path.basename(filename))) ++ non_whitelisted_msg = ('Non-Whitelisted IDs {} found in {}' ++ .format(non_whitelisted_ids_found, os.path.basename(filename))) ++ self.assertFalse(non_whitelisted_ids_found, non_whitelisted_msg) ++ ++ def testWhitelistStrings(self): ++ output_dir = util.TempDir({}) ++ builder = build.RcBuilder() ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/whitelist_strings.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ whitelist_file = util.PathFromRoot('grit/testdata/whitelist.txt') ++ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), ++ '-w', whitelist_file]) ++ header = output_dir.GetPath('whitelist_test_resources.h') ++ rc = output_dir.GetPath('en_whitelist_test_strings.rc') ++ ++ whitelisted_ids = ['IDS_MESSAGE_WHITELISTED'] ++ non_whitelisted_ids = ['IDS_MESSAGE_NOT_WHITELISTED'] ++ self._verifyWhitelistedOutput( ++ header, ++ whitelisted_ids, ++ non_whitelisted_ids, ++ ) ++ self._verifyWhitelistedOutput( ++ rc, ++ whitelisted_ids, ++ non_whitelisted_ids, ++ encoding='utf16' ++ ) ++ output_dir.CleanUp() ++ ++ def testWhitelistResources(self): ++ output_dir = util.TempDir({}) ++ builder = build.RcBuilder() ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/whitelist_resources.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ whitelist_file = util.PathFromRoot('grit/testdata/whitelist.txt') ++ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), ++ '-w', whitelist_file]) ++ header = output_dir.GetPath('whitelist_test_resources.h') ++ map_cc = output_dir.GetPath('whitelist_test_resources_map.cc') ++ map_h = output_dir.GetPath('whitelist_test_resources_map.h') ++ pak = output_dir.GetPath('whitelist_test_resources.pak') ++ ++ # Ensure the resource map header and .pak files exist, but don't verify ++ # their content. ++ self.failUnless(os.path.exists(map_h)) ++ self.failUnless(os.path.exists(pak)) ++ ++ whitelisted_ids = [ ++ 'IDR_STRUCTURE_WHITELISTED', ++ 'IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED', ++ 'IDR_INCLUDE_WHITELISTED', ++ ] ++ non_whitelisted_ids = [ ++ 'IDR_STRUCTURE_NOT_WHITELISTED', ++ 'IDR_STRUCTURE_IN_TRUE_IF_NOT_WHITELISTED', ++ 'IDR_STRUCTURE_IN_FALSE_IF_WHITELISTED', ++ 'IDR_STRUCTURE_IN_FALSE_IF_NOT_WHITELISTED', ++ 'IDR_INCLUDE_NOT_WHITELISTED', ++ ] ++ for output_file in (header, map_cc): ++ self._verifyWhitelistedOutput( ++ output_file, ++ whitelisted_ids, ++ non_whitelisted_ids, ++ ) ++ output_dir.CleanUp() ++ ++ def testWriteOnlyNew(self): ++ output_dir = util.TempDir({}) ++ builder = build.RcBuilder() ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/substitute.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ UNCHANGED = 10 ++ header = output_dir.GetPath('resource.h') ++ ++ builder.Run(DummyOpts(), ['-o', output_dir.GetPath()]) ++ self.failUnless(os.path.exists(header)) ++ first_mtime = os.stat(header).st_mtime ++ ++ os.utime(header, (UNCHANGED, UNCHANGED)) ++ builder.Run(DummyOpts(), ++ ['-o', output_dir.GetPath(), '--write-only-new', '0']) ++ self.failUnless(os.path.exists(header)) ++ second_mtime = os.stat(header).st_mtime ++ ++ os.utime(header, (UNCHANGED, UNCHANGED)) ++ builder.Run(DummyOpts(), ++ ['-o', output_dir.GetPath(), '--write-only-new', '1']) ++ self.failUnless(os.path.exists(header)) ++ third_mtime = os.stat(header).st_mtime ++ ++ self.assertTrue(abs(second_mtime - UNCHANGED) > 5) ++ self.assertTrue(abs(third_mtime - UNCHANGED) < 5) ++ output_dir.CleanUp() ++ ++ def testGenerateDepFileWithDependOnStamp(self): ++ output_dir = util.TempDir({}) ++ builder = build.RcBuilder() ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = util.PathFromRoot('grit/testdata/substitute.grd') ++ self.verbose = False ++ self.extra_verbose = False ++ expected_dep_file_name = 'substitute.grd.d' ++ expected_stamp_file_name = expected_dep_file_name + '.stamp' ++ expected_dep_file = output_dir.GetPath(expected_dep_file_name) ++ expected_stamp_file = output_dir.GetPath(expected_stamp_file_name) ++ if os.path.isfile(expected_stamp_file): ++ os.remove(expected_stamp_file) ++ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), ++ '--depdir', output_dir.GetPath(), ++ '--depfile', expected_dep_file, ++ '--depend-on-stamp']) ++ self.failUnless(os.path.isfile(expected_stamp_file)) ++ first_mtime = os.stat(expected_stamp_file).st_mtime ++ ++ # Reset mtime to very old. ++ OLDTIME = 10 ++ os.utime(expected_stamp_file, (OLDTIME, OLDTIME)) ++ ++ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), ++ '--depdir', output_dir.GetPath(), ++ '--depfile', expected_dep_file, ++ '--depend-on-stamp']) ++ self.failUnless(os.path.isfile(expected_stamp_file)) ++ second_mtime = os.stat(expected_stamp_file).st_mtime ++ ++ # Some OS have a 2s stat resolution window, so can't do a direct comparison. ++ self.assertTrue((second_mtime - OLDTIME) > 5) ++ self.assertTrue(abs(second_mtime - first_mtime) < 5) ++ ++ self.failUnless(os.path.isfile(expected_dep_file)) ++ with open(expected_dep_file) as f: ++ line = f.readline() ++ (dep_output_file, deps_string) = line.split(': ') ++ deps = deps_string.split(' ') ++ ++ self.failUnlessEqual(expected_stamp_file_name, dep_output_file) ++ self.failUnlessEqual(deps, [ ++ util.PathFromRoot('grit/testdata/substitute.xmb'), ++ ]) ++ output_dir.CleanUp() ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/tool/buildinfo.py b/tools/grit/grit/tool/buildinfo.py +new file mode 100644 +index 0000000000..7f8d1a3b04 +--- /dev/null ++++ b/tools/grit/grit/tool/buildinfo.py +@@ -0,0 +1,78 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Output the list of files to be generated by GRIT from an input. ++""" ++ ++from __future__ import print_function ++ ++import getopt ++import os ++import sys ++ ++from grit import grd_reader ++from grit.node import structure ++from grit.tool import interface ++ ++class DetermineBuildInfo(interface.Tool): ++ """Determine what files will be read and output by GRIT. ++Outputs the list of generated files and inputs used to stdout. ++ ++Usage: grit buildinfo [-o DIR] ++ ++The output directory is used for display only. ++""" ++ ++ def __init__(self): ++ pass ++ ++ def ShortDescription(self): ++ """Describes this tool for the usage message.""" ++ return ('Determine what files will be needed and\n' ++ 'output by GRIT with a given input.') ++ ++ def Run(self, opts, args): ++ """Main method for the buildinfo tool.""" ++ self.output_directory = '.' ++ (own_opts, args) = getopt.getopt(args, 'o:', ('help',)) ++ for (key, val) in own_opts: ++ if key == '-o': ++ self.output_directory = val ++ elif key == '--help': ++ self.ShowUsage() ++ sys.exit(0) ++ if len(args) > 0: ++ print('This tool takes exactly one argument: the output directory via -o') ++ return 2 ++ self.SetOptions(opts) ++ ++ res_tree = grd_reader.Parse(opts.input, debug=opts.extra_verbose) ++ ++ langs = {} ++ for output in res_tree.GetOutputFiles(): ++ if output.attrs['lang']: ++ langs[output.attrs['lang']] = os.path.dirname(output.GetFilename()) ++ ++ for lang, dirname in langs.items(): ++ old_output_language = res_tree.output_language ++ res_tree.SetOutputLanguage(lang) ++ for node in res_tree.ActiveDescendants(): ++ with node: ++ if (isinstance(node, structure.StructureNode) and ++ node.HasFileForLanguage()): ++ path = node.FileForLanguage(lang, dirname, create_file=False, ++ return_if_not_generated=False) ++ if path: ++ path = os.path.join(self.output_directory, path) ++ path = os.path.normpath(path) ++ print('%s|%s' % ('rc_all', path)) ++ res_tree.SetOutputLanguage(old_output_language) ++ ++ for output in res_tree.GetOutputFiles(): ++ path = os.path.join(self.output_directory, output.GetFilename()) ++ path = os.path.normpath(path) ++ print('%s|%s' % (output.GetType(), path)) ++ ++ for infile in res_tree.GetInputFiles(): ++ print('input|%s' % os.path.normpath(infile)) +diff --git a/tools/grit/grit/tool/buildinfo_unittest.py b/tools/grit/grit/tool/buildinfo_unittest.py +new file mode 100644 +index 0000000000..24e9ddf8d8 +--- /dev/null ++++ b/tools/grit/grit/tool/buildinfo_unittest.py +@@ -0,0 +1,90 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Unit tests for the 'grit buildinfo' tool. ++""" ++ ++from __future__ import print_function ++ ++import os ++import sys ++import unittest ++ ++# This is needed to find some of the imports below. ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++from six import StringIO ++ ++# pylint: disable-msg=C6204 ++from grit.tool import buildinfo ++ ++ ++class BuildInfoUnittest(unittest.TestCase): ++ def setUp(self): ++ self.old_cwd = os.getcwd() ++ # Change CWD to make tests work independently of callers CWD. ++ os.chdir(os.path.dirname(__file__)) ++ os.chdir('..') ++ self.buf = StringIO() ++ self.old_stdout = sys.stdout ++ sys.stdout = self.buf ++ ++ def tearDown(self): ++ sys.stdout = self.old_stdout ++ os.chdir(self.old_cwd) ++ ++ def testBuildOutput(self): ++ """Find all of the inputs and outputs for a GRD file.""" ++ info_object = buildinfo.DetermineBuildInfo() ++ ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = '../grit/testdata/buildinfo.grd' ++ self.print_header = False ++ self.verbose = False ++ self.extra_verbose = False ++ info_object.Run(DummyOpts(), []) ++ output = self.buf.getvalue().replace('\\', '/') ++ self.failUnless(output.count(r'rc_all|sv_sidebar_loading.html')) ++ self.failUnless(output.count(r'rc_header|resource.h')) ++ self.failUnless(output.count(r'rc_all|en_generated_resources.rc')) ++ self.failUnless(output.count(r'rc_all|sv_generated_resources.rc')) ++ self.failUnless(output.count(r'input|../grit/testdata/substitute.xmb')) ++ self.failUnless(output.count(r'input|../grit/testdata/pr.bmp')) ++ self.failUnless(output.count(r'input|../grit/testdata/pr2.bmp')) ++ self.failUnless( ++ output.count(r'input|../grit/testdata/sidebar_loading.html')) ++ self.failUnless(output.count(r'input|../grit/testdata/transl.rc')) ++ self.failUnless(output.count(r'input|../grit/testdata/transl1.rc')) ++ ++ def testBuildOutputWithDir(self): ++ """Find all the inputs and outputs for a GRD file with an output dir.""" ++ info_object = buildinfo.DetermineBuildInfo() ++ ++ class DummyOpts(object): ++ def __init__(self): ++ self.input = '../grit/testdata/buildinfo.grd' ++ self.print_header = False ++ self.verbose = False ++ self.extra_verbose = False ++ info_object.Run(DummyOpts(), ['-o', '../grit/testdata']) ++ output = self.buf.getvalue().replace('\\', '/') ++ self.failUnless( ++ output.count(r'rc_all|../grit/testdata/sv_sidebar_loading.html')) ++ self.failUnless(output.count(r'rc_header|../grit/testdata/resource.h')) ++ self.failUnless( ++ output.count(r'rc_all|../grit/testdata/en_generated_resources.rc')) ++ self.failUnless( ++ output.count(r'rc_all|../grit/testdata/sv_generated_resources.rc')) ++ self.failUnless(output.count(r'input|../grit/testdata/substitute.xmb')) ++ self.failUnlessEqual(0, ++ output.count(r'rc_all|../grit/testdata/sv_welcome_toast.html')) ++ self.failUnless( ++ output.count(r'rc_all|../grit/testdata/en_welcome_toast.html')) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/tool/count.py b/tools/grit/grit/tool/count.py +new file mode 100644 +index 0000000000..ab37f2ddb3 +--- /dev/null ++++ b/tools/grit/grit/tool/count.py +@@ -0,0 +1,52 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Count number of occurrences of a given message ID.''' ++ ++from __future__ import print_function ++ ++import getopt ++import sys ++ ++from grit import grd_reader ++from grit.tool import interface ++ ++ ++class CountMessage(interface.Tool): ++ '''Count the number of times a given message ID is used.''' ++ ++ def __init__(self): ++ pass ++ ++ def ShortDescription(self): ++ return 'Count the number of times a given message ID is used.' ++ ++ def ParseOptions(self, args): ++ """Set this objects and return all non-option arguments.""" ++ own_opts, args = getopt.getopt(args, '', ('help',)) ++ for key, val in own_opts: ++ if key == '--help': ++ self.ShowUsage() ++ sys.exit(0) ++ return args ++ ++ def Run(self, opts, args): ++ args = self.ParseOptions(args) ++ if len(args) != 1: ++ print('This tool takes a single tool-specific argument, the message ' ++ 'ID to count.') ++ return 2 ++ self.SetOptions(opts) ++ ++ id = args[0] ++ res_tree = grd_reader.Parse(opts.input, debug=opts.extra_verbose) ++ res_tree.OnlyTheseTranslations([]) ++ res_tree.RunGatherers() ++ ++ count = 0 ++ for c in res_tree.UberClique().AllCliques(): ++ if c.GetId() == id: ++ count += 1 ++ ++ print("There are %d occurrences of message %s." % (count, id)) +diff --git a/tools/grit/grit/tool/diff_structures.py b/tools/grit/grit/tool/diff_structures.py +new file mode 100644 +index 0000000000..d69e009b58 +--- /dev/null ++++ b/tools/grit/grit/tool/diff_structures.py +@@ -0,0 +1,119 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''The 'grit sdiff' tool. ++''' ++ ++from __future__ import print_function ++ ++import os ++import getopt ++import sys ++import tempfile ++ ++from grit.node import structure ++from grit.tool import interface ++ ++from grit import constants ++from grit import util ++ ++# Builds the description for the tool (used as the __doc__ ++# for the DiffStructures class). ++_class_doc = """\ ++Allows you to view the differences in the structure of two files, ++disregarding their translateable content. Translateable portions of ++each file are changed to the string "TTTTTT" before invoking the diff program ++specified by the P4DIFF environment variable. ++ ++Usage: grit sdiff [-t TYPE] [-s SECTION] [-e ENCODING] LEFT RIGHT ++ ++LEFT and RIGHT are the files you want to diff. SECTION is required ++for structure types like 'dialog' to identify the part of the file to look at. ++ENCODING indicates the encoding of the left and right files (default 'cp1252'). ++TYPE can be one of the following, defaults to 'tr_html': ++""" ++for gatherer in structure._GATHERERS: ++ _class_doc += " - %s\n" % gatherer ++ ++ ++class DiffStructures(interface.Tool): ++ __doc__ = _class_doc ++ ++ def __init__(self): ++ self.section = None ++ self.left_encoding = 'cp1252' ++ self.right_encoding = 'cp1252' ++ self.structure_type = 'tr_html' ++ ++ def ShortDescription(self): ++ return 'View differences without regard for translateable portions.' ++ ++ def Run(self, global_opts, args): ++ (opts, args) = getopt.getopt(args, 's:e:t:', ++ ('help', 'left_encoding=', 'right_encoding=')) ++ for key, val in opts: ++ if key == '-s': ++ self.section = val ++ elif key == '-e': ++ self.left_encoding = val ++ self.right_encoding = val ++ elif key == '-t': ++ self.structure_type = val ++ elif key == '--left_encoding': ++ self.left_encoding = val ++ elif key == '--right_encoding': ++ self.right_encoding == val ++ elif key == '--help': ++ self.ShowUsage() ++ sys.exit(0) ++ ++ if len(args) != 2: ++ print("Incorrect usage - 'grit help sdiff' for usage details.") ++ return 2 ++ ++ if 'P4DIFF' not in os.environ: ++ print("Environment variable P4DIFF not set; defaulting to 'windiff'.") ++ diff_program = 'windiff' ++ else: ++ diff_program = os.environ['P4DIFF'] ++ ++ left_trans = self.MakeStaticTranslation(args[0], self.left_encoding) ++ try: ++ try: ++ right_trans = self.MakeStaticTranslation(args[1], self.right_encoding) ++ ++ os.system('%s %s %s' % (diff_program, left_trans, right_trans)) ++ finally: ++ os.unlink(right_trans) ++ finally: ++ os.unlink(left_trans) ++ ++ def MakeStaticTranslation(self, original_filename, encoding): ++ """Given the name of the structure type (self.structure_type), the filename ++ of the file holding the original structure, and optionally the "section" key ++ identifying the part of the file to look at (self.section), creates a ++ temporary file holding a "static" translation of the original structure ++ (i.e. one where all translateable parts have been replaced with "TTTTTT") ++ and returns the temporary file name. It is the caller's responsibility to ++ delete the file when finished. ++ ++ Args: ++ original_filename: 'c:\\bingo\\bla.rc' ++ ++ Return: ++ 'c:\\temp\\werlkjsdf334.tmp' ++ """ ++ original = structure._GATHERERS[self.structure_type](original_filename, ++ extkey=self.section, ++ encoding=encoding) ++ original.Parse() ++ translated = original.Translate(constants.CONSTANT_LANGUAGE, False) ++ ++ fname = tempfile.mktemp() ++ with util.WrapOutputStream(open(fname, 'wb')) as writer: ++ writer.write("Original filename: %s\n=============\n\n" ++ % original_filename) ++ writer.write(translated) # write in UTF-8 ++ ++ return fname +diff --git a/tools/grit/grit/tool/diff_structures_unittest.py b/tools/grit/grit/tool/diff_structures_unittest.py +new file mode 100644 +index 0000000000..a6d7585761 +--- /dev/null ++++ b/tools/grit/grit/tool/diff_structures_unittest.py +@@ -0,0 +1,46 @@ ++#!/usr/bin/env python ++# Copyright 2020 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for the 'grit newgrd' tool.''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++from grit.tool import diff_structures ++ ++ ++class DummyOpts(object): ++ """Options needed by NewGrd.""" ++ ++ ++class DiffStructuresUnittest(unittest.TestCase): ++ ++ def testMissingFiles(self): ++ """Verify failure w/out file inputs.""" ++ tool = diff_structures.DiffStructures() ++ ret = tool.Run(DummyOpts(), []) ++ self.assertIsNotNone(ret) ++ self.assertGreater(ret, 0) ++ ++ ret = tool.Run(DummyOpts(), ['left']) ++ self.assertIsNotNone(ret) ++ self.assertGreater(ret, 0) ++ ++ def testTooManyArgs(self): ++ """Verify failure w/too many inputs.""" ++ tool = diff_structures.DiffStructures() ++ ret = tool.Run(DummyOpts(), ['a', 'b', 'c']) ++ self.assertIsNotNone(ret) ++ self.assertGreater(ret, 0) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/tool/interface.py b/tools/grit/grit/tool/interface.py +new file mode 100644 +index 0000000000..e923205223 +--- /dev/null ++++ b/tools/grit/grit/tool/interface.py +@@ -0,0 +1,62 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Base class and interface for tools. ++''' ++ ++from __future__ import print_function ++ ++class Tool(object): ++ '''Base class for all tools. Tools should use their docstring (i.e. the ++ class-level docstring) for the help they want to have printed when they ++ are invoked.''' ++ ++ # ++ # Interface (abstract methods) ++ # ++ ++ def ShortDescription(self): ++ '''Returns a short description of the functionality of the tool.''' ++ raise NotImplementedError() ++ ++ def Run(self, global_options, my_arguments): ++ '''Runs the tool. ++ ++ Args: ++ global_options: object grit_runner.Options ++ my_arguments: [arg1 arg2 ...] ++ ++ Return: ++ 0 for success, non-0 for error ++ ''' ++ raise NotImplementedError() ++ ++ # ++ # Base class implementation ++ # ++ ++ def __init__(self): ++ self.o = None ++ ++ def ShowUsage(self): ++ '''Show usage text for this tool.''' ++ print(self.__doc__) ++ ++ def SetOptions(self, opts): ++ self.o = opts ++ ++ def Out(self, text): ++ '''Always writes out 'text'.''' ++ self.o.output_stream.write(text) ++ ++ def VerboseOut(self, text): ++ '''Writes out 'text' if the verbose option is on.''' ++ if self.o.verbose: ++ self.o.output_stream.write(text) ++ ++ def ExtraVerboseOut(self, text): ++ '''Writes out 'text' if the extra-verbose option is on. ++ ''' ++ if self.o.extra_verbose: ++ self.o.output_stream.write(text) +diff --git a/tools/grit/grit/tool/menu_from_parts.py b/tools/grit/grit/tool/menu_from_parts.py +new file mode 100644 +index 0000000000..fcec26c5b1 +--- /dev/null ++++ b/tools/grit/grit/tool/menu_from_parts.py +@@ -0,0 +1,79 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''The 'grit menufromparts' tool.''' ++ ++from __future__ import print_function ++ ++import six ++ ++from grit import grd_reader ++from grit import util ++from grit import xtb_reader ++from grit.tool import interface ++from grit.tool import transl2tc ++ ++import grit.extern.tclib ++ ++ ++class MenuTranslationsFromParts(interface.Tool): ++ '''One-off tool to generate translated menu messages (where each menu is kept ++in a single message) based on existing translations of the individual menu ++items. Was needed when changing menus from being one message per menu item ++to being one message for the whole menu.''' ++ ++ def ShortDescription(self): ++ return ('Create translations of whole menus from existing translations of ' ++ 'menu items.') ++ ++ def Run(self, globopt, args): ++ self.SetOptions(globopt) ++ assert len(args) == 2, "Need exactly two arguments, the XTB file and the output file" ++ ++ xtb_file = args[0] ++ output_file = args[1] ++ ++ grd = grd_reader.Parse(self.o.input, debug=self.o.extra_verbose) ++ grd.OnlyTheseTranslations([]) # don't load translations ++ grd.RunGatherers() ++ ++ xtb = {} ++ def Callback(msg_id, parts): ++ msg = [] ++ for part in parts: ++ if part[0]: ++ msg = [] ++ break # it had a placeholder so ignore it ++ else: ++ msg.append(part[1]) ++ if len(msg): ++ xtb[msg_id] = ''.join(msg) ++ with open(xtb_file, 'rb') as f: ++ xtb_reader.Parse(f, Callback) ++ ++ translations = [] # list of translations as per transl2tc.WriteTranslations ++ for node in grd: ++ if node.name == 'structure' and node.attrs['type'] == 'menu': ++ assert len(node.GetCliques()) == 1 ++ message = node.GetCliques()[0].GetMessage() ++ translation = [] ++ ++ contents = message.GetContent() ++ for part in contents: ++ if isinstance(part, six.string_types): ++ id = grit.extern.tclib.GenerateMessageId(part) ++ if id not in xtb: ++ print("WARNING didn't find all translations for menu %s" % ++ (node.attrs['name'],)) ++ translation = [] ++ break ++ translation.append(xtb[id]) ++ else: ++ translation.append(part.GetPresentation()) ++ ++ if len(translation): ++ translations.append([message.GetId(), ''.join(translation)]) ++ ++ with util.WrapOutputStream(open(output_file, 'wb')) as f: ++ transl2tc.TranslationToTc.WriteTranslations(f, translations) +diff --git a/tools/grit/grit/tool/newgrd.py b/tools/grit/grit/tool/newgrd.py +new file mode 100644 +index 0000000000..66a18e9c04 +--- /dev/null ++++ b/tools/grit/grit/tool/newgrd.py +@@ -0,0 +1,85 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Tool to create a new, empty .grd file with all the basic sections. ++''' ++ ++from __future__ import print_function ++ ++import getopt ++import sys ++ ++from grit.tool import interface ++from grit import constants ++from grit import util ++ ++# The contents of the new .grd file ++_FILE_CONTENTS = '''\ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++''' % constants.ENCODING_CHECK ++ ++ ++class NewGrd(interface.Tool): ++ '''Usage: grit newgrd OUTPUT_FILE ++ ++Creates a new, empty .grd file OUTPUT_FILE with comments about what to put ++where in the file.''' ++ ++ def ShortDescription(self): ++ return 'Create a new empty .grd file.' ++ ++ def ParseOptions(self, args): ++ """Set this objects and return all non-option arguments.""" ++ own_opts, args = getopt.getopt(args, '', ('help',)) ++ for key, val in own_opts: ++ if key == '--help': ++ self.ShowUsage() ++ sys.exit(0) ++ return args ++ ++ def Run(self, opts, args): ++ args = self.ParseOptions(args) ++ if len(args) != 1: ++ print('This tool requires exactly one argument, the name of the output ' ++ 'file.') ++ return 2 ++ filename = args[0] ++ with util.WrapOutputStream(open(filename, 'wb'), 'utf-8') as out: ++ out.write(_FILE_CONTENTS) ++ print("Wrote file %s" % filename) +diff --git a/tools/grit/grit/tool/newgrd_unittest.py b/tools/grit/grit/tool/newgrd_unittest.py +new file mode 100644 +index 0000000000..f7c8831df5 +--- /dev/null ++++ b/tools/grit/grit/tool/newgrd_unittest.py +@@ -0,0 +1,51 @@ ++#!/usr/bin/env python ++# Copyright 2020 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for the 'grit newgrd' tool.''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++from grit import util ++from grit.tool import newgrd ++ ++ ++class DummyOpts(object): ++ """Options needed by NewGrd.""" ++ ++ ++class NewgrdUnittest(unittest.TestCase): ++ ++ def testNewFile(self): ++ """Create a new file.""" ++ tool = newgrd.NewGrd() ++ with util.TempDir({}) as output_dir: ++ output_file = os.path.join(output_dir.GetPath(), 'new.grd') ++ self.assertIsNone(tool.Run(DummyOpts(), [output_file])) ++ self.assertTrue(os.path.exists(output_file)) ++ ++ def testMissingFile(self): ++ """Verify failure w/out file output.""" ++ tool = newgrd.NewGrd() ++ ret = tool.Run(DummyOpts(), []) ++ self.assertIsNotNone(ret) ++ self.assertGreater(ret, 0) ++ ++ def testTooManyArgs(self): ++ """Verify failure w/too many outputs.""" ++ tool = newgrd.NewGrd() ++ ret = tool.Run(DummyOpts(), ['a', 'b']) ++ self.assertIsNotNone(ret) ++ self.assertGreater(ret, 0) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/tool/postprocess_interface.py b/tools/grit/grit/tool/postprocess_interface.py +new file mode 100644 +index 0000000000..4bb8c5871f +--- /dev/null ++++ b/tools/grit/grit/tool/postprocess_interface.py +@@ -0,0 +1,29 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++''' Base class for postprocessing of RC files. ++''' ++ ++from __future__ import print_function ++ ++class PostProcessor(object): ++ ''' Base class for postprocessing of the RC file data before being ++ output through the RC2GRD tool. You should implement this class if ++ you want GRIT to do specific things to the RC files after it has ++ converted the data into GRD format, i.e. change the content of the ++ RC file, and put it into a P4 changelist, etc.''' ++ ++ ++ def Process(self, rctext, rcpath, grdnode): ++ ''' Processes the data in rctext and grdnode. ++ Args: ++ rctext: string containing the contents of the RC file being processed. ++ rcpath: the path used to access the file. ++ grdtext: the root node of the grd xml data generated by ++ the rc2grd tool. ++ ++ Return: ++ The root node of the processed GRD tree. ++ ''' ++ raise NotImplementedError() +diff --git a/tools/grit/grit/tool/postprocess_unittest.py b/tools/grit/grit/tool/postprocess_unittest.py +new file mode 100644 +index 0000000000..77fe228bbe +--- /dev/null ++++ b/tools/grit/grit/tool/postprocess_unittest.py +@@ -0,0 +1,64 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit test that checks postprocessing of files. ++ Tests postprocessing by having the postprocessor ++ modify the grd data tree, changing the message name attributes. ++''' ++ ++from __future__ import print_function ++ ++import os ++import re ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++import grit.tool.postprocess_interface ++from grit.tool import rc2grd ++ ++ ++class PostProcessingUnittest(unittest.TestCase): ++ ++ def testPostProcessing(self): ++ rctext = '''STRINGTABLE ++BEGIN ++ DUMMY_STRING_1 "String 1" ++ // Some random description ++ DUMMY_STRING_2 "This text was added during preprocessing" ++END ++ ''' ++ tool = rc2grd.Rc2Grd() ++ class DummyOpts(object): ++ verbose = False ++ extra_verbose = False ++ tool.o = DummyOpts() ++ tool.post_process = 'grit.tool.postprocess_unittest.DummyPostProcessor' ++ result = tool.Process(rctext, '.\resource.rc') ++ ++ self.failUnless( ++ result.children[2].children[2].children[0].attrs['name'] == 'SMART_STRING_1') ++ self.failUnless( ++ result.children[2].children[2].children[1].attrs['name'] == 'SMART_STRING_2') ++ ++class DummyPostProcessor(grit.tool.postprocess_interface.PostProcessor): ++ ''' ++ Post processing replaces all message name attributes containing "DUMMY" to ++ "SMART". ++ ''' ++ def Process(self, rctext, rcpath, grdnode): ++ smarter = re.compile(r'(DUMMY)(.*)') ++ messages = grdnode.children[2].children[2] ++ for node in messages.children: ++ name_attr = node.attrs['name'] ++ m = smarter.search(name_attr) ++ if m: ++ node.attrs['name'] = 'SMART' + m.group(2) ++ return grdnode ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/tool/preprocess_interface.py b/tools/grit/grit/tool/preprocess_interface.py +new file mode 100644 +index 0000000000..67974e704e +--- /dev/null ++++ b/tools/grit/grit/tool/preprocess_interface.py +@@ -0,0 +1,25 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++''' Base class for preprocessing of RC files. ++''' ++ ++from __future__ import print_function ++ ++class PreProcessor(object): ++ ''' Base class for preprocessing of the RC file data before being ++ output through the RC2GRD tool. You should implement this class if ++ you have specific constructs in your RC files that GRIT cannot handle.''' ++ ++ ++ def Process(self, rctext, rcpath): ++ ''' Processes the data in rctext. ++ Args: ++ rctext: string containing the contents of the RC file being processed ++ rcpath: the path used to access the file. ++ ++ Return: ++ The processed text. ++ ''' ++ raise NotImplementedError() +diff --git a/tools/grit/grit/tool/preprocess_unittest.py b/tools/grit/grit/tool/preprocess_unittest.py +new file mode 100644 +index 0000000000..40b95cd6f8 +--- /dev/null ++++ b/tools/grit/grit/tool/preprocess_unittest.py +@@ -0,0 +1,50 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit test that checks preprocessing of files. ++ Tests preprocessing by adding having the preprocessor ++ provide the actual rctext data. ++''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import unittest ++ ++import grit.tool.preprocess_interface ++from grit.tool import rc2grd ++ ++ ++class PreProcessingUnittest(unittest.TestCase): ++ ++ def testPreProcessing(self): ++ tool = rc2grd.Rc2Grd() ++ class DummyOpts(object): ++ verbose = False ++ extra_verbose = False ++ tool.o = DummyOpts() ++ tool.pre_process = 'grit.tool.preprocess_unittest.DummyPreProcessor' ++ result = tool.Process('', '.\resource.rc') ++ ++ self.failUnless( ++ result.children[2].children[2].children[0].attrs['name'] == 'DUMMY_STRING_1') ++ ++class DummyPreProcessor(grit.tool.preprocess_interface.PreProcessor): ++ def Process(self, rctext, rcpath): ++ rctext = '''STRINGTABLE ++BEGIN ++ DUMMY_STRING_1 "String 1" ++ // Some random description ++ DUMMY_STRING_2 "This text was added during preprocessing" ++END ++ ''' ++ return rctext ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/tools/grit/grit/tool/rc2grd.py b/tools/grit/grit/tool/rc2grd.py +new file mode 100644 +index 0000000000..3195b39000 +--- /dev/null ++++ b/tools/grit/grit/tool/rc2grd.py +@@ -0,0 +1,418 @@ ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''The 'grit rc2grd' tool.''' ++ ++from __future__ import print_function ++ ++import os.path ++import getopt ++import re ++import sys ++ ++import six ++from six import StringIO ++ ++import grit.node.empty ++from grit.node import include ++from grit.node import structure ++from grit.node import message ++ ++from grit.gather import rc ++from grit.gather import tr_html ++ ++from grit.tool import interface ++from grit.tool import postprocess_interface ++from grit.tool import preprocess_interface ++ ++from grit import grd_reader ++from grit import lazy_re ++from grit import tclib ++from grit import util ++ ++ ++# Matches files referenced from an .rc file ++_FILE_REF = lazy_re.compile(r''' ++ ^(?P[A-Z_0-9.]+)[ \t]+ ++ (?P[A-Z_0-9]+)[ \t]+ ++ "(?P.*?([^"]|""))"[ \t]*$''', re.VERBOSE | re.MULTILINE) ++ ++ ++# Matches a dialog section ++_DIALOG = lazy_re.compile( ++ r'^(?P[A-Z0-9_]+)\s+DIALOG(EX)?\s.+?^BEGIN\s*$.+?^END\s*$', ++ re.MULTILINE | re.DOTALL) ++ ++ ++# Matches a menu section ++_MENU = lazy_re.compile(r'^(?P[A-Z0-9_]+)\s+MENU.+?^BEGIN\s*$.+?^END\s*$', ++ re.MULTILINE | re.DOTALL) ++ ++ ++# Matches a versioninfo section ++_VERSIONINFO = lazy_re.compile( ++ r'^(?P[A-Z0-9_]+)\s+VERSIONINFO\s.+?^BEGIN\s*$.+?^END\s*$', ++ re.MULTILINE | re.DOTALL) ++ ++ ++# Matches a stringtable ++_STRING_TABLE = lazy_re.compile( ++ (r'^STRINGTABLE(\s+(PRELOAD|DISCARDABLE|CHARACTERISTICS.+|LANGUAGE.+|' ++ r'VERSION.+))*\s*\nBEGIN\s*$(?P.+?)^END\s*$'), ++ re.MULTILINE | re.DOTALL) ++ ++ ++# Matches each message inside a stringtable, breaking it up into comments, ++# the ID of the message, and the (RC-escaped) message text. ++_MESSAGE = lazy_re.compile(r''' ++ (?P(^\s+//.+?)*) # 0 or more lines of comments preceding the message ++ ^\s* ++ (?P[A-Za-z0-9_]+) # id ++ \s+ ++ "(?P.*?([^"]|""))"([^"]|$) # The message itself ++ ''', re.MULTILINE | re.DOTALL | re.VERBOSE) ++ ++ ++# Matches each line of comment text in a multi-line comment. ++_COMMENT_TEXT = lazy_re.compile(r'^\s*//\s*(?P.+?)$', re.MULTILINE) ++ ++ ++# Matches a string that is empty or all whitespace ++_WHITESPACE_ONLY = lazy_re.compile(r'\A\s*\Z', re.MULTILINE) ++ ++ ++# Finds printf and FormatMessage style format specifiers ++# Uses non-capturing groups except for the outermost group, so the output of ++# re.split() should include both the normal text and what we intend to ++# replace with placeholders. ++# TODO(joi) Check documentation for printf (and Windows variants) and FormatMessage ++_FORMAT_SPECIFIER = lazy_re.compile( ++ r'(%[-# +]?(?:[0-9]*|\*)(?:\.(?:[0-9]+|\*))?(?:h|l|L)?' # printf up to last char ++ r'(?:d|i|o|u|x|X|e|E|f|F|g|G|c|r|s|ls|ws)' # printf last char ++ r'|\$[1-9][0-9]*)') # FormatMessage ++ ++ ++class Rc2Grd(interface.Tool): ++ '''A tool for converting .rc files to .grd files. This tool is only for ++converting the source (nontranslated) .rc file to a .grd file. For importing ++existing translations, use the rc2xtb tool. ++ ++Usage: grit [global options] rc2grd [OPTIONS] RCFILE ++ ++The tool takes a single argument, which is the path to the .rc file to convert. ++It outputs a .grd file with the same name in the same directory as the .rc file. ++The .grd file may have one or more TODO comments for things that have to be ++cleaned up manually. ++ ++OPTIONS may be any of the following: ++ ++ -e ENCODING Specify the ENCODING of the .rc file. Default is 'cp1252'. ++ ++ -h TYPE Specify the TYPE attribute for HTML structures. ++ Default is 'tr_html'. ++ ++ -u ENCODING Specify the ENCODING of HTML files. Default is 'utf-8'. ++ ++ -n MATCH Specify the regular expression to match in comments that will ++ indicate that the resource the comment belongs to is not ++ translateable. Default is 'Not locali(s|z)able'. ++ ++ -r GRDFILE Specify that GRDFILE should be used as a "role model" for ++ any placeholders that otherwise would have had TODO names. ++ This attempts to find an identical message in the GRDFILE ++ and uses that instead of the automatically placeholderized ++ message. ++ ++ --pre CLASS Specify an optional, fully qualified classname, which ++ has to be a subclass of grit.tool.PreProcessor, to ++ run on the text of the RC file before conversion occurs. ++ This can be used to support constructs in the RC files ++ that GRIT cannot handle on its own. ++ ++ --post CLASS Specify an optional, fully qualified classname, which ++ has to be a subclass of grit.tool.PostProcessor, to ++ run on the text of the converted RC file. ++ This can be used to alter the content of the RC file ++ based on the conversion that occured. ++ ++For menus, dialogs and version info, the .grd file will refer to the original ++.rc file. Once conversion is complete, you can strip the original .rc file ++of its string table and all comments as these will be available in the .grd ++file. ++ ++Note that this tool WILL NOT obey C preprocessor rules, so even if something ++is #if 0-ed out it will still be included in the output of this tool ++Therefore, if your .rc file contains sections like this, you should run the ++C preprocessor on the .rc file or manually edit it before using this tool. ++''' ++ ++ def ShortDescription(self): ++ return 'A tool for converting .rc source files to .grd files.' ++ ++ def __init__(self): ++ self.input_encoding = 'cp1252' ++ self.html_type = 'tr_html' ++ self.html_encoding = 'utf-8' ++ self.not_localizable_re = re.compile('Not locali(s|z)able') ++ self.role_model = None ++ self.pre_process = None ++ self.post_process = None ++ ++ def ParseOptions(self, args, help_func=None): ++ '''Given a list of arguments, set this object's options and return ++ all non-option arguments. ++ ''' ++ (own_opts, args) = getopt.getopt(args, 'e:h:u:n:r', ++ ('help', 'pre=', 'post=')) ++ for (key, val) in own_opts: ++ if key == '-e': ++ self.input_encoding = val ++ elif key == '-h': ++ self.html_type = val ++ elif key == '-u': ++ self.html_encoding = val ++ elif key == '-n': ++ self.not_localizable_re = re.compile(val) ++ elif key == '-r': ++ self.role_model = grd_reader.Parse(val) ++ elif key == '--pre': ++ self.pre_process = val ++ elif key == '--post': ++ self.post_process = val ++ elif key == '--help': ++ if help_func is None: ++ self.ShowUsage() ++ else: ++ help_func() ++ sys.exit(0) ++ return args ++ ++ def Run(self, opts, args): ++ args = self.ParseOptions(args) ++ if len(args) != 1: ++ print('This tool takes a single tool-specific argument, the path to the\n' ++ '.rc file to process.') ++ return 2 ++ self.SetOptions(opts) ++ ++ path = args[0] ++ out_path = os.path.join(util.dirname(path), ++ os.path.splitext(os.path.basename(path))[0] + '.grd') ++ ++ rctext = util.ReadFile(path, self.input_encoding) ++ grd_text = six.text_type(self.Process(rctext, path)) ++ with util.WrapOutputStream(open(out_path, 'wb'), 'utf-8') as outfile: ++ outfile.write(grd_text) ++ ++ print('Wrote output file %s.\nPlease check for TODO items in the file.' % ++ (out_path,)) ++ ++ ++ def Process(self, rctext, rc_path): ++ '''Processes 'rctext' and returns a resource tree corresponding to it. ++ ++ Args: ++ rctext: complete text of the rc file ++ rc_path: 'resource\resource.rc' ++ ++ Return: ++ grit.node.base.Node subclass ++ ''' ++ ++ if self.pre_process: ++ preprocess_class = util.NewClassInstance(self.pre_process, ++ preprocess_interface.PreProcessor) ++ if preprocess_class: ++ rctext = preprocess_class.Process(rctext, rc_path) ++ else: ++ self.Out( ++ 'PreProcessing class could not be found. Skipping preprocessing.\n') ++ ++ # Start with a basic skeleton for the .grd file ++ root = grd_reader.Parse(StringIO( ++ ''' ++ ++ ++ ++ ++ ++ ++ ++ ++ '''), util.dirname(rc_path)) ++ includes = root.children[2].children[0] ++ structures = root.children[2].children[1] ++ messages = root.children[2].children[2] ++ assert (isinstance(includes, grit.node.empty.IncludesNode) and ++ isinstance(structures, grit.node.empty.StructuresNode) and ++ isinstance(messages, grit.node.empty.MessagesNode)) ++ ++ self.AddIncludes(rctext, includes) ++ self.AddStructures(rctext, structures, os.path.basename(rc_path)) ++ self.AddMessages(rctext, messages) ++ ++ self.VerboseOut('Validating that all IDs are unique...\n') ++ root.ValidateUniqueIds() ++ self.ExtraVerboseOut('Done validating that all IDs are unique.\n') ++ ++ if self.post_process: ++ postprocess_class = util.NewClassInstance(self.post_process, ++ postprocess_interface.PostProcessor) ++ if postprocess_class: ++ root = postprocess_class.Process(rctext, rc_path, root) ++ else: ++ self.Out( ++ 'PostProcessing class could not be found. Skipping postprocessing.\n') ++ ++ return root ++ ++ ++ def IsHtml(self, res_type, fname): ++ '''Check whether both the type and file extension indicate HTML''' ++ fext = fname.split('.')[-1].lower() ++ return res_type == 'HTML' and fext in ('htm', 'html') ++ ++ ++ def AddIncludes(self, rctext, node): ++ '''Scans 'rctext' for included resources (e.g. BITMAP, ICON) and ++ adds each included resource as an child node of 'node'.''' ++ for m in _FILE_REF.finditer(rctext): ++ id = m.group('id') ++ res_type = m.group('type').upper() ++ fname = rc.Section.UnEscape(m.group('file')) ++ assert fname.find('\n') == -1 ++ if not self.IsHtml(res_type, fname): ++ self.VerboseOut('Processing %s with ID %s (filename: %s)\n' % ++ (res_type, id, fname)) ++ node.AddChild(include.IncludeNode.Construct(node, id, res_type, fname)) ++ ++ ++ def AddStructures(self, rctext, node, rc_filename): ++ '''Scans 'rctext' for structured resources (e.g. menus, dialogs, version ++ information resources and HTML templates) and adds each as a ++ child of 'node'.''' ++ # First add HTML includes ++ for m in _FILE_REF.finditer(rctext): ++ id = m.group('id') ++ res_type = m.group('type').upper() ++ fname = rc.Section.UnEscape(m.group('file')) ++ if self.IsHtml(type, fname): ++ node.AddChild(structure.StructureNode.Construct( ++ node, id, self.html_type, fname, self.html_encoding)) ++ ++ # Then add all RC includes ++ def AddStructure(res_type, id): ++ self.VerboseOut('Processing %s with ID %s\n' % (res_type, id)) ++ node.AddChild(structure.StructureNode.Construct(node, id, res_type, ++ rc_filename, ++ encoding=self.input_encoding)) ++ for m in _MENU.finditer(rctext): ++ AddStructure('menu', m.group('id')) ++ for m in _DIALOG.finditer(rctext): ++ AddStructure('dialog', m.group('id')) ++ for m in _VERSIONINFO.finditer(rctext): ++ AddStructure('version', m.group('id')) ++ ++ ++ def AddMessages(self, rctext, node): ++ '''Scans 'rctext' for all messages in string tables, preprocesses them as ++ much as possible for placeholders (e.g. messages containing $1, $2 or %s, %d ++ type format specifiers get those specifiers replaced with placeholders, and ++ HTML-formatted messages get run through the HTML-placeholderizer). Adds ++ each message as a node child of 'node'.''' ++ for tm in _STRING_TABLE.finditer(rctext): ++ table = tm.group('body') ++ for mm in _MESSAGE.finditer(table): ++ comment_block = mm.group('comment') ++ comment_text = [] ++ for cm in _COMMENT_TEXT.finditer(comment_block): ++ comment_text.append(cm.group('text')) ++ comment_text = ' '.join(comment_text) ++ ++ id = mm.group('id') ++ text = rc.Section.UnEscape(mm.group('text')) ++ ++ self.VerboseOut('Processing message %s (text: "%s")\n' % (id, text)) ++ ++ msg_obj = self.Placeholderize(text) ++ ++ # Messages that contain only placeholders do not need translation. ++ is_translateable = False ++ for item in msg_obj.GetContent(): ++ if isinstance(item, six.string_types): ++ if not _WHITESPACE_ONLY.match(item): ++ is_translateable = True ++ ++ if self.not_localizable_re.search(comment_text): ++ is_translateable = False ++ ++ message_meaning = '' ++ internal_comment = '' ++ ++ # If we have a "role model" (existing GRD file) and this node exists ++ # in the role model, use the description, meaning and translateable ++ # attributes from the role model. ++ if self.role_model: ++ role_node = self.role_model.GetNodeById(id) ++ if role_node: ++ is_translateable = role_node.IsTranslateable() ++ message_meaning = role_node.attrs['meaning'] ++ comment_text = role_node.attrs['desc'] ++ internal_comment = role_node.attrs['internal_comment'] ++ ++ # For nontranslateable messages, we don't want the complexity of ++ # placeholderizing everything. ++ if not is_translateable: ++ msg_obj = tclib.Message(text=text) ++ ++ msg_node = message.MessageNode.Construct(node, msg_obj, id, ++ desc=comment_text, ++ translateable=is_translateable, ++ meaning=message_meaning) ++ msg_node.attrs['internal_comment'] = internal_comment ++ ++ node.AddChild(msg_node) ++ self.ExtraVerboseOut('Done processing message %s\n' % id) ++ ++ ++ def Placeholderize(self, text): ++ '''Creates a tclib.Message object from 'text', attempting to recognize ++ a few different formats of text that can be automatically placeholderized ++ (HTML code, printf-style format strings, and FormatMessage-style format ++ strings). ++ ''' ++ ++ try: ++ # First try HTML placeholderizing. ++ # TODO(joi) Allow use of non-TotalRecall flavors of HTML placeholderizing ++ msg = tr_html.HtmlToMessage(text, True) ++ for item in msg.GetContent(): ++ if not isinstance(item, six.string_types): ++ return msg # Contained at least one placeholder, so we're done ++ ++ # HTML placeholderization didn't do anything, so try to find printf or ++ # FormatMessage format specifiers and change them into placeholders. ++ msg = tclib.Message() ++ parts = _FORMAT_SPECIFIER.split(text) ++ todo_counter = 1 # We make placeholder IDs 'TODO_0001' etc. ++ for part in parts: ++ if _FORMAT_SPECIFIER.match(part): ++ msg.AppendPlaceholder(tclib.Placeholder( ++ 'TODO_%04d' % todo_counter, part, 'TODO')) ++ todo_counter += 1 ++ elif part != '': ++ msg.AppendText(part) ++ ++ if self.role_model and len(parts) > 1: # there are TODO placeholders ++ role_model_msg = self.role_model.UberClique().BestCliqueByOriginalText( ++ msg.GetRealContent(), '') ++ if role_model_msg: ++ # replace wholesale to get placeholder names and examples ++ msg = role_model_msg ++ ++ return msg ++ except: ++ print('Exception processing message with text "%s"' % text) ++ raise +diff --git a/tools/grit/grit/tool/rc2grd_unittest.py b/tools/grit/grit/tool/rc2grd_unittest.py +new file mode 100644 +index 0000000000..6d53794c27 +--- /dev/null ++++ b/tools/grit/grit/tool/rc2grd_unittest.py +@@ -0,0 +1,163 @@ ++#!/usr/bin/env python ++# Copyright (c) 2012 The Chromium Authors. All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++'''Unit tests for grit.tool.rc2grd''' ++ ++from __future__ import print_function ++ ++import os ++import sys ++if __name__ == '__main__': ++ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) ++ ++import re ++import unittest ++ ++from six import StringIO ++ ++from grit import grd_reader ++from grit import util ++from grit.node import base ++from grit.tool import rc2grd ++ ++ ++class Rc2GrdUnittest(unittest.TestCase): ++ def testPlaceholderize(self): ++ tool = rc2grd.Rc2Grd() ++ original = "Hello %s, how are you? I'm $1 years old!" ++ msg = tool.Placeholderize(original) ++ self.failUnless(msg.GetPresentableContent() == "Hello TODO_0001, how are you? I'm TODO_0002 years old!") ++ self.failUnless(msg.GetRealContent() == original) ++ ++ def testHtmlPlaceholderize(self): ++ tool = rc2grd.Rc2Grd() ++ original = "Hello [USERNAME], how are you? I'm [AGE] years old!" ++ msg = tool.Placeholderize(original) ++ self.failUnless(msg.GetPresentableContent() == ++ "Hello BEGIN_BOLDX_USERNAME_XEND_BOLD, how are you? I'm X_AGE_X years old!") ++ self.failUnless(msg.GetRealContent() == original) ++ ++ def testMenuWithoutWhitespaceRegression(self): ++ # There was a problem in the original regular expression for parsing out ++ # menu sections, that would parse the following block of text as a single ++ # menu instead of two. ++ two_menus = ''' ++// Hyper context menus ++IDR_HYPERMENU_FOLDER MENU ++BEGIN ++ POPUP "HyperFolder" ++ BEGIN ++ MENUITEM "Open Containing Folder", IDM_OPENFOLDER ++ END ++END ++ ++IDR_HYPERMENU_FILE MENU ++BEGIN ++ POPUP "HyperFile" ++ BEGIN ++ MENUITEM "Open Folder", IDM_OPENFOLDER ++ END ++END ++ ++''' ++ self.failUnless(len(rc2grd._MENU.findall(two_menus)) == 2) ++ ++ def testRegressionScriptWithTranslateable(self): ++ tool = rc2grd.Rc2Grd() ++ ++ # test rig ++ class DummyNode(base.Node): ++ def AddChild(self, item): ++ self.node = item ++ verbose = False ++ extra_verbose = False ++ tool.not_localizable_re = re.compile('') ++ tool.o = DummyNode() ++ ++ rc_text = '''STRINGTABLE\nBEGIN\nID_BINGO ""\nEND\n''' ++ tool.AddMessages(rc_text, tool.o) ++ self.failUnless(tool.o.node.GetCdata().find('Set As Homepage') != -1) ++ ++ # TODO(joi) Improve the HTML parser to support translateables inside ++ # ', -+ strip_whitespace=True) -+ -+ def InlineCSSText(text, css_filepath): -+ """Helper function that inlines external resources in CSS text""" -+ filepath = os.path.dirname(css_filepath) -+ # Allow custom modifications before inlining images. -+ if rewrite_function: -+ text = rewrite_function(filepath, text, distribution) -+ text = InlineCSSImages(text, filepath) -+ return InlineCSSImports(text, filepath) -+ -+ def InlineCSSFile(src_match, pattern, base_path=input_filepath): -+ """Helper function to inline external CSS files. -+ -+ Args: -+ src_match: A regular expression match with a named group named "filename". -+ pattern: The pattern to replace with the contents of the CSS file. -+ base_path: The base path to use for resolving the CSS file. -+ -+ Returns: -+ The text that should replace the reference to the CSS file. -+ """ -+ filepath = GetFilepath(src_match, base_path) -+ if filepath is None: -+ return src_match.group(0) -+ -+ # Even if names_only is set, the CSS file needs to be opened, because it -+ # can link to images that need to be added to the file set. -+ inlined_files.add(filepath) -+ -+ # Inline stylesheets included in this css file. -+ text = _INCLUDE_RE.sub(InlineIncludeFiles, util.ReadFile(filepath, 'utf-8')) -+ # When resolving CSS files we need to pass in the path so that relative URLs -+ # can be resolved. -+ -+ return pattern % InlineCSSText(text, filepath) -+ -+ def GetUrlRegexString(postfix=''): -+ """Helper function that returns a string for a regex that matches url('') -+ but not url([[ ]]) or url({{ }}). Appends |postfix| to group names. -+ """ -+ url_re = (r'url\((?!\[\[|{{)(?P"|\'|)(?P[^"\'()]*)' -+ r'(?P=q%s)\)') -+ return url_re % (postfix, postfix, postfix) -+ -+ def InlineCSSImages(text, filepath=input_filepath): -+ """Helper function that inlines external images in CSS backgrounds.""" -+ # Replace contents of url() for css attributes: content, background, -+ # or *-image. -+ property_re = r'(content|background|[\w-]*-image):[^;]*' -+ # Replace group names to prevent duplicates when forming value_re. -+ image_set_value_re = (r'image-set\(([ ]*' + GetUrlRegexString('2') + -+ r'[ ]*[0-9.]*x[ ]*(,[ ]*)?)+\)') -+ value_re = '(%s|%s)' % (GetUrlRegexString(), image_set_value_re) -+ css_re = property_re + value_re -+ return re.sub(css_re, lambda m: InlineCSSUrls(m, filepath), text) -+ -+ def InlineCSSUrls(src_match, filepath=input_filepath): -+ """Helper function that inlines each url on a CSS image rule match.""" -+ # Replace contents of url() references in matches. -+ return re.sub(GetUrlRegexString(), -+ lambda m: SrcReplace(m, filepath), -+ src_match.group(0)) -+ -+ def InlineCSSImports(text, filepath=input_filepath): -+ """Helper function that inlines CSS files included via the @import -+ directive. -+ """ -+ return re.sub(r'@import\s+' + GetUrlRegexString() + r';', -+ lambda m: InlineCSSFile(m, '%s', filepath), -+ text) -+ -+ -+ flat_text = util.ReadFile(input_filename, 'utf-8') -+ -+ # Check conditional elements, remove unsatisfied ones from the file. We do -+ # this twice. The first pass is so that we don't even bother calling -+ # InlineScript, InlineCSSFile and InlineIncludeFiles on text we're eventually -+ # going to throw out anyway. -+ flat_text = CheckConditionalElements(flat_text) -+ -+ flat_text = _INCLUDE_RE.sub(InlineIncludeFiles, flat_text) -+ -+ if not preprocess_only: -+ if strip_whitespace: -+ flat_text = minifier.Minify(flat_text.encode('utf-8'), -+ input_filename).decode('utf-8') -+ -+ if not allow_external_script: -+ # We need to inline css and js before we inline images so that image -+ # references gets inlined in the css and js -+ flat_text = re.sub(r'', -+ InlineScript, -+ flat_text) -+ -+ flat_text = _STYLESHEET_RE.sub( -+ lambda m: InlineCSSFile(m, ''), -+ flat_text) -+ -+ # Check conditional elements, second pass. This catches conditionals in any -+ # of the text we just inlined. -+ flat_text = CheckConditionalElements(flat_text) -+ -+ # Allow custom modifications before inlining images. -+ if rewrite_function: -+ flat_text = rewrite_function(input_filepath, flat_text, distribution) -+ -+ if not preprocess_only: -+ flat_text = _SRC_RE.sub(SrcReplace, flat_text) -+ flat_text = _SRCSET_RE.sub(SrcsetReplace, flat_text) -+ -+ # TODO(arv): Only do this inside -+ -+ -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(util.normpath(filename))) -+ -+ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ -+ tmp_dir.CleanUp() -+ -+ def testInlineIgnoresPolymerBindings(self): -+ '''Tests that polymer bindings are ignored when inlining. -+ ''' -+ -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+
    -+
    -+
    -+ -+ -+ ''', -+ -+ 'test.css': ''' -+ .image { -+ background: url('test.png'); -+ background-image: url([[ignoreMe]]); -+ background-image: image-set(url({{alsoMe}}), 1x); -+ background-image: image-set( -+ url({{ignore}}) 1x, -+ url('test.png') 2x); -+ } -+ ''', -+ -+ 'test.png': 'PNG DATA' -+ } -+ -+ expected_inlined = ''' -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+
    -+
    -+
    -+ -+ -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(util.normpath(filename))) -+ -+ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ -+ tmp_dir.CleanUp() -+ -+ def testInlineCSSWithIncludeDirective(self): -+ '''Tests that include directive in external css files also inlined''' -+ -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ ''', -+ -+ 'foo.css': '''''', -+ -+ 'style.css': ''' -+ -+ blink { -+ display: none; -+ } -+ ''', -+ 'style2.css': '''h1 {}''', -+ } -+ -+ expected_inlined = ''' -+ -+ -+ -+ -+ -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ tmp_dir.CleanUp() -+ -+ def testCssIncludedFileNames(self): -+ '''Tests that all included files from css are returned''' -+ -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ ''', -+ -+ 'test.css': ''' -+ -+ ''', -+ -+ 'test2.css': ''' -+ -+ .image { -+ background: url('test.png'); -+ } -+ ''', -+ -+ 'test3.css': '''h1 {}''', -+ -+ 'test.png': 'PNG DATA' -+ } -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ resources = html_inline.GetResourceFilenames(tmp_dir.GetPath('index.html'), -+ None) -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ tmp_dir.CleanUp() -+ -+ def testInlineCSSLinks(self): -+ '''Tests that only CSS files referenced via relative URLs are inlined.''' -+ -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ -+ ''', -+ -+ 'foo.css': ''' -+ @import url(chrome://resources/blurp.css); -+ blink { -+ display: none; -+ } -+ ''', -+ } -+ -+ expected_inlined = ''' -+ -+ -+ -+ -+ -+ -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ tmp_dir.CleanUp() -+ -+ def testFilenameVariableExpansion(self): -+ '''Tests that variables are expanded in filenames before inlining.''' -+ -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ ''', -+ 'style1.css': '''h1 {}''', -+ 'tmpl1.html': '''

    ''', -+ 'script1.js': '''console.log('hello');''', -+ 'img1.png': '''abc''', -+ } -+ -+ expected_inlined = ''' -+ -+ -+ -+ -+ -+

    -+ -+ -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ def replacer(var, repl): -+ return lambda filename: filename.replace('[%s]' % var, repl) -+ -+ # Test normal inlining. -+ result = html_inline.DoInline( -+ tmp_dir.GetPath('index.html'), -+ None, -+ filename_expansion_function=replacer('WHICH', '1')) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ -+ # Test names-only inlining. -+ result = html_inline.DoInline( -+ tmp_dir.GetPath('index.html'), -+ None, -+ names_only=True, -+ filename_expansion_function=replacer('WHICH', '1')) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ tmp_dir.CleanUp() -+ -+ def testWithCloseTags(self): -+ '''Tests that close tags are removed.''' -+ -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''', -+ 'style1.css': '''h1 {}''', -+ 'style2.css': '''h2 {}''', -+ 'tmpl1.html': '''

    ''', -+ 'tmpl2.html': '''

    ''', -+ 'script1.js': '''console.log('hello');''', -+ 'img1.png': '''abc''', -+ } -+ -+ expected_inlined = ''' -+ -+ -+ -+ -+ -+ -+ -+

    -+

    -+

    -+ -+ -+ -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ # Test normal inlining. -+ result = html_inline.DoInline( -+ tmp_dir.GetPath('index.html'), -+ None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ tmp_dir.CleanUp() -+ -+ def testCommentedJsInclude(self): -+ '''Tests that works inside a comment.''' -+ -+ files = { -+ 'include.js': '// ', -+ 'other.js': '// Copyright somebody\nalert(1);', -+ } -+ -+ expected_inlined = '// Copyright somebody\nalert(1);' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ result = html_inline.DoInline(tmp_dir.GetPath('include.js'), None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('include.js')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ tmp_dir.CleanUp() -+ -+ def testCommentedJsIf(self): -+ '''Tests that works inside a comment.''' -+ -+ files = { -+ 'if.js': ''' -+ // -+ yep(); -+ // -+ -+ // -+ nope(); -+ // -+ ''', -+ } -+ -+ expected_inlined = ''' -+ // -+ yep(); -+ // -+ -+ // -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ class FakeGrdNode(object): -+ def EvaluateCondition(self, cond): -+ return eval(cond) -+ -+ result = html_inline.DoInline(tmp_dir.GetPath('if.js'), FakeGrdNode()) -+ resources = result.inlined_files -+ -+ resources.add(tmp_dir.GetPath('if.js')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ tmp_dir.CleanUp() -+ -+ def testImgSrcset(self): -+ '''Tests that img srcset="" attributes are converted.''' -+ -+ # Note that there is no space before "img10.png" and that -+ # "img11.png" has no descriptor. -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''', -+ 'img1.png': '''a1''', -+ 'img2.png': '''a2''', -+ 'img3.png': '''a3''', -+ 'img4.png': '''a4''', -+ 'img5.png': '''a5''', -+ 'img6.png': '''a6''', -+ 'img7.png': '''a7''', -+ 'img8.png': '''a8''', -+ 'img9.png': '''a9''', -+ 'img10.png': '''a10''', -+ 'img11.png': '''a11''', -+ } -+ -+ expected_inlined = ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ # Test normal inlining. -+ result = html_inline.DoInline( -+ tmp_dir.GetPath('index.html'), -+ None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ tmp_dir.CleanUp() -+ -+ def testImgSrcsetIgnoresI18n(self): -+ '''Tests that $i18n{...} strings are ignored when inlining. -+ ''' -+ -+ src_html = ''' -+ -+ -+ -+ -+ -+ -+ ''' -+ -+ files = { -+ 'index.html': src_html, -+ } -+ -+ expected_inlined = src_html -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(util.normpath(filename))) -+ -+ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ tmp_dir.CleanUp() -+ -+ def testSourceSrcset(self): -+ '''Tests that source srcset="" attributes are converted.''' -+ -+ # Note that there is no space before "img10.png" and that -+ # "img11.png" has no descriptor. -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ -+ -+ ''', -+ 'img1.png': '''a1''', -+ 'img2.png': '''a2''', -+ 'img3.png': '''a3''', -+ 'img4.png': '''a4''', -+ 'img5.png': '''a5''', -+ 'img6.png': '''a6''', -+ 'img7.png': '''a7''', -+ 'img8.png': '''a8''', -+ 'img9.png': '''a9''', -+ 'img10.png': '''a10''', -+ 'img11.png': '''a11''', -+ } -+ -+ expected_inlined = ''' -+ -+ -+ -+ -+ -+ -+ -+ ''' -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ # Test normal inlining. -+ result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ self.failUnlessEqual(expected_inlined, -+ util.FixLineEnd(result.inlined_data, '\n')) -+ tmp_dir.CleanUp() -+ -+ def testConditionalInclude(self): -+ '''Tests that output and dependency generation includes only files not'''\ -+ ''' blocked by macros.''' -+ -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''', -+ 'img1.png': '''a1''', -+ 'img2.png': '''a2''', -+ 'img3.png': '''a3''', -+ 'img4.png': '''a4''', -+ 'img5.png': '''a5''', -+ 'img6.png': '''a6''', -+ 'img7.png': '''a7''', -+ 'img8.png': '''a8''', -+ 'img9.png': '''a9''', -+ 'img10.png': '''a10''', -+ } -+ -+ expected_inlined = ''' -+ -+ -+ -+ -+ -+ ''' -+ -+ expected_files = [ -+ 'index.html', -+ 'img1.png', -+ 'img2.png', -+ 'img3.png', -+ 'img7.png', -+ 'img8.png', -+ 'img9.png', -+ 'img10.png' -+ ] -+ -+ source_resources = set() -+ tmp_dir = util.TempDir(files) -+ for filename in expected_files: -+ source_resources.add(tmp_dir.GetPath(filename)) -+ -+ class FakeGrdNode(object): -+ def EvaluateCondition(self, cond): -+ return eval(cond) -+ -+ # Test normal inlining. -+ result = html_inline.DoInline( -+ tmp_dir.GetPath('index.html'), -+ FakeGrdNode()) -+ resources = result.inlined_files -+ resources.add(tmp_dir.GetPath('index.html')) -+ self.failUnlessEqual(resources, source_resources) -+ -+ # ignore whitespace -+ expected_inlined = re.sub(r'\s+', ' ', expected_inlined) -+ actually_inlined = re.sub(r'\s+', ' ', -+ util.FixLineEnd(result.inlined_data, '\n')) -+ self.failUnlessEqual(expected_inlined, actually_inlined); -+ tmp_dir.CleanUp() -+ -+ def testPreprocessOnlyEvaluatesIncludeAndIf(self): -+ '''Tests that preprocess_only=true evaluates and only. ''' -+ -+ files = { -+ 'index.html': ''' -+ -+ -+ -+ -+ -+
    -+ -+
    -+ -+
    -+ -+ -+
    -+ -+
    -+    -+
    -+ -+
    -+
    -+ ''')) -+ html.Parse() -+ trans = html.Translate('en') -+ if (html.GetText() != trans): -+ self.fail() -+ -+ -+ def testHtmlToMessageWithBlockTags(self): -+ msg = tr_html.HtmlToMessage( -+ 'Hello

    Howdiebingo', True) -+ result = msg.GetPresentableContent() -+ self.failUnless( -+ result == 'HelloBEGIN_PARAGRAPHHowdieBEGIN_BLOCKbingoEND_BLOCK') -+ -+ msg = tr_html.HtmlToMessage( -+ 'Hello

    Howdie', True) -+ result = msg.GetPresentableContent() -+ self.failUnless( -+ result == 'HelloBEGIN_PARAGRAPHHowdieBEGIN_BLOCKbingoEND_BLOCK') -+ -+ -+ def testHtmlToMessageRegressions(self): -+ msg = tr_html.HtmlToMessage(' - ', True) -+ result = msg.GetPresentableContent() -+ self.failUnless(result == ' - ') -+ -+ -+ def testEscapeUnescaped(self): -+ text = '©  & "<hello>"' -+ unescaped = util.UnescapeHtml(text) -+ self.failUnless(unescaped == u'\u00a9\u00a0 & ""') -+ escaped_unescaped = util.EscapeHtml(unescaped, True) -+ self.failUnless(escaped_unescaped == -+ u'\u00a9\u00a0 & "<hello>"') -+ -+ def testRegressionCjkHtmlFile(self): -+ # TODO(joi) Fix this problem where unquoted attributes that -+ # have a value that is CJK characters causes the regular expression -+ # match never to return. (culprit is the _ELEMENT regexp( -+ if False: -+ html = self.HtmlFromFileWithManualCheck(util.PathFromRoot( -+ r'grit/testdata/ko_oem_enable_bug.html')) -+ self.failUnless(True) -+ -+ def testRegressionCpuHang(self): -+ # If this regression occurs, the unit test will never return -+ html = tr_html.TrHtml(StringIO( -+ '''''')) -+ html.Parse() -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/gather/txt.py b/tools/grit/grit/gather/txt.py -new file mode 100644 -index 0000000000..e5c10abc28 ---- /dev/null -+++ b/tools/grit/grit/gather/txt.py -@@ -0,0 +1,38 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Supports making amessage from a text file. -+''' -+ -+from __future__ import print_function -+ -+from grit.gather import interface -+from grit import tclib -+ -+ -+class TxtFile(interface.GathererBase): -+ '''A text file gatherer. Very simple, all text from the file becomes a -+ single clique. -+ ''' -+ -+ def Parse(self): -+ self.text_ = self._LoadInputFile() -+ self.clique_ = self.uberclique.MakeClique(tclib.Message(text=self.text_)) -+ -+ def GetText(self): -+ '''Returns the text of what is being gathered.''' -+ return self.text_ -+ -+ def GetTextualIds(self): -+ return [self.extkey] -+ -+ def GetCliques(self): -+ '''Returns the MessageClique objects for all translateable portions.''' -+ return [self.clique_] -+ -+ def Translate(self, lang, pseudo_if_not_available=True, -+ skeleton_gatherer=None, fallback_to_english=False): -+ return self.clique_.MessageForLanguage(lang, -+ pseudo_if_not_available, -+ fallback_to_english).GetRealContent() -diff --git a/tools/grit/grit/gather/txt_unittest.py b/tools/grit/grit/gather/txt_unittest.py -new file mode 100644 -index 0000000000..abb9ed98d7 ---- /dev/null -+++ b/tools/grit/grit/gather/txt_unittest.py -@@ -0,0 +1,35 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for TxtFile gatherer''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+ -+import unittest -+ -+from six import StringIO -+ -+from grit.gather import txt -+ -+ -+class TxtUnittest(unittest.TestCase): -+ def testGather(self): -+ input = StringIO('Hello there\nHow are you?') -+ gatherer = txt.TxtFile(input) -+ gatherer.Parse() -+ self.failUnless(gatherer.GetText() == input.getvalue()) -+ self.failUnless(len(gatherer.GetCliques()) == 1) -+ self.failUnless(gatherer.GetCliques()[0].GetMessage().GetRealContent() == -+ input.getvalue()) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/grd_reader.py b/tools/grit/grit/grd_reader.py -new file mode 100644 -index 0000000000..b7bb782977 ---- /dev/null -+++ b/tools/grit/grit/grd_reader.py -@@ -0,0 +1,238 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Class for reading GRD files into memory, without processing them. -+''' -+ -+from __future__ import print_function -+ -+import os.path -+import sys -+import xml.sax -+import xml.sax.handler -+ -+import six -+ -+from grit import exception -+from grit import util -+from grit.node import mapping -+from grit.node import misc -+ -+ -+class StopParsingException(Exception): -+ '''An exception used to stop parsing.''' -+ pass -+ -+ -+class GrdContentHandler(xml.sax.handler.ContentHandler): -+ def __init__(self, stop_after, debug, dir, defines, tags_to_ignore, -+ target_platform, source): -+ # Invariant of data: -+ # 'root' is the root of the parse tree being created, or None if we haven't -+ # parsed out any elements. -+ # 'stack' is the a stack of elements that we push new nodes onto and -+ # pop from when they finish parsing, or [] if we are not currently parsing. -+ # 'stack[-1]' is the top of the stack. -+ self.root = None -+ self.stack = [] -+ self.stop_after = stop_after -+ self.debug = debug -+ self.dir = dir -+ self.defines = defines -+ self.tags_to_ignore = tags_to_ignore or set() -+ self.ignore_depth = 0 -+ self.target_platform = target_platform -+ self.source = source -+ -+ def startElement(self, name, attrs): -+ if self.ignore_depth or name in self.tags_to_ignore: -+ if self.debug and self.ignore_depth == 0: -+ print("Ignoring element %s and its children" % name) -+ self.ignore_depth += 1 -+ return -+ -+ if self.debug: -+ attr_list = ' '.join('%s="%s"' % kv for kv in attrs.items()) -+ print("Starting parsing of element %s with attributes %r" % -+ (name, attr_list or '(none)')) -+ -+ typeattr = attrs.get('type') -+ node = mapping.ElementToClass(name, typeattr)() -+ node.source = self.source -+ -+ if self.stack: -+ self.stack[-1].AddChild(node) -+ node.StartParsing(name, self.stack[-1]) -+ else: -+ assert self.root is None -+ self.root = node -+ if isinstance(self.root, misc.GritNode): -+ if self.target_platform: -+ self.root.SetTargetPlatform(self.target_platform) -+ node.StartParsing(name, None) -+ if self.defines: -+ node.SetDefines(self.defines) -+ self.stack.append(node) -+ -+ for attr, attrval in attrs.items(): -+ node.HandleAttribute(attr, attrval) -+ -+ def endElement(self, name): -+ if self.ignore_depth: -+ self.ignore_depth -= 1 -+ return -+ -+ if name == 'part': -+ partnode = self.stack[-1] -+ partnode.started_inclusion = True -+ # Add the contents of the sub-grd file as children of the node. -+ partname = os.path.join(self.dir, partnode.GetInputPath()) -+ # Check the GRDP file exists. -+ if not os.path.exists(partname): -+ raise exception.FileNotFound(partname) -+ # Exceptions propagate to the handler in grd_reader.Parse(). -+ oldsource = self.source -+ try: -+ self.source = partname -+ xml.sax.parse(partname, GrdPartContentHandler(self)) -+ finally: -+ self.source = oldsource -+ -+ if self.debug: -+ print("End parsing of element %s" % name) -+ self.stack.pop().EndParsing() -+ -+ if name == self.stop_after: -+ raise StopParsingException() -+ -+ def characters(self, content): -+ if self.ignore_depth == 0: -+ if self.stack[-1]: -+ self.stack[-1].AppendContent(content) -+ -+ def ignorableWhitespace(self, whitespace): -+ # TODO(joi): This is not supported by expat. Should use a different XML -+ # parser? -+ pass -+ -+ -+class GrdPartContentHandler(xml.sax.handler.ContentHandler): -+ def __init__(self, parent): -+ self.parent = parent -+ self.depth = 0 -+ -+ def startElement(self, name, attrs): -+ if self.depth: -+ self.parent.startElement(name, attrs) -+ else: -+ if name != 'grit-part': -+ raise exception.MissingElement("root tag must be ") -+ if attrs: -+ raise exception.UnexpectedAttribute( -+ " tag must not have attributes") -+ self.depth += 1 -+ -+ def endElement(self, name): -+ self.depth -= 1 -+ if self.depth: -+ self.parent.endElement(name) -+ -+ def characters(self, content): -+ self.parent.characters(content) -+ -+ def ignorableWhitespace(self, whitespace): -+ self.parent.ignorableWhitespace(whitespace) -+ -+ -+def Parse(filename_or_stream, dir=None, stop_after=None, first_ids_file=None, -+ debug=False, defines=None, tags_to_ignore=None, target_platform=None, -+ predetermined_ids_file=None): -+ '''Parses a GRD file into a tree of nodes (from grit.node). -+ -+ If filename_or_stream is a stream, 'dir' should point to the directory -+ notionally containing the stream (this feature is only used in unit tests). -+ -+ If 'stop_after' is provided, the parsing will stop once the first node -+ with this name has been fully parsed (including all its contents). -+ -+ If 'debug' is true, lots of information about the parsing events will be -+ printed out during parsing of the file. -+ -+ If 'first_ids_file' is non-empty, it is used to override the setting for the -+ first_ids_file attribute of the root node. Note that the first_ids_file -+ parameter should be relative to the cwd, even though the first_ids_file -+ attribute of the node is relative to the grd file. -+ -+ If 'target_platform' is set, this is used to determine the target -+ platform of builds, instead of using |sys.platform|. -+ -+ Args: -+ filename_or_stream: './bla.xml' -+ dir: None (if filename_or_stream is a filename) or '.' -+ stop_after: 'inputs' -+ first_ids_file: 'GRIT_DIR/../gritsettings/resource_ids' -+ debug: False -+ defines: dictionary of defines, like {'chromeos': '1'} -+ target_platform: None or the value that would be returned by sys.platform -+ on your target platform. -+ predetermined_ids_file: File path to a file containing a pre-determined -+ mapping from resource names to resource ids which will be used to assign -+ resource ids to those resources. -+ -+ Return: -+ Subclass of grit.node.base.Node -+ -+ Throws: -+ grit.exception.Parsing -+ ''' -+ -+ if isinstance(filename_or_stream, six.string_types): -+ source = filename_or_stream -+ if dir is None: -+ dir = util.dirname(filename_or_stream) -+ else: -+ source = None -+ -+ handler = GrdContentHandler(stop_after=stop_after, debug=debug, dir=dir, -+ defines=defines, tags_to_ignore=tags_to_ignore, -+ target_platform=target_platform, source=source) -+ try: -+ xml.sax.parse(filename_or_stream, handler) -+ except StopParsingException: -+ assert stop_after -+ pass -+ except: -+ if not debug: -+ print("parse exception: run GRIT with the -x flag to debug .grd problems") -+ raise -+ -+ if handler.root.name != 'grit': -+ raise exception.MissingElement("root tag must be ") -+ -+ if hasattr(handler.root, 'SetOwnDir'): -+ # Fix up the base_dir so it is relative to the input file. -+ assert dir is not None -+ handler.root.SetOwnDir(dir) -+ -+ if isinstance(handler.root, misc.GritNode): -+ handler.root.SetPredeterminedIdsFile(predetermined_ids_file) -+ if first_ids_file: -+ # Make the path to the first_ids_file relative to the grd file, -+ # unless it begins with GRIT_DIR. -+ GRIT_DIR_PREFIX = 'GRIT_DIR' -+ if not (first_ids_file.startswith(GRIT_DIR_PREFIX) -+ and first_ids_file[len(GRIT_DIR_PREFIX)] in ['/', '\\']): -+ rel_dir = os.path.relpath(os.getcwd(), dir) -+ first_ids_file = util.normpath(os.path.join(rel_dir, first_ids_file)) -+ handler.root.attrs['first_ids_file'] = first_ids_file -+ # Assign first ids to the nodes that don't have them. -+ handler.root.AssignFirstIds(filename_or_stream, defines) -+ -+ return handler.root -+ -+ -+if __name__ == '__main__': -+ util.ChangeStdoutEncoding() -+ print(six.text_type(Parse(sys.argv[1]))) -diff --git a/tools/grit/grit/grd_reader_unittest.py b/tools/grit/grit/grd_reader_unittest.py -new file mode 100644 -index 0000000000..920a92f9c0 ---- /dev/null -+++ b/tools/grit/grit/grd_reader_unittest.py -@@ -0,0 +1,346 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grd_reader package''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -+ -+import unittest -+ -+import six -+from six import StringIO -+ -+from grit import exception -+from grit import grd_reader -+from grit import util -+from grit.node import empty -+from grit.node import message -+ -+ -+class GrdReaderUnittest(unittest.TestCase): -+ def testParsingAndXmlOutput(self): -+ input = u''' -+ -+ -+ -+ -+ -+ -+ -+ -+ Hello %sJoi, how are you doing today? -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+''' -+ pseudo_file = StringIO(input) -+ tree = grd_reader.Parse(pseudo_file, '.') -+ output = six.text_type(tree) -+ expected_output = input.replace(u' base_dir="."', u'') -+ self.assertEqual(expected_output, output) -+ self.failUnless(tree.GetNodeById('IDS_GREETING')) -+ -+ -+ def testStopAfter(self): -+ input = u''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+''' -+ pseudo_file = StringIO(input) -+ tree = grd_reader.Parse(pseudo_file, '.', stop_after='outputs') -+ # only an child -+ self.failUnless(len(tree.children) == 1) -+ self.failUnless(tree.children[0].name == 'outputs') -+ -+ def testLongLinesWithComments(self): -+ input = u''' -+ -+ -+ -+ -+ This is a very long line with no linebreaks yes yes it stretches on and on and on! -+ -+ -+ -+''' -+ pseudo_file = StringIO(input) -+ tree = grd_reader.Parse(pseudo_file, '.') -+ -+ greeting = tree.GetNodeById('IDS_GREETING') -+ self.failUnless(greeting.GetCliques()[0].GetMessage().GetRealContent() == -+ 'This is a very long line with no linebreaks yes yes it ' -+ 'stretches on and on and on!') -+ -+ def doTestAssignFirstIds(self, first_ids_path): -+ input = u''' -+ -+ -+ -+ -+ test -+ -+ -+ -+''' % first_ids_path -+ pseudo_file = StringIO(input) -+ grit_root_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), -+ '..') -+ fake_input_path = os.path.join( -+ grit_root_dir, "grit/testdata/chrome/app/generated_resources.grd") -+ root = grd_reader.Parse(pseudo_file, os.path.split(fake_input_path)[0]) -+ root.AssignFirstIds(fake_input_path, {}) -+ messages_node = root.children[0].children[0] -+ self.failUnless(isinstance(messages_node, empty.MessagesNode)) -+ self.failUnless(messages_node.attrs["first_id"] != -+ empty.MessagesNode().DefaultAttributes()["first_id"]) -+ -+ def testAssignFirstIds(self): -+ self.doTestAssignFirstIds("../../tools/grit/resource_ids") -+ -+ def testAssignFirstIdsUseGritDir(self): -+ self.doTestAssignFirstIds("GRIT_DIR/grit/testdata/tools/grit/resource_ids") -+ -+ def testAssignFirstIdsMultipleMessages(self): -+ """If there are multiple messages sections, the resource_ids file -+ needs to list multiple first_id values.""" -+ input = u''' -+ -+ -+ -+ -+ test -+ -+ -+ -+ -+ test2 -+ -+ -+ -+''' -+ pseudo_file = StringIO(input) -+ grit_root_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), -+ '..') -+ fake_input_path = os.path.join(grit_root_dir, "grit/testdata/test.grd") -+ -+ root = grd_reader.Parse(pseudo_file, os.path.split(fake_input_path)[0]) -+ root.AssignFirstIds(fake_input_path, {}) -+ messages_node = root.children[0].children[0] -+ self.assertTrue(isinstance(messages_node, empty.MessagesNode)) -+ self.assertEqual('100', messages_node.attrs["first_id"]) -+ messages_node = root.children[0].children[1] -+ self.assertTrue(isinstance(messages_node, empty.MessagesNode)) -+ self.assertEqual('10000', messages_node.attrs["first_id"]) -+ -+ def testUseNameForIdAndPpIfdef(self): -+ input = u''' -+ -+ -+ -+ -+ -+ Hello! -+ -+ -+ -+ -+''' -+ pseudo_file = StringIO(input) -+ root = grd_reader.Parse(pseudo_file, '.', defines={'hello': '1'}) -+ -+ # Check if the ID is set to the name. In the past, there was a bug -+ # that caused the ID to be a generated number. -+ hello = root.GetNodeById('IDS_HELLO') -+ self.failUnless(hello.GetCliques()[0].GetId() == 'IDS_HELLO') -+ -+ def testUseNameForIdWithIfElse(self): -+ input = u''' -+ -+ -+ -+ -+ -+ -+ Hello! -+ -+ -+ -+ -+ Yellow! -+ -+ -+ -+ -+ -+''' -+ pseudo_file = StringIO(input) -+ root = grd_reader.Parse(pseudo_file, '.', defines={'hello': '1'}) -+ -+ # Check if the ID is set to the name. In the past, there was a bug -+ # that caused the ID to be a generated number. -+ hello = root.GetNodeById('IDS_HELLO') -+ self.failUnless(hello.GetCliques()[0].GetId() == 'IDS_HELLO') -+ -+ def testPartInclusionAndCorrectSource(self): -+ arbitrary_path_grd = u'''\ -+ -+ test5 -+ ''' -+ tmp_dir = util.TempDir({'arbitrary_path.grp': arbitrary_path_grd}) -+ arbitrary_path_grd_file = tmp_dir.GetPath('arbitrary_path.grp') -+ top_grd = u'''\ -+ -+ -+ -+ -+ test -+ -+ -+ -+ -+ -+ ''' % arbitrary_path_grd_file -+ sub_grd = u'''\ -+ -+ test2 -+ -+ test3 -+ ''' -+ subsub_grd = u'''\ -+ -+ test4 -+ ''' -+ expected_output = u'''\ -+ -+ -+ -+ -+ test -+ -+ -+ -+ test2 -+ -+ -+ -+ test4 -+ -+ -+ -+ test3 -+ -+ -+ -+ -+ test5 -+ -+ -+ -+ -+ ''' % arbitrary_path_grd_file -+ -+ with util.TempDir({'sub.grp': sub_grd, -+ 'subsub.grp': subsub_grd}) as tmp_sub_dir: -+ output = grd_reader.Parse(StringIO(top_grd), -+ tmp_sub_dir.GetPath()) -+ correct_sources = { -+ 'IDS_TEST': None, -+ 'IDS_TEST2': tmp_sub_dir.GetPath('sub.grp'), -+ 'IDS_TEST3': tmp_sub_dir.GetPath('sub.grp'), -+ 'IDS_TEST4': tmp_sub_dir.GetPath('subsub.grp'), -+ 'IDS_TEST5': arbitrary_path_grd_file, -+ } -+ -+ for node in output.ActiveDescendants(): -+ with node: -+ if isinstance(node, message.MessageNode): -+ self.assertEqual(correct_sources[node.attrs.get('name')], node.source) -+ self.assertEqual(expected_output.split(), output.FormatXml().split()) -+ tmp_dir.CleanUp() -+ -+ def testPartInclusionFailure(self): -+ template = u''' -+ -+ -+ %s -+ -+ ''' -+ -+ part_failures = [ -+ (exception.UnexpectedContent, u'fnord'), -+ (exception.UnexpectedChild, -+ u''), -+ (exception.FileNotFound, u''), -+ ] -+ for raises, data in part_failures: -+ data = StringIO(template % data) -+ self.assertRaises(raises, grd_reader.Parse, data, '.') -+ -+ gritpart_failures = [ -+ (exception.UnexpectedAttribute, u''), -+ (exception.MissingElement, u''), -+ ] -+ for raises, data in gritpart_failures: -+ top_grd = StringIO(template % u'') -+ with util.TempDir({'bad.grp': data}) as temp_dir: -+ self.assertRaises(raises, grd_reader.Parse, top_grd, temp_dir.GetPath()) -+ -+ def testEarlyEnoughPlatformSpecification(self): -+ # This is a regression test for issue -+ # https://code.google.com/p/grit-i18n/issues/detail?id=23 -+ grd_text = u''' -+ -+ -+ -+ -+ foo -+ -+ -+ -+ boo -+ -+ -+ -+ ''' % sys.platform -+ with util.TempDir({}) as temp_dir: -+ grd_reader.Parse(StringIO(grd_text), temp_dir.GetPath(), -+ target_platform='android') -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/grit-todo.xml b/tools/grit/grit/grit-todo.xml -new file mode 100644 -index 0000000000..b8c20fdfad ---- /dev/null -+++ b/tools/grit/grit/grit-todo.xml -@@ -0,0 +1,62 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/tools/grit/grit/grit_runner.py b/tools/grit/grit/grit_runner.py -new file mode 100644 -index 0000000000..26aa0d58c4 ---- /dev/null -+++ b/tools/grit/grit/grit_runner.py -@@ -0,0 +1,334 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Command processor for GRIT. This is the script you invoke to run the various -+GRIT tools. -+""" -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -+ -+import getopt -+ -+from grit import util -+ -+import grit.extern.FP -+ -+# Tool info factories; these import only within each factory to avoid -+# importing most of the GRIT code until required. -+def ToolFactoryBuild(): -+ import grit.tool.build -+ return grit.tool.build.RcBuilder() -+ -+def ToolFactoryBuildInfo(): -+ import grit.tool.buildinfo -+ return grit.tool.buildinfo.DetermineBuildInfo() -+ -+def ToolFactoryCount(): -+ import grit.tool.count -+ return grit.tool.count.CountMessage() -+ -+def ToolFactoryDiffStructures(): -+ import grit.tool.diff_structures -+ return grit.tool.diff_structures.DiffStructures() -+ -+def ToolFactoryMenuTranslationsFromParts(): -+ import grit.tool.menu_from_parts -+ return grit.tool.menu_from_parts.MenuTranslationsFromParts() -+ -+def ToolFactoryNewGrd(): -+ import grit.tool.newgrd -+ return grit.tool.newgrd.NewGrd() -+ -+def ToolFactoryResizeDialog(): -+ import grit.tool.resize -+ return grit.tool.resize.ResizeDialog() -+ -+def ToolFactoryRc2Grd(): -+ import grit.tool.rc2grd -+ return grit.tool.rc2grd.Rc2Grd() -+ -+def ToolFactoryTest(): -+ import grit.tool.test -+ return grit.tool.test.TestTool() -+ -+def ToolFactoryTranslationToTc(): -+ import grit.tool.transl2tc -+ return grit.tool.transl2tc.TranslationToTc() -+ -+def ToolFactoryUnit(): -+ import grit.tool.unit -+ return grit.tool.unit.UnitTestTool() -+ -+ -+def ToolFactoryUpdateResourceIds(): -+ import grit.tool.update_resource_ids -+ return grit.tool.update_resource_ids.UpdateResourceIds() -+ -+ -+def ToolFactoryXmb(): -+ import grit.tool.xmb -+ return grit.tool.xmb.OutputXmb() -+ -+def ToolAndroid2Grd(): -+ import grit.tool.android2grd -+ return grit.tool.android2grd.Android2Grd() -+ -+# Keys for the following map -+_FACTORY = 1 -+_REQUIRES_INPUT = 2 -+_HIDDEN = 3 # optional key - presence indicates tool is hidden -+ -+# Maps tool names to the tool's module. Done as a list of (key, value) tuples -+# instead of a map to preserve ordering. -+_TOOLS = [ -+ ['android2grd', { -+ _FACTORY: ToolAndroid2Grd, -+ _REQUIRES_INPUT: False -+ }], -+ ['build', { -+ _FACTORY: ToolFactoryBuild, -+ _REQUIRES_INPUT: True -+ }], -+ ['buildinfo', { -+ _FACTORY: ToolFactoryBuildInfo, -+ _REQUIRES_INPUT: True -+ }], -+ ['count', { -+ _FACTORY: ToolFactoryCount, -+ _REQUIRES_INPUT: True -+ }], -+ [ -+ 'menufromparts', -+ { -+ _FACTORY: ToolFactoryMenuTranslationsFromParts, -+ _REQUIRES_INPUT: True, -+ _HIDDEN: True -+ } -+ ], -+ ['newgrd', { -+ _FACTORY: ToolFactoryNewGrd, -+ _REQUIRES_INPUT: False -+ }], -+ ['rc2grd', { -+ _FACTORY: ToolFactoryRc2Grd, -+ _REQUIRES_INPUT: False -+ }], -+ ['resize', { -+ _FACTORY: ToolFactoryResizeDialog, -+ _REQUIRES_INPUT: True -+ }], -+ ['sdiff', { -+ _FACTORY: ToolFactoryDiffStructures, -+ _REQUIRES_INPUT: False -+ }], -+ ['test', { -+ _FACTORY: ToolFactoryTest, -+ _REQUIRES_INPUT: True, -+ _HIDDEN: True -+ }], -+ [ -+ 'transl2tc', -+ { -+ _FACTORY: ToolFactoryTranslationToTc, -+ _REQUIRES_INPUT: False -+ } -+ ], -+ ['unit', { -+ _FACTORY: ToolFactoryUnit, -+ _REQUIRES_INPUT: False -+ }], -+ [ -+ 'update_resource_ids', -+ { -+ _FACTORY: ToolFactoryUpdateResourceIds, -+ _REQUIRES_INPUT: False -+ } -+ ], -+ ['xmb', { -+ _FACTORY: ToolFactoryXmb, -+ _REQUIRES_INPUT: True -+ }], -+] -+ -+ -+def PrintUsage(): -+ tool_list = '' -+ for (tool, info) in _TOOLS: -+ if not _HIDDEN in info: -+ tool_list += ' %-12s %s\n' % ( -+ tool, info[_FACTORY]().ShortDescription()) -+ -+ print("""GRIT - the Google Resource and Internationalization Tool -+ -+Usage: grit [GLOBALOPTIONS] TOOL [args to tool] -+ -+Global options: -+ -+ -i INPUT Specifies the INPUT file to use (a .grd file). If this is not -+ specified, GRIT will look for the environment variable GRIT_INPUT. -+ If it is not present either, GRIT will try to find an input file -+ named 'resource.grd' in the current working directory. -+ -+ -h MODULE Causes GRIT to use MODULE.UnsignedFingerPrint instead of -+ grit.extern.FP.UnsignedFingerprint. MODULE must be -+ available somewhere in the PYTHONPATH search path. -+ -+ -v Print more verbose runtime information. -+ -+ -x Print extremely verbose runtime information. Implies -v -+ -+ -p FNAME Specifies that GRIT should profile its execution and output the -+ results to the file FNAME. -+ -+Tools: -+ -+ TOOL can be one of the following: -+%s -+ For more information on how to use a particular tool, and the specific -+ arguments you can send to that tool, execute 'grit help TOOL' -+""" % (tool_list)) -+ -+ -+class Options(object): -+ """Option storage and parsing.""" -+ -+ def __init__(self): -+ self.hash = None -+ self.input = None -+ self.verbose = False -+ self.extra_verbose = False -+ self.output_stream = sys.stdout -+ self.profile_dest = None -+ -+ def ReadOptions(self, args): -+ """Reads options from the start of args and returns the remainder.""" -+ (opts, args) = getopt.getopt(args, 'vxi:p:h:', ('help',)) -+ for (key, val) in opts: -+ if key == '-h': self.hash = val -+ elif key == '-i': self.input = val -+ elif key == '-v': -+ self.verbose = True -+ util.verbose = True -+ elif key == '-x': -+ self.verbose = True -+ util.verbose = True -+ self.extra_verbose = True -+ util.extra_verbose = True -+ elif key == '-p': self.profile_dest = val -+ elif key == '--help': -+ PrintUsage() -+ sys.exit(0) -+ -+ if not self.input: -+ if 'GRIT_INPUT' in os.environ: -+ self.input = os.environ['GRIT_INPUT'] -+ else: -+ self.input = 'resource.grd' -+ -+ return args -+ -+ def __repr__(self): -+ return '(verbose: %d, input: %s)' % ( -+ self.verbose, self.input) -+ -+ -+def _GetToolInfo(tool): -+ """Returns the info map for the tool named 'tool' or None if there is no -+ such tool.""" -+ matches = [t for t in _TOOLS if t[0] == tool] -+ if not matches: -+ return None -+ else: -+ return matches[0][1] -+ -+ -+def Main(args=None): -+ """Parses arguments and does the appropriate thing.""" -+ util.ChangeStdoutEncoding() -+ -+ # Support for setuptools console wrappers. -+ if args is None: -+ args = sys.argv[1:] -+ -+ options = Options() -+ try: -+ args = options.ReadOptions(args) # args may be shorter after this -+ except getopt.GetoptError as e: -+ print("grit:", str(e)) -+ print("Try running 'grit help' for valid options.") -+ return 1 -+ if not args: -+ print("No tool provided. Try running 'grit help' for a list of tools.") -+ return 2 -+ -+ tool = args[0] -+ if tool == 'help': -+ if len(args) == 1: -+ PrintUsage() -+ return 0 -+ else: -+ tool = args[1] -+ if not _GetToolInfo(tool): -+ print("No such tool. Try running 'grit help' for a list of tools.") -+ return 2 -+ -+ print("Help for 'grit %s' (for general help, run 'grit help'):\n" % -+ (tool,)) -+ _GetToolInfo(tool)[_FACTORY]().ShowUsage() -+ return 0 -+ if not _GetToolInfo(tool): -+ print("No such tool. Try running 'grit help' for a list of tools.") -+ return 2 -+ -+ try: -+ if _GetToolInfo(tool)[_REQUIRES_INPUT]: -+ os.stat(options.input) -+ except OSError: -+ print('Input file %s not found.\n' -+ 'To specify a different input file:\n' -+ ' 1. Use the GRIT_INPUT environment variable.\n' -+ ' 2. Use the -i command-line option. This overrides ' -+ 'GRIT_INPUT.\n' -+ ' 3. Specify neither GRIT_INPUT or -i and GRIT will try to load ' -+ "'resource.grd'\n" -+ ' from the current directory.' % options.input) -+ return 2 -+ -+ if options.hash: -+ grit.extern.FP.UseUnsignedFingerPrintFromModule(options.hash) -+ -+ try: -+ toolobject = _GetToolInfo(tool)[_FACTORY]() -+ if options.profile_dest: -+ import hotshot -+ prof = hotshot.Profile(options.profile_dest) -+ return prof.runcall(toolobject.Run, options, args[1:]) -+ else: -+ return toolobject.Run(options, args[1:]) -+ except getopt.GetoptError as e: -+ print("grit: %s: %s" % (tool, str(e))) -+ print("Try running 'grit help %s' for valid options." % (tool,)) -+ return 1 -+ -+ -+if __name__ == '__main__': -+ sys.path.append( -+ os.path.join( -+ os.path.dirname( -+ os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), -+ 'diagnosis')) -+ try: -+ import crbug_1001171 -+ with crbug_1001171.DumpStateOnLookupError(): -+ sys.exit(Main(sys.argv[1:])) -+ except ImportError: -+ pass -+ -+ sys.exit(Main(sys.argv[1:])) -diff --git a/tools/grit/grit/grit_runner_unittest.py b/tools/grit/grit/grit_runner_unittest.py -new file mode 100644 -index 0000000000..1487001d81 ---- /dev/null -+++ b/tools/grit/grit/grit_runner_unittest.py -@@ -0,0 +1,42 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grit.py''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -+ -+import unittest -+ -+from six import StringIO -+ -+from grit import util -+import grit.grit_runner -+ -+class OptionArgsUnittest(unittest.TestCase): -+ def setUp(self): -+ self.buf = StringIO() -+ self.old_stdout = sys.stdout -+ sys.stdout = self.buf -+ -+ def tearDown(self): -+ sys.stdout = self.old_stdout -+ -+ def testSimple(self): -+ grit.grit_runner.Main(['-i', -+ util.PathFromRoot('grit/testdata/simple-input.xml'), -+ 'test', 'bla', 'voff', 'ga']) -+ output = self.buf.getvalue() -+ self.failUnless(output.count("'test'") == 0) # tool name doesn't occur -+ self.failUnless(output.count('bla')) -+ self.failUnless(output.count('simple-input.xml')) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/lazy_re.py b/tools/grit/grit/lazy_re.py -new file mode 100644 -index 0000000000..5c461e87e7 ---- /dev/null -+++ b/tools/grit/grit/lazy_re.py -@@ -0,0 +1,46 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''In GRIT, we used to compile a lot of regular expressions at parse -+time. Since many of them never get used, we use lazy_re to compile -+them on demand the first time they are used, thus speeding up startup -+time in some cases. -+''' -+ -+from __future__ import print_function -+ -+import re -+ -+ -+class LazyRegexObject(object): -+ '''This object creates a RegexObject with the arguments passed in -+ its constructor, the first time any attribute except the several on -+ the class itself is accessed. This accomplishes lazy compilation of -+ the regular expression while maintaining a nearly-identical -+ interface. -+ ''' -+ -+ def __init__(self, *args, **kwargs): -+ self._stash_args = args -+ self._stash_kwargs = kwargs -+ self._lazy_re = None -+ -+ def _LazyInit(self): -+ if not self._lazy_re: -+ self._lazy_re = re.compile(*self._stash_args, **self._stash_kwargs) -+ -+ def __getattribute__(self, name): -+ if name in ('_LazyInit', '_lazy_re', '_stash_args', '_stash_kwargs'): -+ return object.__getattribute__(self, name) -+ else: -+ self._LazyInit() -+ return getattr(self._lazy_re, name) -+ -+ -+def compile(*args, **kwargs): -+ '''Creates a LazyRegexObject that, when invoked on, will compile a -+ re.RegexObject (via re.compile) with the same arguments passed to -+ this function, and delegate almost all of its methods to it. -+ ''' -+ return LazyRegexObject(*args, **kwargs) -diff --git a/tools/grit/grit/lazy_re_unittest.py b/tools/grit/grit/lazy_re_unittest.py -new file mode 100644 -index 0000000000..8488b454ee ---- /dev/null -+++ b/tools/grit/grit/lazy_re_unittest.py -@@ -0,0 +1,40 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit test for lazy_re. -+''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -+ -+import re -+import unittest -+ -+from grit import lazy_re -+ -+ -+class LazyReUnittest(unittest.TestCase): -+ -+ def testCreatedOnlyOnDemand(self): -+ rex = lazy_re.compile('bingo') -+ self.assertEqual(None, rex._lazy_re) -+ self.assertTrue(rex.match('bingo')) -+ self.assertNotEqual(None, rex._lazy_re) -+ -+ def testJustKwargsWork(self): -+ rex = lazy_re.compile(flags=re.I, pattern='BiNgO') -+ self.assertTrue(rex.match('bingo')) -+ -+ def testPositionalAndKwargsWork(self): -+ rex = lazy_re.compile('BiNgO', flags=re.I) -+ self.assertTrue(rex.match('bingo')) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/node/__init__.py b/tools/grit/grit/node/__init__.py -new file mode 100644 -index 0000000000..2fc0d3360c ---- /dev/null -+++ b/tools/grit/grit/node/__init__.py -@@ -0,0 +1,8 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Package 'grit.node' -+''' -+ -+pass -diff --git a/tools/grit/grit/node/base.py b/tools/grit/grit/node/base.py -new file mode 100644 -index 0000000000..40859d301d ---- /dev/null -+++ b/tools/grit/grit/node/base.py -@@ -0,0 +1,670 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Base types for nodes in a GRIT resource tree. -+''' -+ -+from __future__ import print_function -+ -+import ast -+import os -+import struct -+import sys -+from xml.sax import saxutils -+ -+import six -+ -+from grit import constants -+from grit import clique -+from grit import exception -+from grit import util -+from grit.node import brotli_util -+import grit.format.gzip_string -+ -+ -+class Node(object): -+ '''An item in the tree that has children.''' -+ -+ # Valid content types that can be returned by _ContentType() -+ _CONTENT_TYPE_NONE = 0 # No CDATA content but may have children -+ _CONTENT_TYPE_CDATA = 1 # Only CDATA, no children. -+ _CONTENT_TYPE_MIXED = 2 # CDATA and children, possibly intermingled -+ -+ # Types of files to be compressed by default. -+ _COMPRESS_BY_DEFAULT_EXTENSIONS = ('.js', '.html', '.css', '.svg') -+ -+ # Default nodes to not whitelist skipped -+ _whitelist_marked_as_skip = False -+ -+ # A class-static cache to speed up EvaluateExpression(). -+ # Keys are expressions (e.g. 'is_ios and lang == "fr"'). Values are tuples -+ # (code, variables_in_expr) where code is the compiled expression and can be -+ # directly eval'd, and variables_in_expr is the list of variable and method -+ # names used in the expression (e.g. ['is_ios', 'lang']). -+ eval_expr_cache = {} -+ -+ def __init__(self): -+ self.children = [] # A list of child elements -+ self.mixed_content = [] # A list of u'' and/or child elements (this -+ # duplicates 'children' but -+ # is needed to preserve markup-type content). -+ self.name = u'' # The name of this element -+ self.attrs = {} # The set of attributes (keys to values) -+ self.parent = None # Our parent unless we are the root element. -+ self.uberclique = None # Allows overriding uberclique for parts of tree -+ self.source = None # File that this node was parsed from -+ -+ # This context handler allows you to write "with node:" and get a -+ # line identifying the offending node if an exception escapes from the body -+ # of the with statement. -+ def __enter__(self): -+ return self -+ -+ def __exit__(self, exc_type, exc_value, traceback): -+ if exc_type is not None: -+ print(u'Error processing node %s: %s' % (six.text_type(self), exc_value)) -+ -+ def __iter__(self): -+ '''A preorder iteration through the tree that this node is the root of.''' -+ return self.Preorder() -+ -+ def Preorder(self): -+ '''Generator that generates first this node, then the same generator for -+ any child nodes.''' -+ yield self -+ for child in self.children: -+ for iterchild in child.Preorder(): -+ yield iterchild -+ -+ def ActiveChildren(self): -+ '''Returns the children of this node that should be included in the current -+ configuration. Overridden by .''' -+ return [node for node in self.children if not node.WhitelistMarkedAsSkip()] -+ -+ def ActiveDescendants(self): -+ '''Yields the current node and all descendants that should be included in -+ the current configuration, in preorder.''' -+ yield self -+ for child in self.ActiveChildren(): -+ for descendant in child.ActiveDescendants(): -+ yield descendant -+ -+ def GetRoot(self): -+ '''Returns the root Node in the tree this Node belongs to.''' -+ curr = self -+ while curr.parent: -+ curr = curr.parent -+ return curr -+ -+ # TODO(joi) Use this (currently untested) optimization?: -+ #if hasattr(self, '_root'): -+ # return self._root -+ #curr = self -+ #while curr.parent and not hasattr(curr, '_root'): -+ # curr = curr.parent -+ #if curr.parent: -+ # self._root = curr._root -+ #else: -+ # self._root = curr -+ #return self._root -+ -+ def StartParsing(self, name, parent): -+ '''Called at the start of parsing. -+ -+ Args: -+ name: u'elementname' -+ parent: grit.node.base.Node or subclass or None -+ ''' -+ assert isinstance(name, six.string_types) -+ assert not parent or isinstance(parent, Node) -+ self.name = name -+ self.parent = parent -+ -+ def AddChild(self, child): -+ '''Adds a child to the list of children of this node, if it is a valid -+ child for the node.''' -+ assert isinstance(child, Node) -+ if (not self._IsValidChild(child) or -+ self._ContentType() == self._CONTENT_TYPE_CDATA): -+ explanation = 'invalid child %s for parent %s' % (str(child), self.name) -+ raise exception.UnexpectedChild(explanation) -+ self.children.append(child) -+ self.mixed_content.append(child) -+ -+ def RemoveChild(self, child_id): -+ '''Removes the first node that has a "name" attribute which -+ matches "child_id" in the list of immediate children of -+ this node. -+ -+ Args: -+ child_id: String identifying the child to be removed -+ ''' -+ index = 0 -+ # Safe not to copy since we only remove the first element found -+ for child in self.children: -+ name_attr = child.attrs['name'] -+ if name_attr == child_id: -+ self.children.pop(index) -+ self.mixed_content.pop(index) -+ break -+ index += 1 -+ -+ def AppendContent(self, content): -+ '''Appends a chunk of text as content of this node. -+ -+ Args: -+ content: u'hello' -+ -+ Return: -+ None -+ ''' -+ assert isinstance(content, six.string_types) -+ if self._ContentType() != self._CONTENT_TYPE_NONE: -+ self.mixed_content.append(content) -+ elif content.strip() != '': -+ raise exception.UnexpectedContent() -+ -+ def HandleAttribute(self, attrib, value): -+ '''Informs the node of an attribute that was parsed out of the GRD file -+ for it. -+ -+ Args: -+ attrib: 'name' -+ value: 'fooblat' -+ -+ Return: -+ None -+ ''' -+ assert isinstance(attrib, six.string_types) -+ assert isinstance(value, six.string_types) -+ if self._IsValidAttribute(attrib, value): -+ self.attrs[attrib] = value -+ else: -+ raise exception.UnexpectedAttribute(attrib) -+ -+ def EndParsing(self): -+ '''Called at the end of parsing.''' -+ -+ # TODO(joi) Rewrite this, it's extremely ugly! -+ if len(self.mixed_content): -+ if isinstance(self.mixed_content[0], six.string_types): -+ # Remove leading and trailing chunks of pure whitespace. -+ while (len(self.mixed_content) and -+ isinstance(self.mixed_content[0], six.string_types) and -+ self.mixed_content[0].strip() == ''): -+ self.mixed_content = self.mixed_content[1:] -+ # Strip leading and trailing whitespace from mixed content chunks -+ # at front and back. -+ if (len(self.mixed_content) and -+ isinstance(self.mixed_content[0], six.string_types)): -+ self.mixed_content[0] = self.mixed_content[0].lstrip() -+ # Remove leading and trailing ''' (used to demarcate whitespace) -+ if (len(self.mixed_content) and -+ isinstance(self.mixed_content[0], six.string_types)): -+ if self.mixed_content[0].startswith("'''"): -+ self.mixed_content[0] = self.mixed_content[0][3:] -+ if len(self.mixed_content): -+ if isinstance(self.mixed_content[-1], six.string_types): -+ # Same stuff all over again for the tail end. -+ while (len(self.mixed_content) and -+ isinstance(self.mixed_content[-1], six.string_types) and -+ self.mixed_content[-1].strip() == ''): -+ self.mixed_content = self.mixed_content[:-1] -+ if (len(self.mixed_content) and -+ isinstance(self.mixed_content[-1], six.string_types)): -+ self.mixed_content[-1] = self.mixed_content[-1].rstrip() -+ if (len(self.mixed_content) and -+ isinstance(self.mixed_content[-1], six.string_types)): -+ if self.mixed_content[-1].endswith("'''"): -+ self.mixed_content[-1] = self.mixed_content[-1][:-3] -+ -+ # Check that all mandatory attributes are there. -+ for node_mandatt in self.MandatoryAttributes(): -+ mandatt_list = [] -+ if node_mandatt.find('|') >= 0: -+ mandatt_list = node_mandatt.split('|') -+ else: -+ mandatt_list.append(node_mandatt) -+ -+ mandatt_option_found = False -+ for mandatt in mandatt_list: -+ assert mandatt not in self.DefaultAttributes() -+ if mandatt in self.attrs: -+ if not mandatt_option_found: -+ mandatt_option_found = True -+ else: -+ raise exception.MutuallyExclusiveMandatoryAttribute(mandatt) -+ -+ if not mandatt_option_found: -+ raise exception.MissingMandatoryAttribute(mandatt) -+ -+ # Add default attributes if not specified in input file. -+ for defattr in self.DefaultAttributes(): -+ if not defattr in self.attrs: -+ self.attrs[defattr] = self.DefaultAttributes()[defattr] -+ -+ def GetCdata(self): -+ '''Returns all CDATA of this element, concatenated into a single -+ string. Note that this ignores any elements embedded in CDATA.''' -+ return ''.join([c for c in self.mixed_content -+ if isinstance(c, six.string_types)]) -+ -+ def __str__(self): -+ '''Returns this node and all nodes below it as an XML document in a Unicode -+ string.''' -+ header = u'\n' -+ return header + self.FormatXml() -+ -+ # Some Python 2 glue. -+ __unicode__ = __str__ -+ -+ def FormatXml(self, indent = u'', one_line = False): -+ '''Returns this node and all nodes below it as an XML -+ element in a Unicode string. This differs from __unicode__ in that it does -+ not include the stuff at the top of the string. If one_line is true, -+ children and CDATA are layed out in a way that preserves internal -+ whitespace. -+ ''' -+ assert isinstance(indent, six.string_types) -+ -+ content_one_line = (one_line or -+ self._ContentType() == self._CONTENT_TYPE_MIXED) -+ inside_content = self.ContentsAsXml(indent, content_one_line) -+ -+ # Then the attributes for this node. -+ attribs = u'' -+ default_attribs = self.DefaultAttributes() -+ for attrib, value in sorted(self.attrs.items()): -+ # Only print an attribute if it is other than the default value. -+ if attrib not in default_attribs or value != default_attribs[attrib]: -+ attribs += u' %s=%s' % (attrib, saxutils.quoteattr(value)) -+ -+ # Finally build the XML for our node and return it -+ if len(inside_content) > 0: -+ if one_line: -+ return u'<%s%s>%s' % (self.name, attribs, inside_content, -+ self.name) -+ elif content_one_line: -+ return u'%s<%s%s>\n%s %s\n%s' % ( -+ indent, self.name, attribs, -+ indent, inside_content, -+ indent, self.name) -+ else: -+ return u'%s<%s%s>\n%s\n%s' % ( -+ indent, self.name, attribs, -+ inside_content, -+ indent, self.name) -+ else: -+ return u'%s<%s%s />' % (indent, self.name, attribs) -+ -+ def ContentsAsXml(self, indent, one_line): -+ '''Returns the contents of this node (CDATA and child elements) in XML -+ format. If 'one_line' is true, the content will be laid out on one line.''' -+ assert isinstance(indent, six.string_types) -+ -+ # Build the contents of the element. -+ inside_parts = [] -+ last_item = None -+ for mixed_item in self.mixed_content: -+ if isinstance(mixed_item, Node): -+ inside_parts.append(mixed_item.FormatXml(indent + u' ', one_line)) -+ if not one_line: -+ inside_parts.append(u'\n') -+ else: -+ message = mixed_item -+ # If this is the first item and it starts with whitespace, we add -+ # the ''' delimiter. -+ if not last_item and message.lstrip() != message: -+ message = u"'''" + message -+ inside_parts.append(util.EncodeCdata(message)) -+ last_item = mixed_item -+ -+ # If there are only child nodes and no cdata, there will be a spurious -+ # trailing \n -+ if len(inside_parts) and inside_parts[-1] == '\n': -+ inside_parts = inside_parts[:-1] -+ -+ # If the last item is a string (not a node) and ends with whitespace, -+ # we need to add the ''' delimiter. -+ if (isinstance(last_item, six.string_types) and -+ last_item.rstrip() != last_item): -+ inside_parts[-1] = inside_parts[-1] + u"'''" -+ -+ return u''.join(inside_parts) -+ -+ def SubstituteMessages(self, substituter): -+ '''Applies substitutions to all messages in the tree. -+ -+ Called as a final step of RunGatherers. -+ -+ Args: -+ substituter: a grit.util.Substituter object. -+ ''' -+ for child in self.children: -+ child.SubstituteMessages(substituter) -+ -+ def _IsValidChild(self, child): -+ '''Returns true if 'child' is a valid child of this node. -+ Overridden by subclasses.''' -+ return False -+ -+ def _IsValidAttribute(self, name, value): -+ '''Returns true if 'name' is the name of a valid attribute of this element -+ and 'value' is a valid value for that attribute. Overriden by -+ subclasses unless they have only mandatory attributes.''' -+ return (name in self.MandatoryAttributes() or -+ name in self.DefaultAttributes()) -+ -+ def _ContentType(self): -+ '''Returns the type of content this element can have. Overridden by -+ subclasses. The content type can be one of the _CONTENT_TYPE_XXX constants -+ above.''' -+ return self._CONTENT_TYPE_NONE -+ -+ def MandatoryAttributes(self): -+ '''Returns a list of attribute names that are mandatory (non-optional) -+ on the current element. One can specify a list of -+ "mutually exclusive mandatory" attributes by specifying them as one -+ element in the list, separated by a "|" character. -+ ''' -+ return [] -+ -+ def DefaultAttributes(self): -+ '''Returns a dictionary of attribute names that have defaults, mapped to -+ the default value. Overridden by subclasses.''' -+ return {} -+ -+ def GetCliques(self): -+ '''Returns all MessageClique objects belonging to this node. Overridden -+ by subclasses. -+ -+ Return: -+ [clique1, clique2] or [] -+ ''' -+ return [] -+ -+ def ToRealPath(self, path_from_basedir): -+ '''Returns a real path (which can be absolute or relative to the current -+ working directory), given a path that is relative to the base directory -+ set for the GRIT input file. -+ -+ Args: -+ path_from_basedir: '..' -+ -+ Return: -+ 'resource' -+ ''' -+ return util.normpath(os.path.join(self.GetRoot().GetBaseDir(), -+ os.path.expandvars(path_from_basedir))) -+ -+ def GetInputPath(self): -+ '''Returns a path, relative to the base directory set for the grd file, -+ that points to the file the node refers to. -+ ''' -+ # This implementation works for most nodes that have an input file. -+ return self.attrs['file'] -+ -+ def UberClique(self): -+ '''Returns the uberclique that should be used for messages originating in -+ a given node. If the node itself has its uberclique set, that is what we -+ use, otherwise we search upwards until we find one. If we do not find one -+ even at the root node, we set the root node's uberclique to a new -+ uberclique instance. -+ ''' -+ node = self -+ while not node.uberclique and node.parent: -+ node = node.parent -+ if not node.uberclique: -+ node.uberclique = clique.UberClique() -+ return node.uberclique -+ -+ def IsTranslateable(self): -+ '''Returns false if the node has contents that should not be translated, -+ otherwise returns false (even if the node has no contents). -+ ''' -+ if not 'translateable' in self.attrs: -+ return True -+ else: -+ return self.attrs['translateable'] == 'true' -+ -+ def IsAccessibilityWithNoUI(self): -+ '''Returns true if the node is marked as an accessibility label and the -+ message isn't shown in the UI. Otherwise returns false. This label is -+ used to determine if the text requires screenshots.''' -+ if not 'is_accessibility_with_no_ui' in self.attrs: -+ return False -+ else: -+ return self.attrs['is_accessibility_with_no_ui'] == 'true' -+ -+ def GetNodeById(self, id): -+ '''Returns the node in the subtree parented by this node that has a 'name' -+ attribute matching 'id'. Returns None if no such node is found. -+ ''' -+ for node in self: -+ if 'name' in node.attrs and node.attrs['name'] == id: -+ return node -+ return None -+ -+ def GetChildrenOfType(self, type): -+ '''Returns a list of all subnodes (recursing to all leaves) of this node -+ that are of the indicated type (or tuple of types). -+ -+ Args: -+ type: A type you could use with isinstance(). -+ -+ Return: -+ A list, possibly empty. -+ ''' -+ return [child for child in self if isinstance(child, type)] -+ -+ def GetTextualIds(self): -+ '''Returns a list of the textual ids of this node. -+ ''' -+ if 'name' in self.attrs: -+ return [self.attrs['name']] -+ return [] -+ -+ @classmethod -+ def EvaluateExpression(cls, expr, defs, target_platform, extra_variables={}): -+ '''Worker for EvaluateCondition (below) and conditions in XTB files.''' -+ if expr in cls.eval_expr_cache: -+ code, variables_in_expr = cls.eval_expr_cache[expr] -+ else: -+ # Get a list of all variable and method names used in the expression. -+ syntax_tree = ast.parse(expr, mode='eval') -+ variables_in_expr = [node.id for node in ast.walk(syntax_tree) if -+ isinstance(node, ast.Name) and node.id not in ('True', 'False')] -+ code = compile(syntax_tree, filename='', mode='eval') -+ cls.eval_expr_cache[expr] = code, variables_in_expr -+ -+ # Set values only for variables that are needed to eval the expression. -+ variable_map = {} -+ for name in variables_in_expr: -+ if name == 'os': -+ value = target_platform -+ elif name == 'defs': -+ value = defs -+ -+ elif name == 'is_linux': -+ value = target_platform.startswith('linux') -+ elif name == 'is_macosx': -+ value = target_platform == 'darwin' -+ elif name == 'is_win': -+ value = target_platform in ('cygwin', 'win32') -+ elif name == 'is_android': -+ value = target_platform == 'android' -+ elif name == 'is_ios': -+ value = target_platform == 'ios' -+ elif name == 'is_bsd': -+ value = 'bsd' in target_platform -+ elif name == 'is_posix': -+ value = (target_platform in ('darwin', 'linux2', 'linux3', 'sunos5', -+ 'android', 'ios') -+ or 'bsd' in target_platform) -+ -+ elif name == 'pp_ifdef': -+ def pp_ifdef(symbol): -+ return symbol in defs -+ value = pp_ifdef -+ elif name == 'pp_if': -+ def pp_if(symbol): -+ return defs.get(symbol, False) -+ value = pp_if -+ -+ elif name in defs: -+ value = defs[name] -+ elif name in extra_variables: -+ value = extra_variables[name] -+ else: -+ # Undefined variables default to False. -+ value = False -+ -+ variable_map[name] = value -+ -+ eval_result = eval(code, {}, variable_map) -+ assert isinstance(eval_result, bool) -+ return eval_result -+ -+ def EvaluateCondition(self, expr): -+ '''Returns true if and only if the Python expression 'expr' evaluates -+ to true. -+ -+ The expression is given a few local variables: -+ - 'lang' is the language currently being output -+ (the 'lang' attribute of the element). -+ - 'context' is the current output context -+ (the 'context' attribute of the element). -+ - 'defs' is a map of C preprocessor-style symbol names to their values. -+ - 'os' is the current platform (likely 'linux2', 'win32' or 'darwin'). -+ - 'pp_ifdef(symbol)' is a shorthand for "symbol in defs". -+ - 'pp_if(symbol)' is a shorthand for "symbol in defs and defs[symbol]". -+ - 'is_linux', 'is_macosx', 'is_win', 'is_posix' are true if 'os' -+ matches the given platform. -+ ''' -+ root = self.GetRoot() -+ lang = getattr(root, 'output_language', '') -+ context = getattr(root, 'output_context', '') -+ defs = getattr(root, 'defines', {}) -+ target_platform = getattr(root, 'target_platform', '') -+ extra_variables = { -+ 'lang': lang, -+ 'context': context, -+ } -+ return Node.EvaluateExpression( -+ expr, defs, target_platform, extra_variables) -+ -+ def OnlyTheseTranslations(self, languages): -+ '''Turns off loading of translations for languages not in the provided list. -+ -+ Attrs: -+ languages: ['fr', 'zh_cn'] -+ ''' -+ for node in self: -+ if (hasattr(node, 'IsTranslation') and -+ node.IsTranslation() and -+ node.GetLang() not in languages): -+ node.DisableLoading() -+ -+ def FindBooleanAttribute(self, attr, default, skip_self): -+ '''Searches all ancestors of the current node for the nearest enclosing -+ definition of the given boolean attribute. -+ -+ Args: -+ attr: 'fallback_to_english' -+ default: What to return if no node defines the attribute. -+ skip_self: Don't check the current node, only its parents. -+ ''' -+ p = self.parent if skip_self else self -+ while p: -+ value = p.attrs.get(attr, 'default').lower() -+ if value != 'default': -+ return (value == 'true') -+ p = p.parent -+ return default -+ -+ def PseudoIsAllowed(self): -+ '''Returns true if this node is allowed to use pseudo-translations. This -+ is true by default, unless this node is within a node that has -+ the allow_pseudo attribute set to false. -+ ''' -+ return self.FindBooleanAttribute('allow_pseudo', -+ default=True, skip_self=True) -+ -+ def ShouldFallbackToEnglish(self): -+ '''Returns true iff this node should fall back to English when -+ pseudotranslations are disabled and no translation is available for a -+ given message. -+ ''' -+ return self.FindBooleanAttribute('fallback_to_english', -+ default=False, skip_self=True) -+ -+ def WhitelistMarkedAsSkip(self): -+ '''Returns true if the node is marked to be skipped in the output by a -+ whitelist. -+ ''' -+ return self._whitelist_marked_as_skip -+ -+ def SetWhitelistMarkedAsSkip(self, mark_skipped): -+ '''Sets WhitelistMarkedAsSkip. -+ ''' -+ self._whitelist_marked_as_skip = mark_skipped -+ -+ def ExpandVariables(self): -+ '''Whether we need to expand variables on a given node.''' -+ return False -+ -+ def IsResourceMapSource(self): -+ '''Whether this node is a resource map source.''' -+ return False -+ -+ def CompressDataIfNeeded(self, data): -+ '''Compress data using the format specified in the compress attribute. -+ -+ Args: -+ data: The data to compressed. -+ Returns: -+ The data in gzipped or brotli compressed format. If the format is -+ unspecified then this returns the data uncompressed. -+ ''' -+ -+ compress = self.attrs.get('compress') -+ -+ # Compress JS, HTML, CSS and SVG files by default (gzip), unless |compress| -+ # is explicitly specified. -+ compress_by_default = (compress == 'default' -+ and self.attrs.get('file').endswith( -+ self._COMPRESS_BY_DEFAULT_EXTENSIONS)) -+ -+ if compress == 'gzip' or compress_by_default: -+ # We only use rsyncable compression on Linux. -+ # We exclude ChromeOS since ChromeOS bots are Linux based but do not have -+ # the --rsyncable option built in for gzip. See crbug.com/617950. -+ if sys.platform == 'linux2' and 'chromeos' not in self.GetRoot().defines: -+ return grit.format.gzip_string.GzipStringRsyncable(data) -+ return grit.format.gzip_string.GzipString(data) -+ -+ if compress == 'brotli': -+ # The length of the uncompressed data as 8 bytes little-endian. -+ size_bytes = struct.pack(" ') -+ -+ ph = message.PhNode() -+ ph.StartParsing(u'ph', None) -+ ph.HandleAttribute(u'name', u'USERNAME') -+ ph.AppendContent(u'$1') -+ ex = message.ExNode() -+ ex.StartParsing(u'ex', None) -+ ex.AppendContent(u'Joi') -+ ex.EndParsing() -+ ph.AddChild(ex) -+ ph.EndParsing() -+ -+ node.AddChild(ph) -+ node.EndParsing() -+ -+ non_indented_xml = node.FormatXml() -+ self.failUnless(non_indented_xml == u'\n Hello ' -+ u'<young> $1Joi' -+ u'\n') -+ -+ indented_xml = node.FormatXml(u' ') -+ self.failUnless(indented_xml == u' \n Hello ' -+ u'<young> $1Joi' -+ u'\n ') -+ -+ def testXmlFormatMixedContentWithLeadingWhitespace(self): -+ # Again test using the Message node type, because it is the only mixed -+ # content node. -+ node = message.MessageNode() -+ node.StartParsing(u'message', None) -+ node.HandleAttribute(u'name', u'name') -+ node.AppendContent(u"''' Hello ") -+ -+ ph = message.PhNode() -+ ph.StartParsing(u'ph', None) -+ ph.HandleAttribute(u'name', u'USERNAME') -+ ph.AppendContent(u'$1') -+ ex = message.ExNode() -+ ex.StartParsing(u'ex', None) -+ ex.AppendContent(u'Joi') -+ ex.EndParsing() -+ ph.AddChild(ex) -+ ph.EndParsing() -+ -+ node.AddChild(ph) -+ node.AppendContent(u" yessiree '''") -+ node.EndParsing() -+ -+ non_indented_xml = node.FormatXml() -+ self.failUnless(non_indented_xml == -+ u"\n ''' Hello" -+ u' <young> $1Joi' -+ u" yessiree '''\n") -+ -+ indented_xml = node.FormatXml(u' ') -+ self.failUnless(indented_xml == -+ u" \n ''' Hello" -+ u' <young> $1Joi' -+ u" yessiree '''\n ") -+ -+ self.failUnless(node.GetNodeById('name')) -+ -+ def testXmlFormatContentWithEntities(self): -+ '''Tests a bug where   would not be escaped correctly.''' -+ from grit import tclib -+ msg_node = message.MessageNode.Construct(None, tclib.Message( -+ text = 'BEGIN_BOLDHelloWHITESPACEthere!END_BOLD Bingo!', -+ placeholders = [ -+ tclib.Placeholder('BEGIN_BOLD', '', 'bla'), -+ tclib.Placeholder('WHITESPACE', ' ', 'bla'), -+ tclib.Placeholder('END_BOLD', '', 'bla')]), -+ 'BINGOBONGO') -+ xml = msg_node.FormatXml() -+ self.failUnless(xml.find(' ') == -1, 'should have no entities') -+ -+ def testIter(self): -+ # First build a little tree of message and ph nodes. -+ node = message.MessageNode() -+ node.StartParsing(u'message', None) -+ node.HandleAttribute(u'name', u'bla') -+ node.AppendContent(u" ''' two spaces ") -+ node.AppendContent(u' space before and after ') -+ ph = message.PhNode() -+ ph.StartParsing(u'ph', None) -+ ph.AddChild(message.ExNode()) -+ ph.HandleAttribute(u'name', u'BINGO') -+ ph.AppendContent(u'bongo') -+ node.AddChild(ph) -+ node.AddChild(message.PhNode()) -+ node.AppendContent(u" space before two after '''") -+ -+ order = [message.MessageNode, message.PhNode, message.ExNode, message.PhNode] -+ for n in node: -+ self.failUnless(type(n) == order[0]) -+ order = order[1:] -+ self.failUnless(len(order) == 0) -+ -+ def testGetChildrenOfType(self): -+ xml = ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Hello! -+ -+ -+ ''' -+ grd = grd_reader.Parse(StringIO(xml), -+ util.PathFromRoot('grit/test/data')) -+ from grit.node import node_io -+ output_nodes = grd.GetChildrenOfType(node_io.OutputNode) -+ self.failUnlessEqual(len(output_nodes), 3) -+ self.failUnlessEqual(output_nodes[2].attrs['filename'], -+ 'de/generated_resources.rc') -+ -+ def testEvaluateExpression(self): -+ def AssertExpr(expected_value, expr, defs, target_platform, -+ extra_variables): -+ self.failUnlessEqual(expected_value, base.Node.EvaluateExpression( -+ expr, defs, target_platform, extra_variables)) -+ -+ AssertExpr(True, "True", {}, 'linux', {}) -+ AssertExpr(False, "False", {}, 'linux', {}) -+ AssertExpr(True, "True or False", {}, 'linux', {}) -+ AssertExpr(False, "True and False", {}, 'linux', {}) -+ AssertExpr(True, "os == 'linux'", {}, 'linux', {}) -+ AssertExpr(False, "os == 'linux'", {}, 'ios', {}) -+ AssertExpr(True, "'foo' in defs", {'foo': 'bar'}, 'ios', {}) -+ AssertExpr(False, "'foo' in defs", {'baz': 'bar'}, 'ios', {}) -+ AssertExpr(False, "'foo' in defs", {}, 'ios', {}) -+ AssertExpr(True, "is_linux", {}, 'linux2', {}) -+ AssertExpr(False, "is_linux", {}, 'win32', {}) -+ AssertExpr(True, "is_macosx", {}, 'darwin', {}) -+ AssertExpr(False, "is_macosx", {}, 'ios', {}) -+ AssertExpr(True, "is_win", {}, 'win32', {}) -+ AssertExpr(False, "is_win", {}, 'darwin', {}) -+ AssertExpr(True, "is_android", {}, 'android', {}) -+ AssertExpr(False, "is_android", {}, 'linux3', {}) -+ AssertExpr(True, "is_ios", {}, 'ios', {}) -+ AssertExpr(False, "is_ios", {}, 'darwin', {}) -+ AssertExpr(True, "is_posix", {}, 'linux2', {}) -+ AssertExpr(True, "is_posix", {}, 'darwin', {}) -+ AssertExpr(True, "is_posix", {}, 'android', {}) -+ AssertExpr(True, "is_posix", {}, 'ios', {}) -+ AssertExpr(True, "is_posix", {}, 'freebsd7', {}) -+ AssertExpr(False, "is_posix", {}, 'win32', {}) -+ AssertExpr(True, "pp_ifdef('foo')", {'foo': True}, 'win32', {}) -+ AssertExpr(True, "pp_ifdef('foo')", {'foo': False}, 'win32', {}) -+ AssertExpr(False, "pp_ifdef('foo')", {'bar': True}, 'win32', {}) -+ AssertExpr(True, "pp_if('foo')", {'foo': True}, 'win32', {}) -+ AssertExpr(False, "pp_if('foo')", {'foo': False}, 'win32', {}) -+ AssertExpr(False, "pp_if('foo')", {'bar': True}, 'win32', {}) -+ AssertExpr(True, "foo", {'foo': True}, 'win32', {}) -+ AssertExpr(False, "foo", {'foo': False}, 'win32', {}) -+ AssertExpr(False, "foo", {'bar': True}, 'win32', {}) -+ AssertExpr(True, "foo == 'baz'", {'foo': 'baz'}, 'win32', {}) -+ AssertExpr(False, "foo == 'baz'", {'foo': True}, 'win32', {}) -+ AssertExpr(False, "foo == 'baz'", {}, 'win32', {}) -+ AssertExpr(True, "lang == 'de'", {}, 'win32', {'lang': 'de'}) -+ AssertExpr(False, "lang == 'de'", {}, 'win32', {'lang': 'fr'}) -+ AssertExpr(False, "lang == 'de'", {}, 'win32', {}) -+ -+ # Test a couple more complex expressions for good measure. -+ AssertExpr(True, "is_ios and (lang in ['de', 'fr'] or foo)", -+ {'foo': 'bar'}, 'ios', {'lang': 'fr', 'context': 'today'}) -+ AssertExpr(False, "is_ios and (lang in ['de', 'fr'] or foo)", -+ {'foo': False}, 'linux2', {'lang': 'fr', 'context': 'today'}) -+ AssertExpr(False, "is_ios and (lang in ['de', 'fr'] or foo)", -+ {'baz': 'bar'}, 'ios', {'lang': 'he', 'context': 'today'}) -+ AssertExpr(True, "foo == 'bar' or not baz", -+ {'foo': 'bar', 'fun': True}, 'ios', {'lang': 'en'}) -+ AssertExpr(True, "foo == 'bar' or not baz", -+ {}, 'ios', {'lang': 'en', 'context': 'java'}) -+ AssertExpr(False, "foo == 'bar' or not baz", -+ {'foo': 'ruz', 'baz': True}, 'ios', {'lang': 'en'}) -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/node/brotli_util.py b/tools/grit/grit/node/brotli_util.py -new file mode 100644 -index 0000000000..77f70e49d5 ---- /dev/null -+++ b/tools/grit/grit/node/brotli_util.py -@@ -0,0 +1,29 @@ -+# Copyright 2019 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Framework for compressing resources using Brotli.""" -+ -+import subprocess -+ -+__brotli_executable = None -+ -+ -+def SetBrotliCommand(brotli): -+ # brotli is a list. In production it contains the path to the Brotli executable. -+ # During testing it contains [python, mock_brotli.py] for testing on Windows. -+ global __brotli_executable -+ __brotli_executable = brotli -+ -+ -+def BrotliCompress(data): -+ if not __brotli_executable: -+ raise Exception('Add "use_brotli = true" to you GN grit(...) target ' + -+ 'if you want to use brotli.') -+ compress = subprocess.Popen(__brotli_executable + ['-', '-f'], -+ stdin=subprocess.PIPE, stdout=subprocess.PIPE) -+ return compress.communicate(data)[0] -+ -+def IsInitialized(): -+ global __brotli_executable -+ return __brotli_executable is not None -diff --git a/tools/grit/grit/node/custom/__init__.py b/tools/grit/grit/node/custom/__init__.py -new file mode 100644 -index 0000000000..e179cf7730 ---- /dev/null -+++ b/tools/grit/grit/node/custom/__init__.py -@@ -0,0 +1,8 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Package 'grit.node.custom' -+''' -+ -+pass -diff --git a/tools/grit/grit/node/custom/filename.py b/tools/grit/grit/node/custom/filename.py -new file mode 100644 -index 0000000000..55a27e58c1 ---- /dev/null -+++ b/tools/grit/grit/node/custom/filename.py -@@ -0,0 +1,29 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''A CustomType for filenames.''' -+ -+from __future__ import print_function -+ -+from grit import clique -+from grit import lazy_re -+ -+ -+class WindowsFilename(clique.CustomType): -+ '''Validates that messages can be used as Windows filenames, and strips -+ illegal characters out of translations. -+ ''' -+ -+ BANNED = lazy_re.compile(r'\+|:|\/|\\\\|\*|\?|\"|\<|\>|\|') -+ -+ def Validate(self, message): -+ return not self.BANNED.search(message.GetPresentableContent()) -+ -+ def ValidateAndModify(self, lang, translation): -+ is_ok = self.Validate(translation) -+ self.ModifyEachTextPart(lang, translation) -+ return is_ok -+ -+ def ModifyTextPart(self, lang, text): -+ return self.BANNED.sub(' ', text) -diff --git a/tools/grit/grit/node/custom/filename_unittest.py b/tools/grit/grit/node/custom/filename_unittest.py -new file mode 100644 -index 0000000000..8e2a6dd64a ---- /dev/null -+++ b/tools/grit/grit/node/custom/filename_unittest.py -@@ -0,0 +1,34 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grit.node.custom.filename''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../../..')) -+ -+import unittest -+from grit.node.custom import filename -+from grit import clique -+from grit import tclib -+ -+ -+class WindowsFilenameUnittest(unittest.TestCase): -+ -+ def testValidate(self): -+ factory = clique.UberClique() -+ msg = tclib.Message(text='Bingo bongo') -+ c = factory.MakeClique(msg) -+ c.SetCustomType(filename.WindowsFilename()) -+ translation = tclib.Translation(id=msg.GetId(), text='Bilingo bolongo:') -+ c.AddTranslation(translation, 'fr') -+ self.failUnless(c.MessageForLanguage('fr').GetRealContent() == 'Bilingo bolongo ') -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/node/empty.py b/tools/grit/grit/node/empty.py -new file mode 100644 -index 0000000000..e19d2c4ddb ---- /dev/null -+++ b/tools/grit/grit/node/empty.py -@@ -0,0 +1,64 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Container nodes that don't have any logic. -+''' -+ -+from __future__ import print_function -+ -+from grit.node import base -+from grit.node import include -+from grit.node import message -+from grit.node import misc -+from grit.node import node_io -+from grit.node import structure -+ -+ -+class GroupingNode(base.Node): -+ '''Base class for all the grouping elements (, , -+ and ).''' -+ def DefaultAttributes(self): -+ return { -+ 'first_id' : '', -+ 'comment' : '', -+ 'fallback_to_english' : 'false', -+ 'fallback_to_low_resolution' : 'false', -+ } -+ -+ -+class IncludesNode(GroupingNode): -+ '''The element.''' -+ def _IsValidChild(self, child): -+ return isinstance(child, (include.IncludeNode, misc.IfNode, misc.PartNode)) -+ -+ -+class MessagesNode(GroupingNode): -+ '''The element.''' -+ def _IsValidChild(self, child): -+ return isinstance(child, (message.MessageNode, misc.IfNode, misc.PartNode)) -+ -+ -+class StructuresNode(GroupingNode): -+ '''The element.''' -+ def _IsValidChild(self, child): -+ return isinstance(child, (structure.StructureNode, -+ misc.IfNode, misc.PartNode)) -+ -+ -+class TranslationsNode(base.Node): -+ '''The element.''' -+ def _IsValidChild(self, child): -+ return isinstance(child, (node_io.FileNode, misc.IfNode, misc.PartNode)) -+ -+ -+class OutputsNode(base.Node): -+ '''The element.''' -+ def _IsValidChild(self, child): -+ return isinstance(child, (node_io.OutputNode, misc.IfNode, misc.PartNode)) -+ -+ -+class IdentifiersNode(GroupingNode): -+ '''The element.''' -+ def _IsValidChild(self, child): -+ return isinstance(child, misc.IdentifierNode) -diff --git a/tools/grit/grit/node/include.py b/tools/grit/grit/node/include.py -new file mode 100644 -index 0000000000..b06b9889bb ---- /dev/null -+++ b/tools/grit/grit/node/include.py -@@ -0,0 +1,170 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Handling of the element. -+""" -+ -+from __future__ import print_function -+ -+import os -+ -+from grit import util -+import grit.format.html_inline -+import grit.format.rc -+from grit.format import minifier -+from grit.node import base -+ -+class IncludeNode(base.Node): -+ """An element.""" -+ -+ def __init__(self): -+ super(IncludeNode, self).__init__() -+ -+ # Cache flattened data so that we don't flatten the same file -+ # multiple times. -+ self._flattened_data = None -+ # Also keep track of the last filename we flattened to, so we can -+ # avoid doing it more than once. -+ self._last_flat_filename = None -+ -+ def _IsValidChild(self, child): -+ return False -+ -+ def _GetFlattenedData( -+ self, allow_external_script=False, preprocess_only=False): -+ if not self._flattened_data: -+ filename = self.ToRealPath(self.GetInputPath()) -+ self._flattened_data = ( -+ grit.format.html_inline.InlineToString(filename, self, -+ preprocess_only=preprocess_only, -+ allow_external_script=allow_external_script)) -+ return self._flattened_data.encode('utf-8') -+ -+ def MandatoryAttributes(self): -+ return ['name', 'type', 'file'] -+ -+ def DefaultAttributes(self): -+ """Attributes: -+ translateable: False if the node has contents that should not be -+ translated. -+ preprocess: Takes the same code path as flattenhtml, but it -+ disables any processing/inlining outside of -+ and . -+ compress: The format to compress the data with, e.g. 'gzip' -+ or 'false' if data should not be compressed. -+ skip_minify: If true, skips minifying the node's contents. -+ skip_in_resource_map: If true, do not add to the resource map. -+ """ -+ return { -+ 'translateable': 'true', -+ 'generateid': 'true', -+ 'filenameonly': 'false', -+ 'mkoutput': 'false', -+ 'preprocess': 'false', -+ 'flattenhtml': 'false', -+ 'compress': 'default', -+ 'allowexternalscript': 'false', -+ 'relativepath': 'false', -+ 'use_base_dir': 'true', -+ 'skip_minify': 'false', -+ 'skip_in_resource_map': 'false', -+ } -+ -+ def GetInputPath(self): -+ # Do not mess with absolute paths, that would make them invalid. -+ if os.path.isabs(os.path.expandvars(self.attrs['file'])): -+ return self.attrs['file'] -+ -+ # We have no control over code that calls ToRealPath later, so convert -+ # the path to be relative against our basedir. -+ if self.attrs.get('use_base_dir', 'true') != 'true': -+ # Normalize the directory path to use the appropriate OS separator. -+ # GetBaseDir() may return paths\like\this or paths/like/this, since it is -+ # read from the base_dir attribute in the grd file. -+ norm_base_dir = util.normpath(self.GetRoot().GetBaseDir()) -+ return os.path.relpath(self.attrs['file'], norm_base_dir) -+ -+ return self.attrs['file'] -+ -+ def FileForLanguage(self, lang, output_dir): -+ """Returns the file for the specified language. This allows us to return -+ different files for different language variants of the include file. -+ """ -+ input_path = self.GetInputPath() -+ if input_path is None: -+ return None -+ -+ return self.ToRealPath(input_path) -+ -+ def GetDataPackValue(self, lang, encoding): -+ '''Returns bytes or a str represenation for a data_pack entry.''' -+ filename = self.ToRealPath(self.GetInputPath()) -+ if self.attrs['flattenhtml'] == 'true': -+ allow_external_script = self.attrs['allowexternalscript'] == 'true' -+ data = self._GetFlattenedData(allow_external_script=allow_external_script) -+ elif self.attrs['preprocess'] == 'true': -+ data = self._GetFlattenedData(preprocess_only=True) -+ else: -+ data = util.ReadFile(filename, util.BINARY) -+ -+ if self.attrs['skip_minify'] != 'true': -+ # Note that the minifier will only do anything if a minifier command -+ # has been set in the command line. -+ data = minifier.Minify(data, filename) -+ -+ # Include does not care about the encoding, because it only returns binary -+ # data. -+ return self.CompressDataIfNeeded(data) -+ -+ def Process(self, output_dir): -+ """Rewrite file references to be base64 encoded data URLs. The new file -+ will be written to output_dir and the name of the new file is returned.""" -+ filename = self.ToRealPath(self.GetInputPath()) -+ flat_filename = os.path.join(output_dir, -+ self.attrs['name'] + '_' + os.path.basename(filename)) -+ -+ if self._last_flat_filename == flat_filename: -+ return -+ -+ with open(flat_filename, 'wb') as outfile: -+ outfile.write(self._GetFlattenedData()) -+ -+ self._last_flat_filename = flat_filename -+ return os.path.basename(flat_filename) -+ -+ def GetHtmlResourceFilenames(self): -+ """Returns a set of all filenames inlined by this file.""" -+ allow_external_script = self.attrs['allowexternalscript'] == 'true' -+ return grit.format.html_inline.GetResourceFilenames( -+ self.ToRealPath(self.GetInputPath()), -+ self, -+ allow_external_script=allow_external_script) -+ -+ def IsResourceMapSource(self): -+ skip = self.attrs.get('skip_in_resource_map', 'false') == 'true' -+ return not skip -+ -+ @staticmethod -+ def Construct(parent, name, type, file, translateable=True, -+ filenameonly=False, mkoutput=False, relativepath=False): -+ """Creates a new node which is a child of 'parent', with attributes set -+ by parameters of the same name. -+ """ -+ # Convert types to appropriate strings -+ translateable = util.BoolToString(translateable) -+ filenameonly = util.BoolToString(filenameonly) -+ mkoutput = util.BoolToString(mkoutput) -+ relativepath = util.BoolToString(relativepath) -+ -+ node = IncludeNode() -+ node.StartParsing('include', parent) -+ node.HandleAttribute('name', name) -+ node.HandleAttribute('type', type) -+ node.HandleAttribute('file', file) -+ node.HandleAttribute('translateable', translateable) -+ node.HandleAttribute('filenameonly', filenameonly) -+ node.HandleAttribute('mkoutput', mkoutput) -+ node.HandleAttribute('relativepath', relativepath) -+ node.EndParsing() -+ return node -diff --git a/tools/grit/grit/node/include_unittest.py b/tools/grit/grit/node/include_unittest.py -new file mode 100644 -index 0000000000..4c658f1ffe ---- /dev/null -+++ b/tools/grit/grit/node/include_unittest.py -@@ -0,0 +1,134 @@ -+#!/usr/bin/env python -+# Copyright (c) 2013 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for include.IncludeNode''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+import unittest -+import zlib -+ -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+from grit.node import misc -+from grit.node import include -+from grit.node import empty -+from grit import util -+ -+ -+def checkIsGzipped(filename, compress_attr): -+ test_data_root = util.PathFromRoot('grit/testdata') -+ root = util.ParseGrdForUnittest( -+ ''' -+ -+ -+ ''' % (filename, compress_attr), -+ base_dir=test_data_root) -+ node, = root.GetChildrenOfType(include.IncludeNode) -+ compressed = node.GetDataPackValue(lang='en', encoding=util.BINARY) -+ -+ decompressed_data = zlib.decompress(compressed, 16 + zlib.MAX_WBITS) -+ expected = util.ReadFile(os.path.join(test_data_root, filename), util.BINARY) -+ return expected == decompressed_data -+ -+ -+class IncludeNodeUnittest(unittest.TestCase): -+ def testGetPath(self): -+ root = misc.GritNode() -+ root.StartParsing(u'grit', None) -+ root.HandleAttribute(u'latest_public_release', u'0') -+ root.HandleAttribute(u'current_release', u'1') -+ root.HandleAttribute(u'base_dir', r'..\resource') -+ release = misc.ReleaseNode() -+ release.StartParsing(u'release', root) -+ release.HandleAttribute(u'seq', u'1') -+ root.AddChild(release) -+ includes = empty.IncludesNode() -+ includes.StartParsing(u'includes', release) -+ release.AddChild(includes) -+ include_node = include.IncludeNode() -+ include_node.StartParsing(u'include', includes) -+ include_node.HandleAttribute(u'file', r'flugel\kugel.pdf') -+ includes.AddChild(include_node) -+ root.EndParsing() -+ -+ self.assertEqual(root.ToRealPath(include_node.GetInputPath()), -+ util.normpath( -+ os.path.join(r'../resource', r'flugel/kugel.pdf'))) -+ -+ def testGetPathNoBasedir(self): -+ root = misc.GritNode() -+ root.StartParsing(u'grit', None) -+ root.HandleAttribute(u'latest_public_release', u'0') -+ root.HandleAttribute(u'current_release', u'1') -+ root.HandleAttribute(u'base_dir', r'..\resource') -+ release = misc.ReleaseNode() -+ release.StartParsing(u'release', root) -+ release.HandleAttribute(u'seq', u'1') -+ root.AddChild(release) -+ includes = empty.IncludesNode() -+ includes.StartParsing(u'includes', release) -+ release.AddChild(includes) -+ include_node = include.IncludeNode() -+ include_node.StartParsing(u'include', includes) -+ include_node.HandleAttribute(u'file', r'flugel\kugel.pdf') -+ include_node.HandleAttribute(u'use_base_dir', u'false') -+ includes.AddChild(include_node) -+ root.EndParsing() -+ -+ last_dir = os.path.basename(os.getcwd()) -+ expected_path = util.normpath(os.path.join( -+ u'..', last_dir, u'flugel/kugel.pdf')) -+ self.assertEqual(root.ToRealPath(include_node.GetInputPath()), -+ expected_path) -+ -+ def testCompressGzip(self): -+ self.assertTrue(checkIsGzipped('test_text.txt', 'compress="gzip"')) -+ -+ def testCompressGzipByDefault(self): -+ self.assertTrue(checkIsGzipped('test_html.html', '')) -+ self.assertTrue(checkIsGzipped('test_js.js', '')) -+ self.assertTrue(checkIsGzipped('test_css.css', '')) -+ self.assertTrue(checkIsGzipped('test_svg.svg', '')) -+ -+ self.assertTrue(checkIsGzipped('test_html.html', 'compress="default"')) -+ self.assertTrue(checkIsGzipped('test_js.js', 'compress="default"')) -+ self.assertTrue(checkIsGzipped('test_css.css', 'compress="default"')) -+ self.assertTrue(checkIsGzipped('test_svg.svg', 'compress="default"')) -+ -+ def testSkipInResourceMap(self): -+ root = util.ParseGrdForUnittest(''' -+ -+ -+ -+ -+ ''', base_dir = util.PathFromRoot('grit/testdata')) -+ inc = root.GetChildrenOfType(include.IncludeNode) -+ self.assertTrue(inc[0].IsResourceMapSource()) -+ self.assertFalse(inc[1].IsResourceMapSource()) -+ self.assertTrue(inc[2].IsResourceMapSource()) -+ -+ def testAcceptsPreprocess(self): -+ root = util.ParseGrdForUnittest( -+ ''' -+ -+ -+ ''', -+ base_dir=util.PathFromRoot('grit/testdata')) -+ inc, = root.GetChildrenOfType(include.IncludeNode) -+ result = inc.GetDataPackValue(lang='en', encoding=util.BINARY) -+ self.assertIn(b'should be kept', result) -+ self.assertIn(b'in the middle...', result) -+ self.assertNotIn(b'should be removed', result) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/node/mapping.py b/tools/grit/grit/node/mapping.py -new file mode 100644 -index 0000000000..6297f0b666 ---- /dev/null -+++ b/tools/grit/grit/node/mapping.py -@@ -0,0 +1,60 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Maps each node type to an implementation class. -+When adding a new node type, you add to this mapping. -+''' -+ -+from __future__ import print_function -+ -+from grit import exception -+ -+from grit.node import empty -+from grit.node import include -+from grit.node import message -+from grit.node import misc -+from grit.node import node_io -+from grit.node import structure -+from grit.node import variant -+ -+ -+_ELEMENT_TO_CLASS = { -+ 'identifiers' : empty.IdentifiersNode, -+ 'includes' : empty.IncludesNode, -+ 'messages' : empty.MessagesNode, -+ 'outputs' : empty.OutputsNode, -+ 'structures' : empty.StructuresNode, -+ 'translations' : empty.TranslationsNode, -+ 'include' : include.IncludeNode, -+ 'emit' : node_io.EmitNode, -+ 'file' : node_io.FileNode, -+ 'output' : node_io.OutputNode, -+ 'ex' : message.ExNode, -+ 'message' : message.MessageNode, -+ 'ph' : message.PhNode, -+ 'else' : misc.ElseNode, -+ 'grit' : misc.GritNode, -+ 'identifier' : misc.IdentifierNode, -+ 'if' : misc.IfNode, -+ 'part' : misc.PartNode, -+ 'release' : misc.ReleaseNode, -+ 'then' : misc.ThenNode, -+ 'structure' : structure.StructureNode, -+ 'skeleton' : variant.SkeletonNode, -+} -+ -+ -+def ElementToClass(name, typeattr): -+ '''Maps an element to a class that handles the element. -+ -+ Args: -+ name: 'element' (the name of the element) -+ typeattr: 'type' (the value of the type attribute, if present, else None) -+ -+ Return: -+ type -+ ''' -+ if name not in _ELEMENT_TO_CLASS: -+ raise exception.UnknownElement() -+ return _ELEMENT_TO_CLASS[name] -diff --git a/tools/grit/grit/node/message.py b/tools/grit/grit/node/message.py -new file mode 100644 -index 0000000000..4fa83cf26b ---- /dev/null -+++ b/tools/grit/grit/node/message.py -@@ -0,0 +1,362 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Handling of the element. -+''' -+ -+from __future__ import print_function -+ -+import re -+ -+import six -+ -+from grit.node import base -+ -+from grit import clique -+from grit import exception -+from grit import lazy_re -+from grit import tclib -+from grit import util -+ -+ -+# Matches exactly three dots ending a line or followed by whitespace. -+_ELLIPSIS_PATTERN = lazy_re.compile(r'(?\s*)(?P.+?)(?P\s*)\Z', -+ re.DOTALL | re.MULTILINE) -+ -+# placeholder elements should contain the special character formatters -+# used to format element content. -+# Android format. -+_ANDROID_FORMAT = (r'%[1-9]+\$' -+ r'([-#+ 0,(]*)([0-9]+)?(\.[0-9]+)?' -+ r'([bBhHsScCdoxXeEfgGaAtT%n])') -+# Chrome l10n format. -+_CHROME_FORMAT = r'\$+\d' -+# Windows EWT numeric and GRIT %s %d formats. -+_OTHER_FORMAT = r'%[0-9sd]' -+ -+# Finds formatters that must be in a placeholder () element. -+_FORMATTERS = lazy_re.compile( -+ '(%s)|(%s)|(%s)' % (_ANDROID_FORMAT, _CHROME_FORMAT, _OTHER_FORMAT)) -+_BAD_PLACEHOLDER_MSG = ('ERROR: Placeholder formatter found outside of ' -+ 'tag in message "%s" in %s.') -+_INVALID_PH_CHAR_MSG = ('ERROR: Invalid format characters found in message ' -+ '"%s" tag in %s.') -+ -+# Finds HTML tag tokens. -+_HTMLTOKEN = lazy_re.compile(r'<[/]?[a-z][a-z0-9]*[^>]*>', re.I) -+ -+# Finds HTML entities. -+_HTMLENTITY = lazy_re.compile(r'&[^\s]*;') -+ -+ -+class MessageNode(base.ContentNode): -+ '''A element.''' -+ -+ # For splitting a list of things that can be separated by commas or -+ # whitespace -+ _SPLIT_RE = lazy_re.compile(r'\s*,\s*|\s+') -+ -+ def __init__(self): -+ super(MessageNode, self).__init__() -+ # Valid after EndParsing, this is the MessageClique that contains the -+ # source message and any translations of it that have been loaded. -+ self.clique = None -+ -+ # We don't send leading and trailing whitespace into the translation -+ # console, but rather tack it onto the source message and any -+ # translations when formatting them into RC files or what have you. -+ self.ws_at_start = '' # Any whitespace characters at the start of the text -+ self.ws_at_end = '' # --"-- at the end of the text -+ -+ # A list of "shortcut groups" this message is in. We check to make sure -+ # that shortcut keys (e.g. &J) within each shortcut group are unique. -+ self.shortcut_groups_ = [] -+ -+ # Formatter-specific data used to control the output of individual strings. -+ # formatter_data is a space separated list of C preprocessor-style -+ # definitions. Names without values are given the empty string value. -+ # Example: "foo=5 bar baz=100" -+ self.formatter_data = {} -+ -+ # Whether or not to convert ... -> U+2026 within Translate(). -+ self._replace_ellipsis = False -+ -+ def _IsValidChild(self, child): -+ return isinstance(child, (PhNode)) -+ -+ def _IsValidAttribute(self, name, value): -+ if name not in [ -+ 'name', 'offset', 'translateable', 'desc', 'meaning', -+ 'internal_comment', 'shortcut_groups', 'custom_type', 'validation_expr', -+ 'use_name_for_id', 'sub_variable', 'formatter_data', -+ 'is_accessibility_with_no_ui' -+ ]: -+ return False -+ if (name in ('translateable', 'sub_variable') and -+ value not in ['true', 'false']): -+ return False -+ return True -+ -+ def SetReplaceEllipsis(self, value): -+ r'''Sets whether to replace ... with \u2026. -+ ''' -+ self._replace_ellipsis = value -+ -+ def MandatoryAttributes(self): -+ return ['name|offset'] -+ -+ def DefaultAttributes(self): -+ return { -+ 'custom_type': '', -+ 'desc': '', -+ 'formatter_data': '', -+ 'internal_comment': '', -+ 'is_accessibility_with_no_ui': 'false', -+ 'meaning': '', -+ 'shortcut_groups': '', -+ 'sub_variable': 'false', -+ 'translateable': 'true', -+ 'use_name_for_id': 'false', -+ 'validation_expr': '', -+ } -+ -+ def HandleAttribute(self, attrib, value): -+ base.ContentNode.HandleAttribute(self, attrib, value) -+ if attrib != 'formatter_data': -+ return -+ -+ # Parse value, a space-separated list of defines, into a dict. -+ # Example: "foo=5 bar" -> {'foo':'5', 'bar':''} -+ for item in value.split(): -+ name, _, val = item.partition('=') -+ self.formatter_data[name] = val -+ -+ def GetTextualIds(self): -+ ''' -+ Returns the concatenation of the parent's node first_id and -+ this node's offset if it has one, otherwise just call the -+ superclass' implementation -+ ''' -+ if 'offset' not in self.attrs: -+ return super(MessageNode, self).GetTextualIds() -+ -+ # we search for the first grouping node in the parents' list -+ # to take care of the case where the first parent is an node -+ grouping_parent = self.parent -+ import grit.node.empty -+ while grouping_parent and not isinstance(grouping_parent, -+ grit.node.empty.GroupingNode): -+ grouping_parent = grouping_parent.parent -+ -+ assert 'first_id' in grouping_parent.attrs -+ return [grouping_parent.attrs['first_id'] + '_' + self.attrs['offset']] -+ -+ def IsTranslateable(self): -+ return self.attrs['translateable'] == 'true' -+ -+ def EndParsing(self): -+ super(MessageNode, self).EndParsing() -+ -+ # Make the text (including placeholder references) and list of placeholders, -+ # verify placeholder formats, then strip and store leading and trailing -+ # whitespace and create the tclib.Message() and a clique to contain it. -+ -+ text = '' -+ placeholders = [] -+ -+ for item in self.mixed_content: -+ if isinstance(item, six.string_types): -+ # Not a element: fail if any formatters are detected. -+ if _FORMATTERS.search(item): -+ print(_BAD_PLACEHOLDER_MSG % (item, self.source)) -+ raise exception.PlaceholderNotInsidePhNode -+ text += item -+ else: -+ # Extract the element components. -+ presentation = item.attrs['name'].upper() -+ text += presentation -+ ex = ' ' # example element cdata if present. -+ if len(item.children): -+ ex = item.children[0].GetCdata() -+ original = item.GetCdata() -+ -+ # Sanity check the element content. -+ cdata = original -+ # Replace all HTML tag tokens in cdata. -+ match = _HTMLTOKEN.search(cdata) -+ while match: -+ cdata = cdata.replace(match.group(0), '_') -+ match = _HTMLTOKEN.search(cdata) -+ # Replace all HTML entities in cdata. -+ match = _HTMLENTITY.search(cdata) -+ while match: -+ cdata = cdata.replace(match.group(0), '_') -+ match = _HTMLENTITY.search(cdata) -+ # Remove first matching formatter from cdata. -+ match = _FORMATTERS.search(cdata) -+ if match: -+ cdata = cdata.replace(match.group(0), '') -+ # Fail if special chars remain in cdata. -+ if re.search(r'[%\$]', cdata): -+ message_id = self.attrs['name'] + ' ' + original; -+ print(_INVALID_PH_CHAR_MSG % (message_id, self.source)) -+ raise exception.InvalidCharactersInsidePhNode -+ -+ # Otherwise, accept this placeholder. -+ placeholders.append(tclib.Placeholder(presentation, original, ex)) -+ -+ m = _WHITESPACE.match(text) -+ if m: -+ self.ws_at_start = m.group('start') -+ self.ws_at_end = m.group('end') -+ text = m.group('body') -+ -+ self.shortcut_groups_ = self._SPLIT_RE.split(self.attrs['shortcut_groups']) -+ self.shortcut_groups_ = [i for i in self.shortcut_groups_ if i != ''] -+ -+ description_or_id = self.attrs['desc'] -+ if description_or_id == '' and 'name' in self.attrs: -+ description_or_id = 'ID: %s' % self.attrs['name'] -+ -+ assigned_id = None -+ if self.attrs['use_name_for_id'] == 'true': -+ assigned_id = self.attrs['name'] -+ message = tclib.Message(text=text, placeholders=placeholders, -+ description=description_or_id, -+ meaning=self.attrs['meaning'], -+ assigned_id=assigned_id) -+ self.InstallMessage(message) -+ -+ def InstallMessage(self, message): -+ '''Sets this node's clique from a tclib.Message instance. -+ -+ Args: -+ message: A tclib.Message. -+ ''' -+ self.clique = self.UberClique().MakeClique(message, self.IsTranslateable()) -+ for group in self.shortcut_groups_: -+ self.clique.AddToShortcutGroup(group) -+ if self.attrs['custom_type'] != '': -+ self.clique.SetCustomType(util.NewClassInstance(self.attrs['custom_type'], -+ clique.CustomType)) -+ elif self.attrs['validation_expr'] != '': -+ self.clique.SetCustomType( -+ clique.OneOffCustomType(self.attrs['validation_expr'])) -+ -+ def SubstituteMessages(self, substituter): -+ '''Applies substitution to this message. -+ -+ Args: -+ substituter: a grit.util.Substituter object. -+ ''' -+ message = substituter.SubstituteMessage(self.clique.GetMessage()) -+ if message is not self.clique.GetMessage(): -+ self.InstallMessage(message) -+ -+ def GetCliques(self): -+ return [self.clique] if self.clique else [] -+ -+ def Translate(self, lang): -+ '''Returns a translated version of this message. -+ ''' -+ assert self.clique -+ msg = self.clique.MessageForLanguage(lang, -+ self.PseudoIsAllowed(), -+ self.ShouldFallbackToEnglish() -+ ).GetRealContent() -+ if self._replace_ellipsis: -+ msg = _ELLIPSIS_PATTERN.sub(_ELLIPSIS_SYMBOL, msg) -+ # Always remove all byte order marks (\uFEFF) https://crbug.com/1033305 -+ msg = msg.replace(u'\uFEFF','') -+ return msg.replace('[GRITLANGCODE]', lang) -+ -+ def NameOrOffset(self): -+ key = 'name' if 'name' in self.attrs else 'offset' -+ return self.attrs[key] -+ -+ def ExpandVariables(self): -+ '''We always expand variables on Messages.''' -+ return True -+ -+ def GetDataPackValue(self, lang, encoding): -+ '''Returns a str represenation for a data_pack entry.''' -+ message = self.ws_at_start + self.Translate(lang) + self.ws_at_end -+ return util.Encode(message, encoding) -+ -+ def IsResourceMapSource(self): -+ return True -+ -+ @staticmethod -+ def Construct(parent, message, name, desc='', meaning='', translateable=True): -+ '''Constructs a new message node that is a child of 'parent', with the -+ name, desc, meaning and translateable attributes set using the same-named -+ parameters and the text of the message and any placeholders taken from -+ 'message', which must be a tclib.Message() object.''' -+ # Convert type to appropriate string -+ translateable = 'true' if translateable else 'false' -+ -+ node = MessageNode() -+ node.StartParsing('message', parent) -+ node.HandleAttribute('name', name) -+ node.HandleAttribute('desc', desc) -+ node.HandleAttribute('meaning', meaning) -+ node.HandleAttribute('translateable', translateable) -+ -+ items = message.GetContent() -+ for ix, item in enumerate(items): -+ if isinstance(item, six.string_types): -+ # Ensure whitespace at front and back of message is correctly handled. -+ if ix == 0: -+ item = "'''" + item -+ if ix == len(items) - 1: -+ item = item + "'''" -+ -+ node.AppendContent(item) -+ else: -+ phnode = PhNode() -+ phnode.StartParsing('ph', node) -+ phnode.HandleAttribute('name', item.GetPresentation()) -+ phnode.AppendContent(item.GetOriginal()) -+ -+ if len(item.GetExample()) and item.GetExample() != ' ': -+ exnode = ExNode() -+ exnode.StartParsing('ex', phnode) -+ exnode.AppendContent(item.GetExample()) -+ exnode.EndParsing() -+ phnode.AddChild(exnode) -+ -+ phnode.EndParsing() -+ node.AddChild(phnode) -+ -+ node.EndParsing() -+ return node -+ -+ -+class PhNode(base.ContentNode): -+ '''A element.''' -+ -+ def _IsValidChild(self, child): -+ return isinstance(child, ExNode) -+ -+ def MandatoryAttributes(self): -+ return ['name'] -+ -+ def EndParsing(self): -+ super(PhNode, self).EndParsing() -+ # We only allow a single example for each placeholder -+ if len(self.children) > 1: -+ raise exception.TooManyExamples() -+ -+ def GetTextualIds(self): -+ # The 'name' attribute is not an ID. -+ return [] -+ -+ -+class ExNode(base.ContentNode): -+ '''An element.''' -+ pass -diff --git a/tools/grit/grit/node/message_unittest.py b/tools/grit/grit/node/message_unittest.py -new file mode 100644 -index 0000000000..7a4cbbedc2 ---- /dev/null -+++ b/tools/grit/grit/node/message_unittest.py -@@ -0,0 +1,380 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grit.node.message''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+import unittest -+ -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+from grit import exception -+from grit import tclib -+from grit import util -+from grit.node import message -+ -+class MessageUnittest(unittest.TestCase): -+ def testMessage(self): -+ root = util.ParseGrdForUnittest(''' -+ -+ -+ Hello %sJoi, how are you doing today? -+ -+ ''') -+ msg, = root.GetChildrenOfType(message.MessageNode) -+ cliques = msg.GetCliques() -+ content = cliques[0].GetMessage().GetPresentableContent() -+ self.failUnless(content == 'Hello USERNAME, how are you doing today?') -+ -+ def testMessageWithWhitespace(self): -+ root = util.ParseGrdForUnittest("""\ -+ -+ -+ ''' Hello there %s ''' -+ -+ """) -+ msg, = root.GetChildrenOfType(message.MessageNode) -+ content = msg.GetCliques()[0].GetMessage().GetPresentableContent() -+ self.failUnless(content == 'Hello there USERNAME') -+ self.failUnless(msg.ws_at_start == ' ') -+ self.failUnless(msg.ws_at_end == ' ') -+ -+ def testConstruct(self): -+ msg = tclib.Message(text=" Hello USERNAME, how are you? BINGO\t\t", -+ placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi'), -+ tclib.Placeholder('BINGO', '%d', '11')]) -+ msg_node = message.MessageNode.Construct(None, msg, 'BINGOBONGO') -+ self.failUnless(msg_node.children[0].name == 'ph') -+ self.failUnless(msg_node.children[0].children[0].name == 'ex') -+ self.failUnless(msg_node.children[0].children[0].GetCdata() == 'Joi') -+ self.failUnless(msg_node.children[1].children[0].GetCdata() == '11') -+ self.failUnless(msg_node.ws_at_start == ' ') -+ self.failUnless(msg_node.ws_at_end == '\t\t') -+ -+ def testUnicodeConstruct(self): -+ text = u'Howdie \u00fe' -+ msg = tclib.Message(text=text) -+ msg_node = message.MessageNode.Construct(None, msg, 'BINGOBONGO') -+ msg_from_node = msg_node.GetCdata() -+ self.failUnless(msg_from_node == text) -+ -+ def testFormatterData(self): -+ root = util.ParseGrdForUnittest("""\ -+ -+ -+ Text -+ -+ """) -+ msg, = root.GetChildrenOfType(message.MessageNode) -+ expected_formatter_data = { -+ 'foo': '123', -+ 'bar': '', -+ 'qux': 'low'} -+ -+ # Can't use assertDictEqual, not available in Python 2.6, so do it -+ # by hand. -+ self.failUnlessEqual(len(expected_formatter_data), -+ len(msg.formatter_data)) -+ for key in expected_formatter_data: -+ self.failUnlessEqual(expected_formatter_data[key], -+ msg.formatter_data[key]) -+ -+ def testReplaceEllipsis(self): -+ root = util.ParseGrdForUnittest(''' -+ -+ -+ A...B.... %sA... B... C... -+ -+ ''') -+ msg, = root.GetChildrenOfType(message.MessageNode) -+ msg.SetReplaceEllipsis(True) -+ content = msg.Translate('en') -+ self.failUnlessEqual(u'A...B.... %s\u2026 B\u2026 C\u2026', content) -+ -+ def testRemoveByteOrderMark(self): -+ root = util.ParseGrdForUnittest(u''' -+ -+ -+ \uFEFFThis\uFEFF i\uFEFFs OK\uFEFF -+ -+ ''') -+ msg, = root.GetChildrenOfType(message.MessageNode) -+ content = msg.Translate('en') -+ self.failUnlessEqual(u'This is OK', content) -+ -+ def testPlaceholderHasTooManyExamples(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ Hi $1JoiJoy -+ -+ """) -+ except exception.TooManyExamples: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testPlaceholderHasInvalidName(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ Hi $1 -+ -+ """) -+ except exception.InvalidPlaceholderName: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testChromeLocalizedFormatIsInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ This message is missing the ph node: $1 -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testAndroidStringFormatIsInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ This message is missing a ph node: %1$s -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testAndroidIntegerFormatIsInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ This message is missing a ph node: %2$d -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testAndroidIntegerWidthFormatIsInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ This message is missing a ph node: %2$3d -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testValidAndroidIntegerWidthFormatInPhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ %2$3d042 -+ -+ """) -+ except: -+ self.fail('Should not have gotten exception') -+ -+ def testAndroidFloatFormatIsInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ This message is missing a ph node: %3$4.5f -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testGritStringFormatIsInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ This message is missing the ph node: %s -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testGritIntegerFormatIsInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ This message is missing the ph node: %d -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testWindowsETWIntegerFormatIsInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ This message is missing the ph node: %1 -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testValidMultipleFormattersInsidePhNodes(self): -+ root = util.ParseGrdForUnittest("""\ -+ -+ -+ %1$d1 error, %2$d1 warning -+ -+ """) -+ msg, = root.GetChildrenOfType(message.MessageNode) -+ cliques = msg.GetCliques() -+ content = cliques[0].GetMessage().GetPresentableContent() -+ self.failUnless(content == 'ERROR_COUNT error, WARNING_COUNT warning') -+ -+ def testMultipleFormattersAreInsidePhNodes(self): -+ failed = True -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ %1$d error, %2$d warning -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ failed = False -+ if failed: -+ self.fail('Should have gotten exception') -+ return -+ -+ failed = True -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ %1$d1 error, %2$d warning -+ -+ """) -+ except exception.PlaceholderNotInsidePhNode: -+ failed = False -+ if failed: -+ self.fail('Should have gotten exception') -+ return -+ -+ failed = True -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ %1$d %2$d -+ -+ """) -+ except exception.InvalidCharactersInsidePhNode: -+ failed = False -+ if failed: -+ self.fail('Should have gotten exception') -+ return -+ -+ def testValidHTMLFormatInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ <span>$1</span>1 -+ -+ """) -+ except: -+ self.fail('Should not have gotten exception') -+ -+ def testValidHTMLWithAttributesFormatInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ <span attribute="js:$this %">$2</span>2 -+ -+ """) -+ except: -+ self.fail('Should not have gotten exception') -+ -+ def testValidHTMLEntityFormatInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ >%1$d<1 -+ -+ """) -+ except: -+ self.fail('Should not have gotten exception') -+ -+ def testValidMultipleDollarFormatInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ $$1 -+ -+ """) -+ except: -+ self.fail('Should not have gotten exception') -+ -+ def testInvalidDollarCharacterInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ %1$d $ -+ -+ """) -+ except exception.InvalidCharactersInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testInvalidPercentCharacterInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ %1$d % -+ -+ """) -+ except exception.InvalidCharactersInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ def testInvalidMixedFormatCharactersInsidePhNode(self): -+ try: -+ util.ParseGrdForUnittest("""\ -+ -+ -+ %1$2 -+ -+ """) -+ except exception.InvalidCharactersInsidePhNode: -+ return -+ self.fail('Should have gotten exception') -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/node/misc.py b/tools/grit/grit/node/misc.py -new file mode 100644 -index 0000000000..2d8b06d6a5 ---- /dev/null -+++ b/tools/grit/grit/node/misc.py -@@ -0,0 +1,707 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Miscellaneous node types. -+""" -+ -+from __future__ import print_function -+ -+import os.path -+import re -+import sys -+ -+import six -+ -+from grit import constants -+from grit import exception -+from grit import util -+from grit.extern import FP -+from grit.node import base -+from grit.node import message -+from grit.node import node_io -+ -+ -+# Python 3 doesn't have long() as int() works everywhere. But we really do need -+# the long() behavior on Python 2 as our ids are much too large for int(). -+try: -+ long -+except NameError: -+ long = int -+ -+ -+# RTL languages -+# TODO(jennyz): remove this fixed set of RTL language array -+# now that generic expand_variable code exists. -+_RTL_LANGS = ( -+ 'ar', # Arabic -+ 'fa', # Farsi -+ 'iw', # Hebrew -+ 'ks', # Kashmiri -+ 'ku', # Kurdish -+ 'ps', # Pashto -+ 'ur', # Urdu -+ 'yi', # Yiddish -+) -+ -+ -+def _ReadFirstIdsFromFile(filename, defines): -+ """Read the starting resource id values from |filename|. We also -+ expand variables of the form <(FOO) based on defines passed in on -+ the command line. -+ -+ Returns a tuple, the absolute path of SRCDIR followed by the -+ first_ids dictionary. -+ """ -+ first_ids_dict = eval(util.ReadFile(filename, 'utf-8')) -+ src_root_dir = os.path.abspath(os.path.join(os.path.dirname(filename), -+ first_ids_dict['SRCDIR'])) -+ -+ def ReplaceVariable(matchobj): -+ for key, value in defines.items(): -+ if matchobj.group(1) == key: -+ return value -+ return '' -+ -+ renames = [] -+ for grd_filename in first_ids_dict: -+ new_grd_filename = re.sub(r'<\(([A-Za-z_]+)\)', ReplaceVariable, -+ grd_filename) -+ if new_grd_filename != grd_filename: -+ abs_grd_filename = os.path.abspath(new_grd_filename) -+ if abs_grd_filename[:len(src_root_dir)] != src_root_dir: -+ new_grd_filename = os.path.basename(abs_grd_filename) -+ else: -+ new_grd_filename = abs_grd_filename[len(src_root_dir) + 1:] -+ new_grd_filename = new_grd_filename.replace('\\', '/') -+ renames.append((grd_filename, new_grd_filename)) -+ -+ for grd_filename, new_grd_filename in renames: -+ first_ids_dict[new_grd_filename] = first_ids_dict[grd_filename] -+ del(first_ids_dict[grd_filename]) -+ -+ return (src_root_dir, first_ids_dict) -+ -+ -+def _ComputeIds(root, predetermined_tids): -+ """Returns a dict of textual id -> numeric id for all nodes in root. -+ -+ IDs are mostly assigned sequentially, but will vary based on: -+ * first_id node attribute (from first_ids_file) -+ * hash of textual id (if not first_id is defined) -+ * offset node attribute -+ * whether the textual id matches a system id -+ * whether the node generates its own ID via GetId() -+ -+ Args: -+ predetermined_tids: Dict of textual id -> numeric id to use in return dict. -+ """ -+ from grit.node import empty, include, misc, structure -+ -+ ids = {} # Maps numeric id to textual id -+ tids = {} # Maps textual id to numeric id -+ id_reasons = {} # Maps numeric id to text id and a human-readable explanation -+ group = None -+ last_id = None -+ predetermined_ids = {value: key -+ for key, value in predetermined_tids.items()} -+ -+ for item in root: -+ if isinstance(item, empty.GroupingNode): -+ # Note: this won't work if any GroupingNode can be contained inside -+ # another. -+ group = item -+ last_id = None -+ continue -+ -+ assert not item.GetTextualIds() or isinstance(item, -+ (include.IncludeNode, message.MessageNode, -+ misc.IdentifierNode, structure.StructureNode)) -+ -+ # Resources that use the RES protocol don't need -+ # any numerical ids generated, so we skip them altogether. -+ # This is accomplished by setting the flag 'generateid' to false -+ # in the GRD file. -+ if item.attrs.get('generateid', 'true') == 'false': -+ continue -+ -+ for tid in item.GetTextualIds(): -+ if util.SYSTEM_IDENTIFIERS.match(tid): -+ # Don't emit a new ID for predefined IDs -+ continue -+ -+ if tid in tids: -+ continue -+ -+ if predetermined_tids and tid in predetermined_tids: -+ id = predetermined_tids[tid] -+ reason = "from predetermined_tids map" -+ -+ # Some identifier nodes can provide their own id, -+ # and we use that id in the generated header in that case. -+ elif hasattr(item, 'GetId') and item.GetId(): -+ id = long(item.GetId()) -+ reason = 'returned by GetId() method' -+ -+ elif ('offset' in item.attrs and group and -+ group.attrs.get('first_id', '') != ''): -+ offset_text = item.attrs['offset'] -+ parent_text = group.attrs['first_id'] -+ -+ try: -+ offset_id = long(offset_text) -+ except ValueError: -+ offset_id = tids[offset_text] -+ -+ try: -+ parent_id = long(parent_text) -+ except ValueError: -+ parent_id = tids[parent_text] -+ -+ id = parent_id + offset_id -+ reason = 'first_id %d + offset %d' % (parent_id, offset_id) -+ -+ # We try to allocate IDs sequentially for blocks of items that might -+ # be related, for instance strings in a stringtable (as their IDs might be -+ # used e.g. as IDs for some radio buttons, in which case the IDs must -+ # be sequential). -+ # -+ # We do this by having the first item in a section store its computed ID -+ # (computed from a fingerprint) in its parent object. Subsequent children -+ # of the same parent will then try to get IDs that sequentially follow -+ # the currently stored ID (on the parent) and increment it. -+ elif last_id is None: -+ # First check if the starting ID is explicitly specified by the parent. -+ if group and group.attrs.get('first_id', '') != '': -+ id = long(group.attrs['first_id']) -+ reason = "from parent's first_id attribute" -+ else: -+ # Automatically generate the ID based on the first clique from the -+ # first child of the first child node of our parent (i.e. when we -+ # first get to this location in the code). -+ -+ # According to -+ # http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx -+ # the safe usable range for resource IDs in Windows is from decimal -+ # 101 to 0x7FFF. -+ -+ id = FP.UnsignedFingerPrint(tid) -+ id = id % (0x7FFF - 101) + 101 -+ reason = 'chosen by random fingerprint -- use first_id to override' -+ -+ last_id = id -+ else: -+ id = last_id = last_id + 1 -+ reason = 'sequentially assigned' -+ -+ reason = "%s (%s)" % (tid, reason) -+ # Don't fail when 'offset' is specified, as the base and the 0th -+ # offset will have the same ID. -+ if id in id_reasons and not 'offset' in item.attrs: -+ raise exception.IdRangeOverlap('ID %d was assigned to both %s and %s.' -+ % (id, id_reasons[id], reason)) -+ -+ if id < 101: -+ print('WARNING: Numeric resource IDs should be greater than 100 to\n' -+ 'avoid conflicts with system-defined resource IDs.') -+ -+ if tid not in predetermined_tids and id in predetermined_ids: -+ raise exception.IdRangeOverlap('ID %d overlaps between %s and %s' -+ % (id, tid, predetermined_ids[tid])) -+ -+ ids[id] = tid -+ tids[tid] = id -+ id_reasons[id] = reason -+ -+ return tids -+ -+class SplicingNode(base.Node): -+ """A node whose children should be considered to be at the same level as -+ its siblings for most purposes. This includes and nodes. -+ """ -+ -+ def _IsValidChild(self, child): -+ assert self.parent, '<%s> node should never be root.' % self.name -+ if isinstance(child, SplicingNode): -+ return True # avoid O(n^2) behavior -+ return self.parent._IsValidChild(child) -+ -+ -+class IfNode(SplicingNode): -+ """A node for conditional inclusion of resources. -+ """ -+ -+ def MandatoryAttributes(self): -+ return ['expr'] -+ -+ def _IsValidChild(self, child): -+ return (isinstance(child, (ThenNode, ElseNode)) or -+ super(IfNode, self)._IsValidChild(child)) -+ -+ def EndParsing(self): -+ children = self.children -+ self.if_then_else = False -+ if any(isinstance(node, (ThenNode, ElseNode)) for node in children): -+ if (len(children) != 2 or not isinstance(children[0], ThenNode) or -+ not isinstance(children[1], ElseNode)): -+ raise exception.UnexpectedChild( -+ ' element must be ......') -+ self.if_then_else = True -+ -+ def ActiveChildren(self): -+ cond = self.EvaluateCondition(self.attrs['expr']) -+ if self.if_then_else: -+ return self.children[0 if cond else 1].ActiveChildren() -+ else: -+ # Equivalent to having all children inside with an empty -+ return super(IfNode, self).ActiveChildren() if cond else [] -+ -+ -+class ThenNode(SplicingNode): -+ """A node. Can only appear directly inside an node.""" -+ pass -+ -+ -+class ElseNode(SplicingNode): -+ """An node. Can only appear directly inside an node.""" -+ pass -+ -+ -+class PartNode(SplicingNode): -+ """A node for inclusion of sub-grd (*.grp) files. -+ """ -+ -+ def __init__(self): -+ super(PartNode, self).__init__() -+ self.started_inclusion = False -+ -+ def MandatoryAttributes(self): -+ return ['file'] -+ -+ def _IsValidChild(self, child): -+ return self.started_inclusion and super(PartNode, self)._IsValidChild(child) -+ -+ -+class ReleaseNode(base.Node): -+ """The element.""" -+ -+ def _IsValidChild(self, child): -+ from grit.node import empty -+ return isinstance(child, (empty.IncludesNode, empty.MessagesNode, -+ empty.StructuresNode, empty.IdentifiersNode)) -+ -+ def _IsValidAttribute(self, name, value): -+ return ( -+ (name == 'seq' and int(value) <= self.GetRoot().GetCurrentRelease()) or -+ name == 'allow_pseudo' -+ ) -+ -+ def MandatoryAttributes(self): -+ return ['seq'] -+ -+ def DefaultAttributes(self): -+ return { 'allow_pseudo' : 'true' } -+ -+ -+class GritNode(base.Node): -+ """The root element.""" -+ -+ def __init__(self): -+ super(GritNode, self).__init__() -+ self.output_language = '' -+ self.defines = {} -+ self.substituter = None -+ self.target_platform = sys.platform -+ self.whitelist_support = False -+ self._predetermined_ids_file = None -+ self._id_map = None # Dict of textual_id -> numeric_id. -+ -+ def _IsValidChild(self, child): -+ from grit.node import empty -+ return isinstance(child, (ReleaseNode, empty.TranslationsNode, -+ empty.OutputsNode)) -+ -+ def _IsValidAttribute(self, name, value): -+ if name not in ['base_dir', 'first_ids_file', 'source_lang_id', -+ 'latest_public_release', 'current_release', -+ 'enc_check', 'tc_project', 'grit_version', -+ 'output_all_resource_defines']: -+ return False -+ if name in ['latest_public_release', 'current_release'] and value.strip( -+ '0123456789') != '': -+ return False -+ return True -+ -+ def MandatoryAttributes(self): -+ return ['latest_public_release', 'current_release'] -+ -+ def DefaultAttributes(self): -+ return { -+ 'base_dir' : '.', -+ 'first_ids_file': '', -+ 'grit_version': 1, -+ 'source_lang_id' : 'en', -+ 'enc_check' : constants.ENCODING_CHECK, -+ 'tc_project' : 'NEED_TO_SET_tc_project_ATTRIBUTE', -+ } -+ -+ def EndParsing(self): -+ super(GritNode, self).EndParsing() -+ if (int(self.attrs['latest_public_release']) -+ > int(self.attrs['current_release'])): -+ raise exception.Parsing('latest_public_release cannot have a greater ' -+ 'value than current_release') -+ -+ self.ValidateUniqueIds() -+ -+ # Add the encoding check if it's not present (should ensure that it's always -+ # present in all .grd files generated by GRIT). If it's present, assert if -+ # it's not correct. -+ if 'enc_check' not in self.attrs or self.attrs['enc_check'] == '': -+ self.attrs['enc_check'] = constants.ENCODING_CHECK -+ else: -+ assert self.attrs['enc_check'] == constants.ENCODING_CHECK, ( -+ 'Are you sure your .grd file is in the correct encoding (UTF-8)?') -+ -+ def ValidateUniqueIds(self): -+ """Validate that 'name' attribute is unique in all nodes in this tree -+ except for nodes that are children of nodes. -+ """ -+ unique_names = {} -+ duplicate_names = [] -+ # To avoid false positives from mutually exclusive clauses, check -+ # against whatever the output condition happens to be right now. -+ # TODO(benrg): do something better. -+ for node in self.ActiveDescendants(): -+ if node.attrs.get('generateid', 'true') == 'false': -+ continue # Duplication not relevant in that case -+ -+ for node_id in node.GetTextualIds(): -+ if util.SYSTEM_IDENTIFIERS.match(node_id): -+ continue # predefined IDs are sometimes used more than once -+ -+ if node_id in unique_names and node_id not in duplicate_names: -+ duplicate_names.append(node_id) -+ unique_names[node_id] = 1 -+ -+ if len(duplicate_names): -+ raise exception.DuplicateKey(', '.join(duplicate_names)) -+ -+ -+ def GetCurrentRelease(self): -+ """Returns the current release number.""" -+ return int(self.attrs['current_release']) -+ -+ def GetLatestPublicRelease(self): -+ """Returns the latest public release number.""" -+ return int(self.attrs['latest_public_release']) -+ -+ def GetSourceLanguage(self): -+ """Returns the language code of the source language.""" -+ return self.attrs['source_lang_id'] -+ -+ def GetTcProject(self): -+ """Returns the name of this project in the TranslationConsole, or -+ 'NEED_TO_SET_tc_project_ATTRIBUTE' if it is not defined.""" -+ return self.attrs['tc_project'] -+ -+ def SetOwnDir(self, dir): -+ """Informs the 'grit' element of the directory the file it is in resides. -+ This allows it to calculate relative paths from the input file, which is -+ what we desire (rather than from the current path). -+ -+ Args: -+ dir: r'c:\bla' -+ -+ Return: -+ None -+ """ -+ assert dir -+ self.base_dir = os.path.normpath(os.path.join(dir, self.attrs['base_dir'])) -+ -+ def GetBaseDir(self): -+ """Returns the base directory, relative to the working directory. To get -+ the base directory as set in the .grd file, use GetOriginalBaseDir() -+ """ -+ if hasattr(self, 'base_dir'): -+ return self.base_dir -+ else: -+ return self.GetOriginalBaseDir() -+ -+ def GetOriginalBaseDir(self): -+ """Returns the base directory, as set in the .grd file. -+ """ -+ return self.attrs['base_dir'] -+ -+ def IsWhitelistSupportEnabled(self): -+ return self.whitelist_support -+ -+ def SetWhitelistSupportEnabled(self, whitelist_support): -+ self.whitelist_support = whitelist_support -+ -+ def GetInputFiles(self): -+ """Returns the list of files that are read to produce the output.""" -+ -+ # Importing this here avoids a circular dependency in the imports. -+ # pylint: disable-msg=C6204 -+ from grit.node import include -+ from grit.node import misc -+ from grit.node import structure -+ from grit.node import variant -+ -+ # Check if the input is required for any output configuration. -+ input_files = set() -+ # Collect even inactive PartNodes since they affect ID assignments. -+ for node in self: -+ if isinstance(node, misc.PartNode): -+ input_files.add(self.ToRealPath(node.GetInputPath())) -+ -+ old_output_language = self.output_language -+ for lang, ctx, fallback in self.GetConfigurations(): -+ self.SetOutputLanguage(lang or self.GetSourceLanguage()) -+ self.SetOutputContext(ctx) -+ self.SetFallbackToDefaultLayout(fallback) -+ -+ for node in self.ActiveDescendants(): -+ if isinstance(node, (node_io.FileNode, include.IncludeNode, -+ structure.StructureNode, variant.SkeletonNode)): -+ input_path = node.GetInputPath() -+ if input_path is not None: -+ input_files.add(self.ToRealPath(input_path)) -+ -+ # If it's a flattened node, grab inlined resources too. -+ if ((node.name == 'structure' or node.name == 'include') -+ and node.attrs['flattenhtml'] == 'true'): -+ if node.name == 'structure': -+ node.RunPreSubstitutionGatherer() -+ input_files.update(node.GetHtmlResourceFilenames()) -+ -+ self.SetOutputLanguage(old_output_language) -+ return sorted(input_files) -+ -+ def GetFirstIdsFile(self): -+ """Returns a usable path to the first_ids file, if set, otherwise -+ returns None. -+ -+ The first_ids_file attribute is by default relative to the -+ base_dir of the .grd file, but may be prefixed by GRIT_DIR/, -+ which makes it relative to the directory of grit.py -+ (e.g. GRIT_DIR/../gritsettings/resource_ids). -+ """ -+ if not self.attrs['first_ids_file']: -+ return None -+ -+ path = self.attrs['first_ids_file'] -+ GRIT_DIR_PREFIX = 'GRIT_DIR' -+ if (path.startswith(GRIT_DIR_PREFIX) -+ and path[len(GRIT_DIR_PREFIX)] in ['/', '\\']): -+ return util.PathFromRoot(path[len(GRIT_DIR_PREFIX) + 1:]) -+ else: -+ return self.ToRealPath(path) -+ -+ def GetOutputFiles(self): -+ """Returns the list of nodes that are descendants of this node's -+ child and are not enclosed by unsatisfied conditionals. -+ """ -+ for child in self.children: -+ if child.name == 'outputs': -+ return [node for node in child.ActiveDescendants() -+ if node.name == 'output'] -+ raise exception.MissingElement() -+ -+ def GetConfigurations(self): -+ """Returns the distinct (language, context, fallback_to_default_layout) -+ triples from the output nodes. -+ """ -+ return set((n.GetLanguage(), n.GetContext(), n.GetFallbackToDefaultLayout()) -+ for n in self.GetOutputFiles()) -+ -+ def GetSubstitutionMessages(self): -+ """Returns the list of nodes.""" -+ return [n for n in self.ActiveDescendants() -+ if isinstance(n, message.MessageNode) -+ and n.attrs['sub_variable'] == 'true'] -+ -+ def SetOutputLanguage(self, output_language): -+ """Set the output language. Prepares substitutions. -+ -+ The substitutions are reset every time the language is changed. -+ They include messages designated as variables, and language codes for html -+ and rc files. -+ -+ Args: -+ output_language: a two-letter language code (eg: 'en', 'ar'...) or '' -+ """ -+ if not output_language: -+ # We do not specify the output language for .grh files, -+ # so we get an empty string as the default. -+ # The value should match grit.clique.MessageClique.source_language. -+ output_language = self.GetSourceLanguage() -+ if output_language != self.output_language: -+ self.output_language = output_language -+ self.substituter = None # force recalculate -+ -+ def SetOutputContext(self, output_context): -+ self.output_context = output_context -+ self.substituter = None # force recalculate -+ -+ def SetFallbackToDefaultLayout(self, fallback_to_default_layout): -+ self.fallback_to_default_layout = fallback_to_default_layout -+ self.substituter = None # force recalculate -+ -+ def SetDefines(self, defines): -+ self.defines = defines -+ self.substituter = None # force recalculate -+ -+ def SetTargetPlatform(self, target_platform): -+ self.target_platform = target_platform -+ -+ def GetSubstituter(self): -+ if self.substituter is None: -+ self.substituter = util.Substituter() -+ self.substituter.AddMessages(self.GetSubstitutionMessages(), -+ self.output_language) -+ if self.output_language in _RTL_LANGS: -+ direction = 'dir="RTL"' -+ else: -+ direction = 'dir="LTR"' -+ self.substituter.AddSubstitutions({ -+ 'GRITLANGCODE': self.output_language, -+ 'GRITDIR': direction, -+ }) -+ from grit.format import rc # avoid circular dep -+ rc.RcSubstitutions(self.substituter, self.output_language) -+ return self.substituter -+ -+ def AssignFirstIds(self, filename_or_stream, defines): -+ """Assign first ids to each grouping node based on values from the -+ first_ids file (if specified on the node). -+ """ -+ assert self._id_map is None, 'AssignFirstIds() after InitializeIds()' -+ # If the input is a stream, then we're probably in a unit test and -+ # should skip this step. -+ if not isinstance(filename_or_stream, six.string_types): -+ return -+ -+ # Nothing to do if the first_ids_filename attribute isn't set. -+ first_ids_filename = self.GetFirstIdsFile() -+ if not first_ids_filename: -+ return -+ -+ src_root_dir, first_ids = _ReadFirstIdsFromFile(first_ids_filename, -+ defines) -+ from grit.node import empty -+ for node in self.Preorder(): -+ if isinstance(node, empty.GroupingNode): -+ abs_filename = os.path.abspath(filename_or_stream) -+ if abs_filename[:len(src_root_dir)] != src_root_dir: -+ filename = os.path.basename(filename_or_stream) -+ else: -+ filename = abs_filename[len(src_root_dir) + 1:] -+ filename = filename.replace('\\', '/') -+ -+ if node.attrs['first_id'] != '': -+ raise Exception( -+ "Don't set the first_id attribute when using the first_ids_file " -+ "attribute on the node, update %s instead." % -+ first_ids_filename) -+ -+ try: -+ id_list = first_ids[filename][node.name] -+ except KeyError as e: -+ print('-' * 78) -+ print('Resource id not set for %s (%s)!' % (filename, node.name)) -+ print('Please update %s to include an entry for %s. See the ' -+ 'comments in resource_ids for information on why you need to ' -+ 'update that file.' % (first_ids_filename, filename)) -+ print('-' * 78) -+ raise e -+ -+ try: -+ node.attrs['first_id'] = str(id_list.pop(0)) -+ except IndexError as e: -+ raise Exception('Please update %s and add a first id for %s (%s).' -+ % (first_ids_filename, filename, node.name)) -+ -+ def GetIdMap(self): -+ '''Return a dictionary mapping textual ids to numeric ids.''' -+ return self._id_map -+ -+ def SetPredeterminedIdsFile(self, predetermined_ids_file): -+ assert self._id_map is None, ( -+ 'SetPredeterminedIdsFile() after InitializeIds()') -+ self._predetermined_ids_file = predetermined_ids_file -+ -+ def InitializeIds(self): -+ '''Initializes the text ID -> numeric ID mapping.''' -+ predetermined_id_map = {} -+ if self._predetermined_ids_file: -+ with open(self._predetermined_ids_file) as f: -+ for line in f: -+ tid, nid = line.split() -+ predetermined_id_map[tid] = int(nid) -+ self._id_map = _ComputeIds(self, predetermined_id_map) -+ -+ def RunGatherers(self, debug=False): -+ '''Call RunPreSubstitutionGatherer() on every node of the tree, then apply -+ substitutions, then call RunPostSubstitutionGatherer() on every node. -+ -+ The substitutions step requires that the output language has been set. -+ Locally, get the Substitution messages and add them to the substituter. -+ Also add substitutions for language codes in the Rc. -+ -+ Args: -+ debug: will print information while running gatherers. -+ ''' -+ for node in self.ActiveDescendants(): -+ if hasattr(node, 'RunPreSubstitutionGatherer'): -+ with node: -+ node.RunPreSubstitutionGatherer(debug=debug) -+ -+ assert self.output_language -+ self.SubstituteMessages(self.GetSubstituter()) -+ -+ for node in self.ActiveDescendants(): -+ if hasattr(node, 'RunPostSubstitutionGatherer'): -+ with node: -+ node.RunPostSubstitutionGatherer(debug=debug) -+ -+ -+class IdentifierNode(base.Node): -+ """A node for specifying identifiers that should appear in the resource -+ header file, and be unique amongst all other resource identifiers, but don't -+ have any other attributes or reference any resources. -+ """ -+ -+ def MandatoryAttributes(self): -+ return ['name'] -+ -+ def DefaultAttributes(self): -+ return { 'comment' : '', 'id' : '', 'systemid': 'false' } -+ -+ def GetId(self): -+ """Returns the id of this identifier if it has one, None otherwise -+ """ -+ if 'id' in self.attrs: -+ return self.attrs['id'] -+ return None -+ -+ def EndParsing(self): -+ """Handles system identifiers.""" -+ super(IdentifierNode, self).EndParsing() -+ if self.attrs['systemid'] == 'true': -+ util.SetupSystemIdentifiers((self.attrs['name'],)) -+ -+ @staticmethod -+ def Construct(parent, name, id, comment, systemid='false'): -+ """Creates a new node which is a child of 'parent', with attributes set -+ by parameters of the same name. -+ """ -+ node = IdentifierNode() -+ node.StartParsing('identifier', parent) -+ node.HandleAttribute('name', name) -+ node.HandleAttribute('id', id) -+ node.HandleAttribute('comment', comment) -+ node.HandleAttribute('systemid', systemid) -+ node.EndParsing() -+ return node -diff --git a/tools/grit/grit/node/misc_unittest.py b/tools/grit/grit/node/misc_unittest.py -new file mode 100644 -index 0000000000..c192b096f4 ---- /dev/null -+++ b/tools/grit/grit/node/misc_unittest.py -@@ -0,0 +1,590 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for misc.GritNode''' -+ -+from __future__ import print_function -+ -+import contextlib -+import os -+import sys -+import tempfile -+import unittest -+ -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+from six import StringIO -+ -+from grit import grd_reader -+import grit.exception -+from grit import util -+from grit.format import rc -+from grit.format import rc_header -+from grit.node import misc -+ -+ -+@contextlib.contextmanager -+def _MakeTempPredeterminedIdsFile(content): -+ """Write the |content| string to a temporary file. -+ -+ The temporary file must be deleted by the caller. -+ -+ Example: -+ with _MakeTempPredeterminedIdsFile('foo') as path: -+ ... -+ os.remove(path) -+ -+ Args: -+ content: The string to write. -+ -+ Yields: -+ The name of the temporary file. -+ """ -+ with tempfile.NamedTemporaryFile(mode='w', delete=False) as f: -+ f.write(content) -+ f.flush() -+ f.close() -+ yield f.name -+ -+ -+class GritNodeUnittest(unittest.TestCase): -+ def testUniqueNameAttribute(self): -+ try: -+ restree = grd_reader.Parse( -+ util.PathFromRoot('grit/testdata/duplicate-name-input.xml')) -+ self.fail('Expected parsing exception because of duplicate names.') -+ except grit.exception.Parsing: -+ pass # Expected case -+ -+ def testReadFirstIdsFromFile(self): -+ test_resource_ids = os.path.join(os.path.dirname(__file__), '..', -+ 'testdata', 'resource_ids') -+ base_dir = os.path.dirname(test_resource_ids) -+ -+ src_dir, id_dict = misc._ReadFirstIdsFromFile( -+ test_resource_ids, -+ { -+ 'FOO': os.path.join(base_dir, 'bar'), -+ 'SHARED_INTERMEDIATE_DIR': os.path.join(base_dir, -+ 'out/Release/obj/gen'), -+ }) -+ self.assertEqual({}, id_dict.get('bar/file.grd', None)) -+ self.assertEqual({}, -+ id_dict.get('out/Release/obj/gen/devtools/devtools.grd', None)) -+ -+ src_dir, id_dict = misc._ReadFirstIdsFromFile( -+ test_resource_ids, -+ { -+ 'SHARED_INTERMEDIATE_DIR': '/outside/src_dir', -+ }) -+ self.assertEqual({}, id_dict.get('devtools.grd', None)) -+ -+ # Verifies that GetInputFiles() returns the correct list of files -+ # corresponding to ChromeScaledImage nodes when assets are missing. -+ def testGetInputFilesChromeScaledImage(self): -+ chrome_html_path = util.PathFromRoot('grit/testdata/chrome_html.html') -+ xml = ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''' % chrome_html_path -+ -+ grd = grd_reader.Parse(StringIO(xml), -+ util.PathFromRoot('grit/testdata')) -+ expected = ['chrome_html.html', 'default_100_percent/a.png', -+ 'default_100_percent/b.png', 'included_sample.html', -+ 'special_100_percent/a.png'] -+ actual = [os.path.relpath(path, util.PathFromRoot('grit/testdata')) for -+ path in grd.GetInputFiles()] -+ # Convert path separator for Windows paths. -+ actual = [path.replace('\\', '/') for path in actual] -+ self.assertEquals(expected, actual) -+ -+ # Verifies that GetInputFiles() returns the correct list of files -+ # when files include other files. -+ def testGetInputFilesFromIncludes(self): -+ chrome_html_path = util.PathFromRoot('grit/testdata/chrome_html.html') -+ xml = ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''' % chrome_html_path -+ -+ grd = grd_reader.Parse(StringIO(xml), util.PathFromRoot('grit/testdata')) -+ expected = ['chrome_html.html', 'included_sample.html'] -+ actual = [os.path.relpath(path, util.PathFromRoot('grit/testdata')) for -+ path in grd.GetInputFiles()] -+ # Convert path separator for Windows paths. -+ actual = [path.replace('\\', '/') for path in actual] -+ self.assertEquals(expected, actual) -+ -+ def testNonDefaultEntry(self): -+ grd = util.ParseGrdForUnittest(''' -+ -+ bar -+ -+ bar -+ -+ ''') -+ grd.SetOutputLanguage('fr') -+ output = ''.join(rc_header.Format(grd, 'fr', '.')) -+ self.assertIn('#define IDS_A 2378\n#define IDS_B 2379', output) -+ -+ def testExplicitFirstIdOverlaps(self): -+ # second first_id will overlap preexisting range -+ self.assertRaises(grit.exception.IdRangeOverlap, -+ util.ParseGrdForUnittest, ''' -+ -+ -+ -+ -+ -+ -+ Hello %sJoi, how are you doing today? -+ -+ Frubegfrums -+ ''') -+ -+ def testImplicitOverlapsPreexisting(self): -+ # second message in will overlap preexisting range -+ self.assertRaises(grit.exception.IdRangeOverlap, -+ util.ParseGrdForUnittest, ''' -+ -+ -+ -+ -+ -+ -+ Hello %sJoi, how are you doing today? -+ -+ Frubegfrums -+ ''') -+ -+ def testPredeterminedIds(self): -+ with _MakeTempPredeterminedIdsFile('IDS_A 101\nIDS_B 102') as ids_file: -+ grd = util.ParseGrdForUnittest(''' -+ -+ -+ -+ -+ -+ Hello %sJoi, how are you doing today? -+ -+ -+ Bongo! -+ -+ ''', predetermined_ids_file=ids_file) -+ output = rc_header.FormatDefines(grd) -+ self.assertEqual(('#define IDS_B 102\n' -+ '#define IDS_GREETING 10000\n' -+ '#define IDS_A 101\n'), ''.join(output)) -+ os.remove(ids_file) -+ -+ def testPredeterminedIdsOverlap(self): -+ with _MakeTempPredeterminedIdsFile('ID_LOGO 10000') as ids_file: -+ self.assertRaises(grit.exception.IdRangeOverlap, -+ util.ParseGrdForUnittest, ''' -+ -+ -+ -+ -+ -+ Hello %sJoi, how are you doing today? -+ -+ -+ Bongo! -+ -+ ''', predetermined_ids_file=ids_file) -+ os.remove(ids_file) -+ -+ -+class IfNodeUnittest(unittest.TestCase): -+ def testIffyness(self): -+ grd = grd_reader.Parse(StringIO(''' -+ -+ -+ -+ -+ -+ Bingo! -+ -+ -+ -+ -+ Hello! -+ -+ -+ -+ -+ Good morning -+ -+ -+ -+ is_win -+ -+ -+ -+ '''), dir='.') -+ -+ messages_node = grd.children[0].children[0] -+ bingo_message = messages_node.children[0].children[0] -+ hello_message = messages_node.children[1].children[0] -+ french_message = messages_node.children[2].children[0] -+ is_win_message = messages_node.children[3].children[0] -+ -+ self.assertTrue(bingo_message.name == 'message') -+ self.assertTrue(hello_message.name == 'message') -+ self.assertTrue(french_message.name == 'message') -+ -+ grd.SetOutputLanguage('fr') -+ grd.SetDefines({'hello': '1'}) -+ active = set(grd.ActiveDescendants()) -+ self.failUnless(bingo_message not in active) -+ self.failUnless(hello_message in active) -+ self.failUnless(french_message in active) -+ -+ grd.SetOutputLanguage('en') -+ grd.SetDefines({'bingo': 1}) -+ active = set(grd.ActiveDescendants()) -+ self.failUnless(bingo_message in active) -+ self.failUnless(hello_message not in active) -+ self.failUnless(french_message not in active) -+ -+ grd.SetOutputLanguage('en') -+ grd.SetDefines({'FORCE_FRENCH': '1', 'bingo': '1'}) -+ active = set(grd.ActiveDescendants()) -+ self.failUnless(bingo_message in active) -+ self.failUnless(hello_message not in active) -+ self.failUnless(french_message in active) -+ -+ grd.SetOutputLanguage('en') -+ grd.SetDefines({}) -+ self.failUnless(grd.target_platform == sys.platform) -+ grd.SetTargetPlatform('darwin') -+ active = set(grd.ActiveDescendants()) -+ self.failUnless(is_win_message not in active) -+ grd.SetTargetPlatform('win32') -+ active = set(grd.ActiveDescendants()) -+ self.failUnless(is_win_message in active) -+ -+ def testElsiness(self): -+ grd = util.ParseGrdForUnittest(''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''') -+ included = [msg.attrs['name'] for msg in grd.ActiveDescendants() -+ if msg.name == 'message'] -+ self.assertEqual(['IDS_YES1', 'IDS_YES2', 'IDS_YES3', 'IDS_YES4'], included) -+ -+ def testIffynessWithOutputNodes(self): -+ grd = grd_reader.Parse(StringIO(''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ '''), dir='.') -+ -+ outputs_node = grd.children[0] -+ uncond1_output = outputs_node.children[0] -+ only_fr_adm_output = outputs_node.children[1].children[0] -+ only_fr_plist_output = outputs_node.children[1].children[1] -+ doc_output = outputs_node.children[2].children[0] -+ uncond2_output = outputs_node.children[0] -+ self.assertTrue(uncond1_output.name == 'output') -+ self.assertTrue(only_fr_adm_output.name == 'output') -+ self.assertTrue(only_fr_plist_output.name == 'output') -+ self.assertTrue(doc_output.name == 'output') -+ self.assertTrue(uncond2_output.name == 'output') -+ -+ grd.SetOutputLanguage('ru') -+ grd.SetDefines({'hello': '1'}) -+ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] -+ self.assertEquals( -+ outputs, -+ ['uncond1.rc', 'only_fr.adm', 'only_fr.plist', 'doc.html', -+ 'uncond2.adm', 'iftest.h']) -+ -+ grd.SetOutputLanguage('ru') -+ grd.SetDefines({'bingo': '2'}) -+ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] -+ self.assertEquals( -+ outputs, -+ ['uncond1.rc', 'doc.html', 'uncond2.adm', 'iftest.h']) -+ -+ grd.SetOutputLanguage('fr') -+ grd.SetDefines({'hello': '1'}) -+ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] -+ self.assertEquals( -+ outputs, -+ ['uncond1.rc', 'only_fr.adm', 'only_fr.plist', 'uncond2.adm', -+ 'iftest.h']) -+ -+ grd.SetOutputLanguage('en') -+ grd.SetDefines({'bingo': '1'}) -+ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] -+ self.assertEquals(outputs, ['uncond1.rc', 'uncond2.adm', 'iftest.h']) -+ -+ grd.SetOutputLanguage('fr') -+ grd.SetDefines({'bingo': '1'}) -+ outputs = [output.GetFilename() for output in grd.GetOutputFiles()] -+ self.assertNotEquals(outputs, ['uncond1.rc', 'uncond2.adm', 'iftest.h']) -+ -+ def testChildrenAccepted(self): -+ grd_reader.Parse(StringIO(r''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Bingo! -+ -+ -+ -+ Bingo! -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ '''), dir='.') -+ -+ def testIfBadChildrenNesting(self): -+ # includes -+ xml = StringIO(r''' -+ -+ -+ -+ -+ -+ -+ -+ -+ ''') -+ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) -+ # messages -+ xml = StringIO(r''' -+ -+ -+ -+ -+ -+ -+ -+ -+ ''') -+ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) -+ # structures -+ xml = StringIO(''' -+ -+ -+ -+ -+ Bingo! -+ -+ -+ -+ ''') -+ # translations -+ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) -+ xml = StringIO(''' -+ -+ -+ -+ Bingo! -+ -+ -+ ''') -+ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) -+ # same with nesting -+ xml = StringIO(r''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''') -+ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) -+ xml = StringIO(r''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ''') -+ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) -+ xml = StringIO(''' -+ -+ -+ -+ -+ -+ Bingo! -+ -+ -+ -+ -+ ''') -+ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) -+ xml = StringIO(''' -+ -+ -+ -+ -+ Bingo! -+ -+ -+ -+ ''') -+ self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml) -+ -+ -+class ReleaseNodeUnittest(unittest.TestCase): -+ def testPseudoControl(self): -+ grd = grd_reader.Parse(StringIO(''' -+ -+ -+ -+ -+ Hello -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Bingo -+ -+ -+ -+ -+ -+ -+ '''), util.PathFromRoot('grit/testdata')) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ -+ hello = grd.GetNodeById('IDS_HELLO') -+ aboutbox = grd.GetNodeById('IDD_ABOUTBOX') -+ bingo = grd.GetNodeById('IDS_BINGO') -+ menu = grd.GetNodeById('IDC_KLONKMENU') -+ -+ for node in [hello, aboutbox]: -+ self.failUnless(not node.PseudoIsAllowed()) -+ -+ for node in [bingo, menu]: -+ self.failUnless(node.PseudoIsAllowed()) -+ -+ # TODO(benrg): There was a test here that formatting hello and aboutbox with -+ # a pseudo language should fail, but they do not fail and the test was -+ # broken and failed to catch it. Fix this. -+ -+ # Should not raise an exception since pseudo is allowed -+ rc.FormatMessage(bingo, 'xyz-pseudo') -+ rc.FormatStructure(menu, 'xyz-pseudo', '.') -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/node/mock_brotli.py b/tools/grit/grit/node/mock_brotli.py -new file mode 100644 -index 0000000000..14237aab20 ---- /dev/null -+++ b/tools/grit/grit/node/mock_brotli.py -@@ -0,0 +1,10 @@ -+#!/usr/bin/env python -+# Copyright 2019 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Mock Brotli Executable for testing purposes.""" -+ -+import sys -+ -+sys.stdout.write('This has been mock compressed!') -diff --git a/tools/grit/grit/node/node_io.py b/tools/grit/grit/node/node_io.py -new file mode 100644 -index 0000000000..ccbc2c0647 ---- /dev/null -+++ b/tools/grit/grit/node/node_io.py -@@ -0,0 +1,117 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''The and elements. -+''' -+ -+from __future__ import print_function -+ -+import os -+ -+from grit import xtb_reader -+from grit.node import base -+ -+ -+class FileNode(base.Node): -+ '''A element.''' -+ -+ def __init__(self): -+ super(FileNode, self).__init__() -+ self.re = None -+ self.should_load_ = True -+ -+ def IsTranslation(self): -+ return True -+ -+ def GetLang(self): -+ return self.attrs['lang'] -+ -+ def DisableLoading(self): -+ self.should_load_ = False -+ -+ def MandatoryAttributes(self): -+ return ['path', 'lang'] -+ -+ def RunPostSubstitutionGatherer(self, debug=False): -+ if not self.should_load_: -+ return -+ -+ root = self.GetRoot() -+ defs = getattr(root, 'defines', {}) -+ target_platform = getattr(root, 'target_platform', '') -+ -+ xtb_file = open(self.ToRealPath(self.GetInputPath()), 'rb') -+ try: -+ lang = xtb_reader.Parse(xtb_file, -+ self.UberClique().GenerateXtbParserCallback( -+ self.attrs['lang'], debug=debug), -+ defs=defs, -+ target_platform=target_platform) -+ except: -+ print("Exception during parsing of %s" % self.GetInputPath()) -+ raise -+ # Translation console uses non-standard language codes 'iw' and 'no' for -+ # Hebrew and Norwegian Bokmal instead of 'he' and 'nb' used in Chrome. -+ # Note that some Chrome's .grd still use 'no' instead of 'nb', but 'nb' is -+ # always used for generated .pak files. -+ ALTERNATIVE_LANG_CODE_MAP = { 'he': 'iw', 'nb': 'no' } -+ assert (lang == self.attrs['lang'] or -+ lang == ALTERNATIVE_LANG_CODE_MAP[self.attrs['lang']]), ( -+ 'The XTB file you reference must contain messages in the language ' -+ 'specified\nby the \'lang\' attribute.') -+ -+ def GetInputPath(self): -+ return os.path.expandvars(self.attrs['path']) -+ -+ -+class OutputNode(base.Node): -+ '''An element.''' -+ -+ def MandatoryAttributes(self): -+ return ['filename', 'type'] -+ -+ def DefaultAttributes(self): -+ return { -+ 'lang' : '', # empty lang indicates all languages -+ 'language_section' : 'neutral', # defines a language neutral section -+ 'context' : '', -+ 'fallback_to_default_layout' : 'true', -+ } -+ -+ def GetType(self): -+ return self.attrs['type'] -+ -+ def GetLanguage(self): -+ '''Returns the language ID, default 'en'.''' -+ return self.attrs['lang'] -+ -+ def GetContext(self): -+ return self.attrs['context'] -+ -+ def GetFilename(self): -+ return self.attrs['filename'] -+ -+ def GetOutputFilename(self): -+ path = None -+ if hasattr(self, 'output_filename'): -+ path = self.output_filename -+ else: -+ path = self.attrs['filename'] -+ return os.path.expandvars(path) -+ -+ def GetFallbackToDefaultLayout(self): -+ return self.attrs['fallback_to_default_layout'].lower() == 'true' -+ -+ def _IsValidChild(self, child): -+ return isinstance(child, EmitNode) -+ -+class EmitNode(base.ContentNode): -+ ''' An element.''' -+ -+ def DefaultAttributes(self): -+ return { 'emit_type' : 'prepend'} -+ -+ def GetEmitType(self): -+ '''Returns the emit_type for this node. Default is 'append'.''' -+ return self.attrs['emit_type'] -diff --git a/tools/grit/grit/node/node_io_unittest.py b/tools/grit/grit/node/node_io_unittest.py -new file mode 100644 -index 0000000000..1f45e51af8 ---- /dev/null -+++ b/tools/grit/grit/node/node_io_unittest.py -@@ -0,0 +1,182 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for node_io.FileNode''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+import unittest -+ -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+from six import StringIO -+ -+from grit.node import misc -+from grit.node import node_io -+from grit.node import empty -+from grit import grd_reader -+from grit import util -+ -+ -+def _GetAllCliques(root_node): -+ """Return all cliques in the |root_node| tree.""" -+ ret = [] -+ for node in root_node: -+ ret.extend(node.GetCliques()) -+ return ret -+ -+ -+class FileNodeUnittest(unittest.TestCase): -+ def testGetPath(self): -+ root = misc.GritNode() -+ root.StartParsing(u'grit', None) -+ root.HandleAttribute(u'latest_public_release', u'0') -+ root.HandleAttribute(u'current_release', u'1') -+ root.HandleAttribute(u'base_dir', r'..\resource') -+ translations = empty.TranslationsNode() -+ translations.StartParsing(u'translations', root) -+ root.AddChild(translations) -+ file_node = node_io.FileNode() -+ file_node.StartParsing(u'file', translations) -+ file_node.HandleAttribute(u'path', r'flugel\kugel.pdf') -+ translations.AddChild(file_node) -+ root.EndParsing() -+ -+ self.failUnless(root.ToRealPath(file_node.GetInputPath()) == -+ util.normpath( -+ os.path.join(r'../resource', r'flugel/kugel.pdf'))) -+ -+ def VerifyCliquesContainEnglishAndFrenchAndNothingElse(self, cliques): -+ self.assertEqual(2, len(cliques)) -+ for clique in cliques: -+ self.assertEqual({'en', 'fr'}, set(clique.clique.keys())) -+ -+ def testLoadTranslations(self): -+ xml = ''' -+ -+ -+ -+ -+ -+ -+ Hello! -+ Hello %sJoi -+ -+ -+ ''' -+ grd = grd_reader.Parse(StringIO(xml), -+ util.PathFromRoot('grit/testdata')) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ self.VerifyCliquesContainEnglishAndFrenchAndNothingElse(_GetAllCliques(grd)) -+ -+ def testIffyness(self): -+ grd = grd_reader.Parse(StringIO(''' -+ -+ -+ -+ -+ -+ -+ -+ -+ Hello! -+ Hello %sJoi -+ -+ -+ '''), util.PathFromRoot('grit/testdata')) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ cliques = _GetAllCliques(grd) -+ self.assertEqual(2, len(cliques)) -+ for clique in cliques: -+ self.assertEqual({'en'}, set(clique.clique.keys())) -+ -+ grd.SetOutputLanguage('fr') -+ grd.RunGatherers() -+ self.VerifyCliquesContainEnglishAndFrenchAndNothingElse(_GetAllCliques(grd)) -+ -+ def testConditionalLoadTranslations(self): -+ xml = ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Hello! -+ Hello %s -+ Joi -+ -+ -+ ''' -+ grd = grd_reader.Parse(StringIO(xml), -+ util.PathFromRoot('grit/testdata')) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ self.VerifyCliquesContainEnglishAndFrenchAndNothingElse(_GetAllCliques(grd)) -+ -+ def testConditionalOutput(self): -+ xml = ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Hello! -+ -+ -+ ''' -+ grd = grd_reader.Parse(StringIO(xml), -+ util.PathFromRoot('grit/test/data'), -+ defines={}) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ outputs = grd.GetChildrenOfType(node_io.OutputNode) -+ active = set(grd.ActiveDescendants()) -+ self.failUnless(outputs[0] in active) -+ self.failUnless(outputs[0].GetType() == 'rc_header') -+ self.failUnless(outputs[1] in active) -+ self.failUnless(outputs[1].GetType() == 'rc_all') -+ self.failUnless(outputs[2] not in active) -+ self.failUnless(outputs[2].GetType() == 'rc_all') -+ -+ # Verify that 'iw' and 'no' language codes in xtb files are mapped to 'he' and -+ # 'nb'. -+ def testLangCodeMapping(self): -+ grd = grd_reader.Parse(StringIO(''' -+ -+ -+ -+ -+ -+ -+ -+ -+ '''), util.PathFromRoot('grit/testdata')) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ self.assertEqual([], _GetAllCliques(grd)) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/node/structure.py b/tools/grit/grit/node/structure.py -new file mode 100644 -index 0000000000..ec170faebb ---- /dev/null -+++ b/tools/grit/grit/node/structure.py -@@ -0,0 +1,375 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''The element. -+''' -+ -+from __future__ import print_function -+ -+import os -+import platform -+import re -+ -+from grit import exception -+from grit import util -+from grit.node import base -+from grit.node import variant -+ -+import grit.gather.admin_template -+import grit.gather.chrome_html -+import grit.gather.chrome_scaled_image -+import grit.gather.policy_json -+import grit.gather.rc -+import grit.gather.tr_html -+import grit.gather.txt -+ -+import grit.format.rc -+ -+# Type of the gatherer to use for each type attribute -+_GATHERERS = { -+ 'accelerators' : grit.gather.rc.Accelerators, -+ 'admin_template' : grit.gather.admin_template.AdmGatherer, -+ 'chrome_html' : grit.gather.chrome_html.ChromeHtml, -+ 'chrome_scaled_image' : grit.gather.chrome_scaled_image.ChromeScaledImage, -+ 'dialog' : grit.gather.rc.Dialog, -+ 'menu' : grit.gather.rc.Menu, -+ 'rcdata' : grit.gather.rc.RCData, -+ 'tr_html' : grit.gather.tr_html.TrHtml, -+ 'txt' : grit.gather.txt.TxtFile, -+ 'version' : grit.gather.rc.Version, -+ 'policy_template_metafile' : grit.gather.policy_json.PolicyJson, -+} -+ -+ -+# TODO(joi) Print a warning if the 'variant_of_revision' attribute indicates -+# that a skeleton variant is older than the original file. -+ -+ -+class StructureNode(base.Node): -+ '''A element.''' -+ -+ # Regular expression for a local variable definition. Each definition -+ # is of the form NAME=VALUE, where NAME cannot contain '=' or ',' and -+ # VALUE must escape all commas: ',' -> ',,'. Each variable definition -+ # should be separated by a comma with no extra whitespace. -+ # Example: THING1=foo,THING2=bar -+ variable_pattern = re.compile(r'([^,=\s]+)=((?:,,|[^,])*)') -+ -+ def __init__(self): -+ super(StructureNode, self).__init__() -+ -+ # Keep track of the last filename we flattened to, so we can -+ # avoid doing it more than once. -+ self._last_flat_filename = None -+ -+ # See _Substitute; this substituter is used for local variables and -+ # the root substituter is used for global variables. -+ self.substituter = None -+ -+ def _IsValidChild(self, child): -+ return isinstance(child, variant.SkeletonNode) -+ -+ def _ParseVariables(self, variables): -+ '''Parse a variable string into a dictionary.''' -+ matches = StructureNode.variable_pattern.findall(variables) -+ return dict((name, value.replace(',,', ',')) for name, value in matches) -+ -+ def EndParsing(self): -+ super(StructureNode, self).EndParsing() -+ -+ # Now that we have attributes and children, instantiate the gatherers. -+ gathertype = _GATHERERS[self.attrs['type']] -+ -+ self.gatherer = gathertype(self.attrs['file'], -+ self.attrs['name'], -+ self.attrs['encoding']) -+ self.gatherer.SetGrdNode(self) -+ self.gatherer.SetUberClique(self.UberClique()) -+ if hasattr(self.GetRoot(), 'defines'): -+ self.gatherer.SetDefines(self.GetRoot().defines) -+ self.gatherer.SetAttributes(self.attrs) -+ if self.ExpandVariables(): -+ self.gatherer.SetFilenameExpansionFunction(self._Substitute) -+ -+ # Parse local variables and instantiate the substituter. -+ if self.attrs['variables']: -+ variables = self.attrs['variables'] -+ self.substituter = util.Substituter() -+ self.substituter.AddSubstitutions(self._ParseVariables(variables)) -+ -+ self.skeletons = {} # Maps expressions to skeleton gatherers -+ for child in self.children: -+ assert isinstance(child, variant.SkeletonNode) -+ skel = gathertype(child.attrs['file'], -+ self.attrs['name'], -+ child.GetEncodingToUse(), -+ is_skeleton=True) -+ skel.SetGrdNode(self) # TODO(benrg): Or child? Only used for ToRealPath -+ skel.SetUberClique(self.UberClique()) -+ if hasattr(self.GetRoot(), 'defines'): -+ skel.SetDefines(self.GetRoot().defines) -+ if self.ExpandVariables(): -+ skel.SetFilenameExpansionFunction(self._Substitute) -+ self.skeletons[child.attrs['expr']] = skel -+ -+ def MandatoryAttributes(self): -+ return ['type', 'name', 'file'] -+ -+ def DefaultAttributes(self): -+ return { -+ 'encoding': 'cp1252', -+ 'exclude_from_rc': 'false', -+ 'line_end': 'unix', -+ 'output_encoding': 'utf-8', -+ 'generateid': 'true', -+ 'expand_variables': 'false', -+ 'output_filename': '', -+ 'fold_whitespace': 'false', -+ # Run an arbitrary command after translation is complete -+ # so that it doesn't interfere with what's in translation -+ # console. -+ 'run_command': '', -+ # Leave empty to run on all platforms, comma-separated -+ # for one or more specific platforms. Values must match -+ # output of platform.system(). -+ 'run_command_on_platforms': '', -+ 'allowexternalscript': 'false', -+ # preprocess takes the same code path as flattenhtml, but it -+ # disables any processing/inlining outside of and . -+ 'preprocess': 'false', -+ 'flattenhtml': 'false', -+ 'fallback_to_low_resolution': 'default', -+ 'variables': '', -+ 'compress': 'default', -+ 'use_base_dir': 'true', -+ } -+ -+ def IsExcludedFromRc(self): -+ return self.attrs['exclude_from_rc'] == 'true' -+ -+ def Process(self, output_dir): -+ """Writes the processed data to output_dir. In the case of a chrome_html -+ structure this will add references to other scale factors. If flattening -+ this will also write file references to be base64 encoded data URLs. The -+ name of the new file is returned.""" -+ filename = self.ToRealPath(self.GetInputPath()) -+ flat_filename = os.path.join(output_dir, -+ self.attrs['name'] + '_' + os.path.basename(filename)) -+ -+ if self._last_flat_filename == flat_filename: -+ return -+ -+ with open(flat_filename, 'wb') as outfile: -+ if self.ExpandVariables(): -+ text = self.gatherer.GetText() -+ file_contents = self._Substitute(text) -+ else: -+ file_contents = self.gatherer.GetData('', 'utf-8') -+ outfile.write(file_contents.encode('utf-8')) -+ -+ self._last_flat_filename = flat_filename -+ return os.path.basename(flat_filename) -+ -+ def GetLineEnd(self): -+ '''Returns the end-of-line character or characters for files output because -+ of this node ('\r\n', '\n', or '\r' depending on the 'line_end' attribute). -+ ''' -+ if self.attrs['line_end'] == 'unix': -+ return '\n' -+ elif self.attrs['line_end'] == 'windows': -+ return '\r\n' -+ elif self.attrs['line_end'] == 'mac': -+ return '\r' -+ else: -+ raise exception.UnexpectedAttribute( -+ "Attribute 'line_end' must be one of 'unix' (default), 'windows' or " -+ "'mac'") -+ -+ def GetCliques(self): -+ return self.gatherer.GetCliques() -+ -+ def GetDataPackValue(self, lang, encoding): -+ """Returns a bytes representation for a data_pack entry.""" -+ if self.ExpandVariables(): -+ text = self.gatherer.GetText() -+ data = util.Encode(self._Substitute(text), encoding) -+ else: -+ data = self.gatherer.GetData(lang, encoding) -+ if encoding != util.BINARY: -+ data = data.encode(encoding) -+ return self.CompressDataIfNeeded(data) -+ -+ def GetHtmlResourceFilenames(self): -+ """Returns a set of all filenames inlined by this node.""" -+ return self.gatherer.GetHtmlResourceFilenames() -+ -+ def GetInputPath(self): -+ path = self.gatherer.GetInputPath() -+ if path is None: -+ return path -+ -+ # Do not mess with absolute paths, that would make them invalid. -+ if os.path.isabs(os.path.expandvars(path)): -+ return path -+ -+ # We have no control over code that calls ToRealPath later, so convert -+ # the path to be relative against our basedir. -+ if self.attrs.get('use_base_dir', 'true') != 'true': -+ # Normalize the directory path to use the appropriate OS separator. -+ # GetBaseDir() may return paths\like\this or paths/like/this, since it is -+ # read from the base_dir attribute in the grd file. -+ norm_base_dir = util.normpath(self.GetRoot().GetBaseDir()) -+ return os.path.relpath(path, norm_base_dir) -+ -+ return path -+ -+ def GetTextualIds(self): -+ if not hasattr(self, 'gatherer'): -+ # This case is needed because this method is called by -+ # GritNode.ValidateUniqueIds before RunGatherers has been called. -+ # TODO(benrg): Fix this? -+ return [self.attrs['name']] -+ return self.gatherer.GetTextualIds() -+ -+ def RunPreSubstitutionGatherer(self, debug=False): -+ if debug: -+ print('Running gatherer %s for file %s' % -+ (type(self.gatherer), self.GetInputPath())) -+ -+ # Note: Parse() is idempotent, therefore this method is also. -+ self.gatherer.Parse() -+ for skel in self.skeletons.values(): -+ skel.Parse() -+ -+ def GetSkeletonGatherer(self): -+ '''Returns the gatherer for the alternate skeleton that should be used, -+ based on the expressions for selecting skeletons, or None if the skeleton -+ from the English version of the structure should be used. -+ ''' -+ for expr in self.skeletons: -+ if self.EvaluateCondition(expr): -+ return self.skeletons[expr] -+ return None -+ -+ def HasFileForLanguage(self): -+ return self.attrs['type'] in ['tr_html', 'admin_template', 'txt', -+ 'chrome_scaled_image', -+ 'chrome_html'] -+ -+ def ExpandVariables(self): -+ '''Variable expansion on structures is controlled by an XML attribute. -+ -+ However, old files assume that expansion is always on for Rc files. -+ -+ Returns: -+ A boolean. -+ ''' -+ attrs = self.GetRoot().attrs -+ if 'grit_version' in attrs and attrs['grit_version'] > 1: -+ return self.attrs['expand_variables'] == 'true' -+ else: -+ return (self.attrs['expand_variables'] == 'true' or -+ self.attrs['file'].lower().endswith('.rc')) -+ -+ def _Substitute(self, text): -+ '''Perform local and global variable substitution.''' -+ if self.substituter: -+ text = self.substituter.Substitute(text) -+ return self.GetRoot().GetSubstituter().Substitute(text) -+ -+ def RunCommandOnCurrentPlatform(self): -+ if self.attrs['run_command_on_platforms'] == '': -+ return True -+ else: -+ target_platforms = self.attrs['run_command_on_platforms'].split(',') -+ return platform.system() in target_platforms -+ -+ def FileForLanguage(self, lang, output_dir, create_file=True, -+ return_if_not_generated=True): -+ '''Returns the filename of the file associated with this structure, -+ for the specified language. -+ -+ Args: -+ lang: 'fr' -+ output_dir: 'c:\temp' -+ create_file: True -+ ''' -+ assert self.HasFileForLanguage() -+ # If the source language is requested, and no extra changes are requested, -+ # use the existing file. -+ if ((not lang or lang == self.GetRoot().GetSourceLanguage()) and -+ self.attrs['expand_variables'] != 'true' and -+ (not self.attrs['run_command'] or -+ not self.RunCommandOnCurrentPlatform())): -+ if return_if_not_generated: -+ input_path = self.GetInputPath() -+ if input_path is None: -+ return None -+ return self.ToRealPath(input_path) -+ else: -+ return None -+ -+ if self.attrs['output_filename'] != '': -+ filename = self.attrs['output_filename'] -+ else: -+ filename = os.path.basename(self.attrs['file']) -+ assert len(filename) -+ filename = '%s_%s' % (lang, filename) -+ filename = os.path.join(output_dir, filename) -+ -+ # Only create the output if it was requested by the call. -+ if create_file: -+ text = self.gatherer.Translate( -+ lang, -+ pseudo_if_not_available=self.PseudoIsAllowed(), -+ fallback_to_english=self.ShouldFallbackToEnglish(), -+ skeleton_gatherer=self.GetSkeletonGatherer()) -+ -+ file_contents = util.FixLineEnd(text, self.GetLineEnd()) -+ if self.ExpandVariables(): -+ # Note that we reapply substitution a second time here. -+ # This is because a) we need to look inside placeholders -+ # b) the substitution values are language-dependent -+ file_contents = self._Substitute(file_contents) -+ -+ with open(filename, 'wb') as file_object: -+ output_stream = util.WrapOutputStream(file_object, -+ self.attrs['output_encoding']) -+ output_stream.write(file_contents) -+ -+ if self.attrs['run_command'] and self.RunCommandOnCurrentPlatform(): -+ # Run arbitrary commands after translation is complete so that it -+ # doesn't interfere with what's in translation console. -+ command = self.attrs['run_command'] % {'filename': filename} -+ result = os.system(command) -+ assert result == 0, '"%s" failed.' % command -+ -+ return filename -+ -+ def IsResourceMapSource(self): -+ return True -+ -+ @staticmethod -+ def Construct(parent, name, type, file, encoding='cp1252'): -+ '''Creates a new node which is a child of 'parent', with attributes set -+ by parameters of the same name. -+ ''' -+ node = StructureNode() -+ node.StartParsing('structure', parent) -+ node.HandleAttribute('name', name) -+ node.HandleAttribute('type', type) -+ node.HandleAttribute('file', file) -+ node.HandleAttribute('encoding', encoding) -+ node.EndParsing() -+ return node -+ -+ def SubstituteMessages(self, substituter): -+ '''Propagates substitution to gatherer. -+ -+ Args: -+ substituter: a grit.util.Substituter object. -+ ''' -+ assert hasattr(self, 'gatherer') -+ if self.ExpandVariables(): -+ self.gatherer.SubstituteMessages(substituter) -diff --git a/tools/grit/grit/node/structure_unittest.py b/tools/grit/grit/node/structure_unittest.py -new file mode 100644 -index 0000000000..0e66dce37a ---- /dev/null -+++ b/tools/grit/grit/node/structure_unittest.py -@@ -0,0 +1,178 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for nodes. -+''' -+ -+from __future__ import print_function -+ -+import os -+import os.path -+import sys -+import zlib -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+import platform -+import tempfile -+import unittest -+import struct -+ -+from grit import constants -+from grit import util -+from grit.node import brotli_util -+from grit.node import structure -+from grit.format import rc -+ -+ -+def checkIsGzipped(filename, compress_attr): -+ test_data_root = util.PathFromRoot('grit/testdata') -+ root = util.ParseGrdForUnittest( -+ ''' -+ -+ -+ ''' % (filename, compress_attr), -+ base_dir=test_data_root) -+ node, = root.GetChildrenOfType(structure.StructureNode) -+ node.RunPreSubstitutionGatherer() -+ compressed = node.GetDataPackValue(lang='en', encoding=util.BINARY) -+ -+ decompressed_data = zlib.decompress(compressed, 16 + zlib.MAX_WBITS) -+ expected = util.ReadFile(os.path.join(test_data_root, filename), util.BINARY) -+ return expected == decompressed_data -+ -+ -+class StructureUnittest(unittest.TestCase): -+ def testSkeleton(self): -+ grd = util.ParseGrdForUnittest(''' -+ -+ -+ -+ -+ ''', base_dir=util.PathFromRoot('grit/testdata')) -+ grd.SetOutputLanguage('fr') -+ grd.RunGatherers() -+ transl = ''.join(rc.Format(grd, 'fr', '.')) -+ self.failUnless(transl.count('040704') and transl.count('110978')) -+ self.failUnless(transl.count('2005",IDC_STATIC')) -+ -+ def testRunCommandOnCurrentPlatform(self): -+ node = structure.StructureNode() -+ node.attrs = node.DefaultAttributes() -+ self.failUnless(node.RunCommandOnCurrentPlatform()) -+ node.attrs['run_command_on_platforms'] = 'Nosuch' -+ self.failIf(node.RunCommandOnCurrentPlatform()) -+ node.attrs['run_command_on_platforms'] = ( -+ 'Nosuch,%s,Othernot' % platform.system()) -+ self.failUnless(node.RunCommandOnCurrentPlatform()) -+ -+ def testVariables(self): -+ grd = util.ParseGrdForUnittest(''' -+ -+ -+ ''', base_dir=util.PathFromRoot('grit/testdata')) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ node, = grd.GetChildrenOfType(structure.StructureNode) -+ filename = node.Process(tempfile.gettempdir()) -+ filepath = os.path.join(tempfile.gettempdir(), filename) -+ with open(filepath) as f: -+ result = f.read() -+ self.failUnlessEqual(('

    Hello!

    \n' -+ 'Some cool things are foo, bar, baz.\n' -+ 'Did you know that 2+2==4?\n' -+ '

    \n' -+ ' Hello!\n' -+ '

    \n'), result) -+ os.remove(filepath) -+ -+ def testGetPath(self): -+ base_dir = util.PathFromRoot('grit/testdata') -+ grd = util.ParseGrdForUnittest(''' -+ -+ -+ ''', base_dir) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ node, = grd.GetChildrenOfType(structure.StructureNode) -+ self.assertEqual(grd.ToRealPath(node.GetInputPath()), -+ os.path.abspath(os.path.join( -+ base_dir, r'structure_variables.html'))) -+ -+ def testGetPathNoBasedir(self): -+ base_dir = util.PathFromRoot('grit/testdata') -+ abs_path = os.path.join(base_dir, r'structure_variables.html') -+ rel_path = os.path.relpath(abs_path, os.getcwd()) -+ grd = util.ParseGrdForUnittest(''' -+ -+ -+ ''', util.PathFromRoot('grit/testdata')) -+ grd.SetOutputLanguage('en') -+ grd.RunGatherers() -+ node, = grd.GetChildrenOfType(structure.StructureNode) -+ self.assertEqual(grd.ToRealPath(node.GetInputPath()), -+ os.path.abspath(os.path.join( -+ base_dir, r'structure_variables.html'))) -+ -+ def testCompressGzip(self): -+ self.assertTrue(checkIsGzipped('test_text.txt', 'compress="gzip"')) -+ -+ def testCompressGzipByDefault(self): -+ self.assertTrue(checkIsGzipped('test_html.html', '')) -+ self.assertTrue(checkIsGzipped('test_js.js', '')) -+ self.assertTrue(checkIsGzipped('test_css.css', '')) -+ self.assertTrue(checkIsGzipped('test_svg.svg', '')) -+ -+ self.assertTrue(checkIsGzipped('test_html.html', 'compress="default"')) -+ self.assertTrue(checkIsGzipped('test_js.js', 'compress="default"')) -+ self.assertTrue(checkIsGzipped('test_css.css', 'compress="default"')) -+ self.assertTrue(checkIsGzipped('test_svg.svg', 'compress="default"')) -+ -+ def testCompressBrotli(self): -+ test_data_root = util.PathFromRoot('grit/testdata') -+ root = util.ParseGrdForUnittest( -+ ''' -+ -+ -+ ''', -+ base_dir=test_data_root) -+ node, = root.GetChildrenOfType(structure.StructureNode) -+ node.RunPreSubstitutionGatherer() -+ -+ # Using the mock brotli decompression executable. -+ brotli_util.SetBrotliCommand([sys.executable, -+ os.path.join(os.path.dirname(__file__), -+ 'mock_brotli.py')]) -+ compressed = node.GetDataPackValue(lang='en', encoding=util.BINARY) -+ # Assert that the first two bytes in compressed format is BROTLI_CONST. -+ self.assertEqual(constants.BROTLI_CONST, compressed[0:2]) -+ -+ # Compare the actual size of the uncompressed test data with -+ # the size appended during compression. -+ actual_size = len(util.ReadFile( -+ os.path.join(test_data_root, 'test_text.txt'), util.BINARY)) -+ uncompress_size = struct.unpack(' -+ -+ ''', base_dir=test_data_root) -+ node, = root.GetChildrenOfType(structure.StructureNode) -+ node.RunPreSubstitutionGatherer() -+ data = node.GetDataPackValue(lang='en', encoding=util.BINARY) -+ -+ self.assertEqual(util.ReadFile( -+ os.path.join(test_data_root, 'test_text.txt'), util.BINARY), data) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/node/variant.py b/tools/grit/grit/node/variant.py -new file mode 100644 -index 0000000000..9f5845f954 ---- /dev/null -+++ b/tools/grit/grit/node/variant.py -@@ -0,0 +1,41 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''The element. -+''' -+ -+from __future__ import print_function -+ -+from grit.node import base -+ -+ -+class SkeletonNode(base.Node): -+ '''A element.''' -+ -+ # TODO(joi) Support inline skeleton variants as CDATA instead of requiring -+ # a 'file' attribute. -+ -+ def MandatoryAttributes(self): -+ return ['expr', 'variant_of_revision', 'file'] -+ -+ def DefaultAttributes(self): -+ '''If not specified, 'encoding' will actually default to the parent node's -+ encoding. -+ ''' -+ return {'encoding' : ''} -+ -+ def _ContentType(self): -+ if 'file' in self.attrs: -+ return self._CONTENT_TYPE_NONE -+ else: -+ return self._CONTENT_TYPE_CDATA -+ -+ def GetEncodingToUse(self): -+ if self.attrs['encoding'] == '': -+ return self.parent.attrs['encoding'] -+ else: -+ return self.attrs['encoding'] -+ -+ def GetInputPath(self): -+ return self.attrs['file'] -diff --git a/tools/grit/grit/pseudo.py b/tools/grit/grit/pseudo.py -new file mode 100644 -index 0000000000..b607bfc6bb ---- /dev/null -+++ b/tools/grit/grit/pseudo.py -@@ -0,0 +1,129 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Pseudotranslation support. Our pseudotranslations are based on the -+P-language, which is a simple vowel-extending language. Examples of P: -+ - "hello" becomes "hepellopo" -+ - "howdie" becomes "hopowdiepie" -+ - "because" becomes "bepecaupause" (but in our implementation we don't -+ handle the silent e at the end so it actually would return "bepecaupausepe" -+ -+The P-language has the excellent quality of increasing the length of text -+by around 30-50% which is great for pseudotranslations, to stress test any -+GUI layouts etc. -+ -+To make the pseudotranslations more obviously "not a translation" and to make -+them exercise any code that deals with encodings, we also transform all English -+vowels into equivalent vowels with diacriticals on them (rings, acutes, -+diaresis, and circumflex), and we write the "p" in the P-language as a Hebrew -+character Qof. It looks sort of like a latin character "p" but it is outside -+the latin-1 character set which will stress character encoding bugs. -+''' -+ -+from __future__ import print_function -+ -+from grit import lazy_re -+from grit import tclib -+ -+ -+# An RFC language code for the P pseudolanguage. -+PSEUDO_LANG = 'x-P-pseudo' -+ -+# Hebrew character Qof. It looks kind of like a 'p' but is outside -+# the latin-1 character set which is good for our purposes. -+# TODO(joi) For now using P instead of Qof, because of some bugs it used. Find -+# a better solution, i.e. one that introduces a non-latin1 character into the -+# pseudotranslation. -+#_QOF = u'\u05e7' -+_QOF = u'P' -+ -+# How we map each vowel. -+_VOWELS = { -+ u'a' : u'\u00e5', # a with ring -+ u'e' : u'\u00e9', # e acute -+ u'i' : u'\u00ef', # i diaresis -+ u'o' : u'\u00f4', # o circumflex -+ u'u' : u'\u00fc', # u diaresis -+ u'y' : u'\u00fd', # y acute -+ u'A' : u'\u00c5', # A with ring -+ u'E' : u'\u00c9', # E acute -+ u'I' : u'\u00cf', # I diaresis -+ u'O' : u'\u00d4', # O circumflex -+ u'U' : u'\u00dc', # U diaresis -+ u'Y' : u'\u00dd', # Y acute -+} -+_VOWELS_KEYS = set(_VOWELS.keys()) -+ -+# Matches vowels and P -+_PSUB_RE = lazy_re.compile("(%s)" % '|'.join(_VOWELS_KEYS | {'P'})) -+ -+ -+# Pseudotranslations previously created. This is important for performance -+# reasons, especially since we routinely pseudotranslate the whole project -+# several or many different times for each build. -+_existing_translations = {} -+ -+ -+def MapVowels(str, also_p = False): -+ '''Returns a copy of 'str' where characters that exist as keys in _VOWELS -+ have been replaced with the corresponding value. If also_p is true, this -+ function will also change capital P characters into a Hebrew character Qof. -+ ''' -+ def Repl(match): -+ if match.group() == 'p': -+ if also_p: -+ return _QOF -+ else: -+ return 'p' -+ else: -+ return _VOWELS[match.group()] -+ return _PSUB_RE.sub(Repl, str) -+ -+ -+def PseudoString(str): -+ '''Returns a pseudotranslation of the provided string, in our enhanced -+ P-language.''' -+ if str in _existing_translations: -+ return _existing_translations[str] -+ -+ outstr = u'' -+ ix = 0 -+ while ix < len(str): -+ if str[ix] not in _VOWELS_KEYS: -+ outstr += str[ix] -+ ix += 1 -+ else: -+ # We want to treat consecutive vowels as one composite vowel. This is not -+ # always accurate e.g. in composite words but good enough. -+ consecutive_vowels = u'' -+ while ix < len(str) and str[ix] in _VOWELS_KEYS: -+ consecutive_vowels += str[ix] -+ ix += 1 -+ changed_vowels = MapVowels(consecutive_vowels) -+ outstr += changed_vowels -+ outstr += _QOF -+ outstr += changed_vowels -+ -+ _existing_translations[str] = outstr -+ return outstr -+ -+ -+def PseudoMessage(message): -+ '''Returns a pseudotranslation of the provided message. -+ -+ Args: -+ message: tclib.Message() -+ -+ Return: -+ tclib.Translation() -+ ''' -+ transl = tclib.Translation() -+ -+ for part in message.GetContent(): -+ if isinstance(part, tclib.Placeholder): -+ transl.AppendPlaceholder(part) -+ else: -+ transl.AppendText(PseudoString(part)) -+ -+ return transl -diff --git a/tools/grit/grit/pseudo_rtl.py b/tools/grit/grit/pseudo_rtl.py -new file mode 100644 -index 0000000000..2240b571de ---- /dev/null -+++ b/tools/grit/grit/pseudo_rtl.py -@@ -0,0 +1,104 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Pseudo RTL, (aka Fake Bidi) support. It simply wraps each word with -+Unicode RTL overrides. -+More info at https://sites.google.com/a/chromium.org/dev/Home/fake-bidi -+''' -+ -+from __future__ import print_function -+ -+import re -+ -+from grit import lazy_re -+from grit import tclib -+ -+ACCENTED_STRINGS = { -+ 'a': u"\u00e5", 'e': u"\u00e9", 'i': u"\u00ee", 'o': u"\u00f6", -+ 'u': u"\u00fb", 'A': u"\u00c5", 'E': u"\u00c9", 'I': u"\u00ce", -+ 'O': u"\u00d6", 'U': u"\u00db", 'c': u"\u00e7", 'd': u"\u00f0", -+ 'n': u"\u00f1", 'p': u"\u00fe", 'y': u"\u00fd", 'C': u"\u00c7", -+ 'D': u"\u00d0", 'N': u"\u00d1", 'P': u"\u00de", 'Y': u"\u00dd", -+ 'f': u"\u0192", 's': u"\u0161", 'S': u"\u0160", 'z': u"\u017e", -+ 'Z': u"\u017d", 'g': u"\u011d", 'G': u"\u011c", 'h': u"\u0125", -+ 'H': u"\u0124", 'j': u"\u0135", 'J': u"\u0134", 'k': u"\u0137", -+ 'K': u"\u0136", 'l': u"\u013c", 'L': u"\u013b", 't': u"\u0163", -+ 'T': u"\u0162", 'w': u"\u0175", 'W': u"\u0174", -+ '$': u"\u20ac", '?': u"\u00bf", 'R': u"\u00ae", r'!': u"\u00a1", -+} -+ -+# a character set containing the keys in ACCENTED_STRINGS -+# We should not accent characters in an escape sequence such as "\n". -+# To be safe, we assume every character following a backslash is an escaped -+# character. We also need to consider the case like "\\n", which means -+# a blackslash and a character "n", we will accent the character "n". -+TO_ACCENT = lazy_re.compile( -+ r'[%s]|\\[a-z\\]' % ''.join(ACCENTED_STRINGS.keys())) -+ -+# Lex text so that we don't interfere with html tokens and entities. -+# This lexing scheme will handle all well formed tags and entities, html or -+# xhtml. It will not handle comments, CDATA sections, or the unescaping tags: -+# script, style, xmp or listing. If any of those appear in messages, -+# something is wrong. -+TOKENS = [ lazy_re.compile( -+ '^%s' % pattern, # match at the beginning of input -+ re.I | re.S # html tokens are case-insensitive -+ ) -+ for pattern in -+ ( -+ # a run of non html special characters -+ r'[^<&]+', -+ # a tag -+ (r']+|"[^\"]*"|\'[^\']*\'))?' # attribute value -+ r')*\s*/?>'), -+ # an entity -+ r'&(?:[a-z]\w+|#\d+|#x[\da-f]+);', -+ # an html special character not part of a special sequence -+ r'.' -+ ) ] -+ -+ALPHABETIC_RUN = lazy_re.compile(r'([^\W0-9_]+)') -+ -+RLO = u'\u202e' -+PDF = u'\u202c' -+ -+def PseudoRTLString(text): -+ '''Returns a fake bidirectional version of the source string. This code is -+ based on accentString above, in turn copied from Frank Tang. -+ ''' -+ parts = [] -+ while text: -+ m = None -+ for token in TOKENS: -+ m = token.search(text) -+ if m: -+ part = m.group(0) -+ text = text[len(part):] -+ if part[0] not in ('<', '&'): -+ # not a tag or entity, so accent -+ part = ALPHABETIC_RUN.sub(lambda run: RLO + run.group() + PDF, part) -+ parts.append(part) -+ break -+ return ''.join(parts) -+ -+ -+def PseudoRTLMessage(message): -+ '''Returns a pseudo-RTL (aka Fake-Bidi) translation of the provided message. -+ -+ Args: -+ message: tclib.Message() -+ -+ Return: -+ tclib.Translation() -+ ''' -+ transl = tclib.Translation() -+ for part in message.GetContent(): -+ if isinstance(part, tclib.Placeholder): -+ transl.AppendPlaceholder(part) -+ else: -+ transl.AppendText(PseudoRTLString(part)) -+ -+ return transl -diff --git a/tools/grit/grit/pseudo_unittest.py b/tools/grit/grit/pseudo_unittest.py -new file mode 100644 -index 0000000000..b1d53ff401 ---- /dev/null -+++ b/tools/grit/grit/pseudo_unittest.py -@@ -0,0 +1,55 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grit.pseudo''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -+ -+import unittest -+ -+from grit import pseudo -+from grit import tclib -+ -+ -+class PseudoUnittest(unittest.TestCase): -+ def testVowelMapping(self): -+ self.failUnless(pseudo.MapVowels('abebibobuby') == -+ u'\u00e5b\u00e9b\u00efb\u00f4b\u00fcb\u00fd') -+ self.failUnless(pseudo.MapVowels('ABEBIBOBUBY') == -+ u'\u00c5B\u00c9B\u00cfB\u00d4B\u00dcB\u00dd') -+ -+ def testPseudoString(self): -+ out = pseudo.PseudoString('hello') -+ self.failUnless(out == pseudo.MapVowels(u'hePelloPo', True)) -+ -+ def testConsecutiveVowels(self): -+ out = pseudo.PseudoString("beautiful weather, ain't it?") -+ self.failUnless(out == pseudo.MapVowels( -+ u"beauPeautiPifuPul weaPeathePer, aiPain't iPit?", 1)) -+ -+ def testCapitals(self): -+ out = pseudo.PseudoString("HOWDIE DOODIE, DR. JONES") -+ self.failUnless(out == pseudo.MapVowels( -+ u"HOPOWDIEPIE DOOPOODIEPIE, DR. JOPONEPES", 1)) -+ -+ def testPseudoMessage(self): -+ msg = tclib.Message(text='Hello USERNAME, how are you?', -+ placeholders=[ -+ tclib.Placeholder('USERNAME', '%s', 'Joi')]) -+ trans = pseudo.PseudoMessage(msg) -+ # TODO(joi) It would be nicer if 'you' -> 'youPou' instead of -+ # 'you' -> 'youPyou' and if we handled the silent e in 'are' -+ self.failUnless(trans.GetPresentableContent() == -+ pseudo.MapVowels( -+ u'HePelloPo USERNAME, hoPow aParePe youPyou?', 1)) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/shortcuts.py b/tools/grit/grit/shortcuts.py -new file mode 100644 -index 0000000000..0db2ce436c ---- /dev/null -+++ b/tools/grit/grit/shortcuts.py -@@ -0,0 +1,93 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Stuff to prevent conflicting shortcuts. -+''' -+ -+from __future__ import print_function -+ -+from grit import lazy_re -+ -+ -+class ShortcutGroup(object): -+ '''Manages a list of cliques that belong together in a single shortcut -+ group. Knows how to detect conflicting shortcut keys. -+ ''' -+ -+ # Matches shortcut keys, e.g. &J -+ SHORTCUT_RE = lazy_re.compile('([^&]|^)(&[A-Za-z])') -+ -+ def __init__(self, name): -+ self.name = name -+ # Map of language codes to shortcut keys used (which is a map of -+ # shortcut keys to counts). -+ self.keys_by_lang = {} -+ # List of cliques in this group -+ self.cliques = [] -+ -+ def AddClique(self, c): -+ for existing_clique in self.cliques: -+ if existing_clique.GetId() == c.GetId(): -+ # This happens e.g. when we have e.g. -+ # -+ # where only one will really be included in the output. -+ return -+ -+ self.cliques.append(c) -+ for (lang, msg) in c.clique.items(): -+ if lang not in self.keys_by_lang: -+ self.keys_by_lang[lang] = {} -+ keymap = self.keys_by_lang[lang] -+ -+ content = msg.GetRealContent() -+ keys = [groups[1] for groups in self.SHORTCUT_RE.findall(content)] -+ for key in keys: -+ key = key.upper() -+ if key in keymap: -+ keymap[key] += 1 -+ else: -+ keymap[key] = 1 -+ -+ def GenerateWarnings(self, tc_project): -+ # For any language that has more than one occurrence of any shortcut, -+ # make a list of the conflicting shortcuts. -+ problem_langs = {} -+ for (lang, keys) in self.keys_by_lang.items(): -+ for (key, count) in keys.items(): -+ if count > 1: -+ if lang not in problem_langs: -+ problem_langs[lang] = [] -+ problem_langs[lang].append(key) -+ -+ warnings = [] -+ if len(problem_langs): -+ warnings.append("WARNING - duplicate keys exist in shortcut group %s" % -+ self.name) -+ for (lang,keys) in problem_langs.items(): -+ warnings.append(" %6s duplicates: %s" % (lang, ', '.join(keys))) -+ return warnings -+ -+ -+def GenerateDuplicateShortcutsWarnings(uberclique, tc_project): -+ '''Given an UberClique and a project name, will print out helpful warnings -+ if there are conflicting shortcuts within shortcut groups in the provided -+ UberClique. -+ -+ Args: -+ uberclique: clique.UberClique() -+ tc_project: 'MyProjectNameInTheTranslationConsole' -+ -+ Returns: -+ ['warning line 1', 'warning line 2', ...] -+ ''' -+ warnings = [] -+ groups = {} -+ for c in uberclique.AllCliques(): -+ for group in c.shortcut_groups: -+ if group not in groups: -+ groups[group] = ShortcutGroup(group) -+ groups[group].AddClique(c) -+ for group in groups.values(): -+ warnings += group.GenerateWarnings(tc_project) -+ return warnings -diff --git a/tools/grit/grit/shortcuts_unittest.py b/tools/grit/grit/shortcuts_unittest.py -new file mode 100644 -index 0000000000..30e7c4f758 ---- /dev/null -+++ b/tools/grit/grit/shortcuts_unittest.py -@@ -0,0 +1,79 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grit.shortcuts -+''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -+ -+import unittest -+ -+from six import StringIO -+ -+from grit import shortcuts -+from grit import clique -+from grit import tclib -+from grit.gather import rc -+ -+class ShortcutsUnittest(unittest.TestCase): -+ -+ def setUp(self): -+ self.uq = clique.UberClique() -+ -+ def testFunctionality(self): -+ c = self.uq.MakeClique(tclib.Message(text="Hello &there")) -+ c.AddToShortcutGroup('group_name') -+ c = self.uq.MakeClique(tclib.Message(text="Howdie &there partner")) -+ c.AddToShortcutGroup('group_name') -+ -+ warnings = shortcuts.GenerateDuplicateShortcutsWarnings(self.uq, 'PROJECT') -+ self.failUnless(warnings) -+ -+ def testAmpersandEscaping(self): -+ c = self.uq.MakeClique(tclib.Message(text="Hello &there")) -+ c.AddToShortcutGroup('group_name') -+ c = self.uq.MakeClique(tclib.Message(text="S&&T are the &letters S and T")) -+ c.AddToShortcutGroup('group_name') -+ -+ warnings = shortcuts.GenerateDuplicateShortcutsWarnings(self.uq, 'PROJECT') -+ self.failUnless(len(warnings) == 0) -+ -+ def testDialog(self): -+ dlg = rc.Dialog(StringIO('''\ -+IDD_SIDEBAR_RSS_PANEL_PROPPAGE DIALOGEX 0, 0, 239, 221 -+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -+FONT 8, "MS Shell Dlg", 400, 0, 0x1 -+BEGIN -+ PUSHBUTTON "Add &URL",IDC_SIDEBAR_RSS_ADD_URL,182,53,57,14 -+ EDITTEXT IDC_SIDEBAR_RSS_NEW_URL,0,53,178,15,ES_AUTOHSCROLL -+ PUSHBUTTON "&Remove",IDC_SIDEBAR_RSS_REMOVE,183,200,56,14 -+ PUSHBUTTON "&Edit",IDC_SIDEBAR_RSS_EDIT,123,200,56,14 -+ CONTROL "&Automatically add commonly viewed clips", -+ IDC_SIDEBAR_RSS_AUTO_ADD,"Button",BS_AUTOCHECKBOX | -+ BS_MULTILINE | WS_TABSTOP,0,200,120,17 -+ PUSHBUTTON "",IDC_SIDEBAR_RSS_HIDDEN,179,208,6,6,NOT WS_VISIBLE -+ LTEXT "You can display clips from blogs, news sites, and other online sources.", -+ IDC_STATIC,0,0,239,10 -+ LISTBOX IDC_SIDEBAR_DISPLAYED_FEED_LIST,0,69,239,127,LBS_SORT | -+ LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | -+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | -+ WS_TABSTOP -+ LTEXT "Add a clip from a recently viewed website by clicking Add Recent Clips.", -+ IDC_STATIC,0,13,141,19 -+ LTEXT "Or, if you know a site supports RSS or Atom, you can enter the RSS or Atom URL below and add it to your list of Web Clips.", -+ IDC_STATIC,0,33,239,18 -+ PUSHBUTTON "Add Recent &Clips (10)...", -+ IDC_SIDEBAR_RSS_ADD_RECENT_CLIPS,146,14,93,14 -+END'''), 'IDD_SIDEBAR_RSS_PANEL_PROPPAGE') -+ dlg.SetUberClique(self.uq) -+ dlg.Parse() -+ -+ warnings = shortcuts.GenerateDuplicateShortcutsWarnings(self.uq, 'PROJECT') -+ self.failUnless(len(warnings) == 0) -+ -diff --git a/tools/grit/grit/tclib.py b/tools/grit/grit/tclib.py -new file mode 100644 -index 0000000000..27ba366924 ---- /dev/null -+++ b/tools/grit/grit/tclib.py -@@ -0,0 +1,246 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Adaptation of the extern.tclib classes for our needs. -+''' -+ -+from __future__ import print_function -+ -+import functools -+import re -+ -+import six -+ -+from grit import exception -+from grit import lazy_re -+import grit.extern.tclib -+ -+ -+# Matches whitespace sequences which can be folded into a single whitespace -+# character. This matches single characters so that non-spaces are replaced -+# with spaces. -+_FOLD_WHITESPACE = re.compile(r'\s+') -+ -+# Caches compiled regexp used to split tags in BaseMessage.__init__() -+_RE_CACHE = {} -+ -+def Identity(i): -+ return i -+ -+ -+class BaseMessage(object): -+ '''Base class with methods shared by Message and Translation. -+ ''' -+ -+ def __init__(self, text='', placeholders=[], description='', meaning=''): -+ self.parts = [] -+ self.placeholders = [] -+ self.meaning = meaning -+ self.dirty = True # True if self.id is (or might be) wrong -+ self.id = 0 -+ self.SetDescription(description) -+ -+ if text != '': -+ if not placeholders or placeholders == []: -+ self.AppendText(text) -+ else: -+ tag_map = {} -+ for placeholder in placeholders: -+ tag_map[placeholder.GetPresentation()] = [placeholder, 0] -+ # This creates a regexp like '(TAG1|TAG2|TAG3)'. -+ # The tags have to be sorted in order of decreasing length, so that -+ # longer tags are substituted before shorter tags that happen to be -+ # substrings of the longer tag. -+ # E.g. "EXAMPLE_FOO_NAME" must be matched before "EXAMPLE_FOO", -+ # otherwise "EXAMPLE_FOO" splits "EXAMPLE_FOO_NAME" too. -+ tags = sorted(tag_map.keys(), -+ key=functools.cmp_to_key( -+ lambda x, y: len(x) - len(y) or ((x > y) - (x < y))), -+ reverse=True) -+ tag_re = '(' + '|'.join(tags) + ')' -+ -+ # This caching improves the time to build -+ # chrome/app:generated_resources from 21.562s to 17.672s on Linux. -+ compiled_re = _RE_CACHE.get(tag_re, None) -+ if compiled_re is None: -+ compiled_re = re.compile(tag_re) -+ _RE_CACHE[tag_re] = compiled_re -+ -+ chunked_text = compiled_re.split(text) -+ -+ for chunk in chunked_text: -+ if chunk: # ignore empty chunk -+ if chunk in tag_map: -+ self.AppendPlaceholder(tag_map[chunk][0]) -+ tag_map[chunk][1] += 1 # increase placeholder use count -+ else: -+ self.AppendText(chunk) -+ for key in tag_map: -+ assert tag_map[key][1] != 0 -+ -+ def GetRealContent(self, escaping_function=Identity): -+ '''Returns the original content, i.e. what your application and users -+ will see. -+ -+ Specify a function to escape each translateable bit, if you like. -+ ''' -+ bits = [] -+ for item in self.parts: -+ if isinstance(item, six.string_types): -+ bits.append(escaping_function(item)) -+ else: -+ bits.append(item.GetOriginal()) -+ return ''.join(bits) -+ -+ def GetPresentableContent(self): -+ presentable_content = [] -+ for part in self.parts: -+ if isinstance(part, Placeholder): -+ presentable_content.append(part.GetPresentation()) -+ else: -+ presentable_content.append(part) -+ return ''.join(presentable_content) -+ -+ def AppendPlaceholder(self, placeholder): -+ assert isinstance(placeholder, Placeholder) -+ dup = False -+ for other in self.GetPlaceholders(): -+ if other.presentation == placeholder.presentation: -+ assert other.original == placeholder.original -+ dup = True -+ -+ if not dup: -+ self.placeholders.append(placeholder) -+ self.parts.append(placeholder) -+ self.dirty = True -+ -+ def AppendText(self, text): -+ assert isinstance(text, six.string_types) -+ assert text != '' -+ -+ self.parts.append(text) -+ self.dirty = True -+ -+ def GetContent(self): -+ '''Returns the parts of the message. You may modify parts if you wish. -+ Note that you must not call GetId() on this object until you have finished -+ modifying the contents. -+ ''' -+ self.dirty = True # user might modify content -+ return self.parts -+ -+ def GetDescription(self): -+ return self.description -+ -+ def SetDescription(self, description): -+ self.description = _FOLD_WHITESPACE.sub(' ', description) -+ -+ def GetMeaning(self): -+ return self.meaning -+ -+ def GetId(self): -+ if self.dirty: -+ self.id = self.GenerateId() -+ self.dirty = False -+ return self.id -+ -+ def GenerateId(self): -+ return grit.extern.tclib.GenerateMessageId(self.GetPresentableContent(), -+ self.meaning) -+ -+ def GetPlaceholders(self): -+ return self.placeholders -+ -+ def FillTclibBaseMessage(self, msg): -+ msg.SetDescription(self.description.encode('utf-8')) -+ -+ for part in self.parts: -+ if isinstance(part, Placeholder): -+ ph = grit.extern.tclib.Placeholder( -+ part.presentation.encode('utf-8'), -+ part.original.encode('utf-8'), -+ part.example.encode('utf-8')) -+ msg.AppendPlaceholder(ph) -+ else: -+ msg.AppendText(part.encode('utf-8')) -+ -+ -+class Message(BaseMessage): -+ '''A message.''' -+ -+ def __init__(self, text='', placeholders=[], description='', meaning='', -+ assigned_id=None): -+ super(Message, self).__init__(text, placeholders, description, meaning) -+ self.assigned_id = assigned_id -+ -+ def ToTclibMessage(self): -+ msg = grit.extern.tclib.Message('utf-8', meaning=self.meaning) -+ self.FillTclibBaseMessage(msg) -+ return msg -+ -+ def GetId(self): -+ '''Use the assigned id if we have one.''' -+ if self.assigned_id: -+ return self.assigned_id -+ -+ return super(Message, self).GetId() -+ -+ def HasAssignedId(self): -+ '''Returns True if this message has an assigned id.''' -+ return bool(self.assigned_id) -+ -+ -+class Translation(BaseMessage): -+ '''A translation.''' -+ -+ def __init__(self, text='', id='', placeholders=[], description='', meaning=''): -+ super(Translation, self).__init__(text, placeholders, description, meaning) -+ self.id = id -+ -+ def GetId(self): -+ assert id != '', "ID has not been set." -+ return self.id -+ -+ def SetId(self, id): -+ self.id = id -+ -+ def ToTclibMessage(self): -+ msg = grit.extern.tclib.Message( -+ 'utf-8', id=self.id, meaning=self.meaning) -+ self.FillTclibBaseMessage(msg) -+ return msg -+ -+ -+class Placeholder(grit.extern.tclib.Placeholder): -+ '''Modifies constructor to accept a Unicode string -+ ''' -+ -+ # Must match placeholder presentation names -+ _NAME_RE = lazy_re.compile('^[A-Za-z0-9_]+$') -+ -+ def __init__(self, presentation, original, example): -+ '''Creates a new placeholder. -+ -+ Args: -+ presentation: 'USERNAME' -+ original: '%s' -+ example: 'Joi' -+ ''' -+ assert presentation != '' -+ assert original != '' -+ assert example != '' -+ if not self._NAME_RE.match(presentation): -+ raise exception.InvalidPlaceholderName(presentation) -+ self.presentation = presentation -+ self.original = original -+ self.example = example -+ -+ def GetPresentation(self): -+ return self.presentation -+ -+ def GetOriginal(self): -+ return self.original -+ -+ def GetExample(self): -+ return self.example -diff --git a/tools/grit/grit/tclib_unittest.py b/tools/grit/grit/tclib_unittest.py -new file mode 100644 -index 0000000000..7a08654e1b ---- /dev/null -+++ b/tools/grit/grit/tclib_unittest.py -@@ -0,0 +1,180 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grit.tclib''' -+ -+from __future__ import print_function -+ -+import sys -+import os.path -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -+ -+import unittest -+ -+import six -+ -+from grit import tclib -+ -+from grit import exception -+import grit.extern.tclib -+ -+ -+class TclibUnittest(unittest.TestCase): -+ def testInit(self): -+ msg = tclib.Message(text=u'Hello Earthlings', -+ description='Greetings\n\t message') -+ self.failUnlessEqual(msg.GetPresentableContent(), 'Hello Earthlings') -+ self.failUnless(isinstance(msg.GetPresentableContent(), six.string_types)) -+ self.failUnlessEqual(msg.GetDescription(), 'Greetings message') -+ -+ def testGetAttr(self): -+ msg = tclib.Message() -+ msg.AppendText(u'Hello') # Tests __getattr__ -+ self.failUnless(msg.GetPresentableContent() == 'Hello') -+ self.failUnless(isinstance(msg.GetPresentableContent(), six.string_types)) -+ -+ def testAll(self): -+ text = u'Howdie USERNAME' -+ phs = [tclib.Placeholder(u'USERNAME', u'%s', 'Joi')] -+ msg = tclib.Message(text=text, placeholders=phs) -+ self.failUnless(msg.GetPresentableContent() == 'Howdie USERNAME') -+ -+ trans = tclib.Translation(text=text, placeholders=phs) -+ self.failUnless(trans.GetPresentableContent() == 'Howdie USERNAME') -+ self.failUnless(isinstance(trans.GetPresentableContent(), six.string_types)) -+ -+ def testUnicodeReturn(self): -+ text = u'\u00fe' -+ msg = tclib.Message(text=text) -+ self.failUnless(msg.GetPresentableContent() == text) -+ from_list = msg.GetContent()[0] -+ self.failUnless(from_list == text) -+ -+ def testRegressionTranslationInherited(self): -+ '''Regression tests a bug that was caused by grit.tclib.Translation -+ inheriting from the translation console's Translation object -+ instead of only owning an instance of it. -+ ''' -+ msg = tclib.Message(text=u"BLA1\r\nFrom: BLA2 \u00fe BLA3", -+ placeholders=[ -+ tclib.Placeholder('BLA1', '%s', '%s'), -+ tclib.Placeholder('BLA2', '%s', '%s'), -+ tclib.Placeholder('BLA3', '%s', '%s')]) -+ transl = tclib.Translation(text=msg.GetPresentableContent(), -+ placeholders=msg.GetPlaceholders()) -+ content = transl.GetContent() -+ self.failUnless(isinstance(content[3], six.string_types)) -+ -+ def testFingerprint(self): -+ # This has Windows line endings. That is on purpose. -+ id = grit.extern.tclib.GenerateMessageId( -+ 'Google Desktop for Enterprise\r\n' -+ 'All Rights Reserved\r\n' -+ '\r\n' -+ '---------\r\n' -+ 'Contents\r\n' -+ '---------\r\n' -+ 'This distribution contains the following files:\r\n' -+ '\r\n' -+ 'GoogleDesktopSetup.msi - Installation and setup program\r\n' -+ 'GoogleDesktop.adm - Group Policy administrative template file\r\n' -+ 'AdminGuide.pdf - Google Desktop for Enterprise administrative guide\r\n' -+ '\r\n' -+ '\r\n' -+ '--------------\r\n' -+ 'Documentation\r\n' -+ '--------------\r\n' -+ 'Full documentation and installation instructions are in the \r\n' -+ 'administrative guide, and also online at \r\n' -+ 'http://desktop.google.com/enterprise/adminguide.html.\r\n' -+ '\r\n' -+ '\r\n' -+ '------------------------\r\n' -+ 'IBM Lotus Notes Plug-In\r\n' -+ '------------------------\r\n' -+ 'The Lotus Notes plug-in is included in the release of Google \r\n' -+ 'Desktop for Enterprise. The IBM Lotus Notes Plug-in for Google \r\n' -+ 'Desktop indexes mail, calendar, task, contact and journal \r\n' -+ 'documents from Notes. Discussion documents including those from \r\n' -+ 'the discussion and team room templates can also be indexed by \r\n' -+ 'selecting an option from the preferences. Once indexed, this data\r\n' -+ 'will be returned in Google Desktop searches. The corresponding\r\n' -+ 'document can be opened in Lotus Notes from the Google Desktop \r\n' -+ 'results page.\r\n' -+ '\r\n' -+ 'Install: The plug-in will install automatically during the Google \r\n' -+ 'Desktop setup process if Lotus Notes is already installed. Lotus \r\n' -+ 'Notes must not be running in order for the install to occur. \r\n' -+ '\r\n' -+ 'Preferences: Preferences and selection of databases to index are\r\n' -+ 'set in the \'Google Desktop for Notes\' dialog reached through the \r\n' -+ '\'Actions\' menu.\r\n' -+ '\r\n' -+ 'Reindexing: Selecting \'Reindex all databases\' will index all the \r\n' -+ 'documents in each database again.\r\n' -+ '\r\n' -+ '\r\n' -+ 'Notes Plug-in Known Issues\r\n' -+ '---------------------------\r\n' -+ '\r\n' -+ 'If the \'Google Desktop for Notes\' item is not available from the \r\n' -+ 'Lotus Notes Actions menu, then installation was not successful. \r\n' -+ 'Installation consists of writing one file, notesgdsplugin.dll, to \r\n' -+ 'the Notes application directory and a setting to the notes.ini \r\n' -+ 'configuration file. The most likely cause of an unsuccessful \r\n' -+ 'installation is that the installer was not able to locate the \r\n' -+ 'notes.ini file. Installation will complete if the user closes Notes\r\n' -+ 'and manually adds the following setting to this file on a new line:\r\n' -+ 'AddinMenus=notegdsplugin.dll\r\n' -+ '\r\n' -+ 'If the notesgdsplugin.dll file is not in the application directory\r\n' -+ r'(e.g., C:\Program Files\Lotus\Notes) after Google Desktop \r\n' -+ 'installation, it is likely that Notes was not installed correctly. \r\n' -+ '\r\n' -+ 'Only local databases can be indexed. If they can be determined, \r\n' -+ 'the user\'s local mail file and address book will be included in the\r\n' -+ 'list automatically. Mail archives and other databases must be \r\n' -+ 'added with the \'Add\' button.\r\n' -+ '\r\n' -+ 'Some users may experience performance issues during the initial \r\n' -+ 'indexing of a database. The \'Perform the initial index of a \r\n' -+ 'database only when I\'m idle\' option will limit the indexing process\r\n' -+ 'to times when the user is not using the machine. If this does not \r\n' -+ 'alleviate the problem or the user would like to continually index \r\n' -+ 'but just do so more slowly or quickly, the GoogleWaitTime notes.ini\r\n' -+ 'value can be set. Increasing the GoogleWaitTime value will slow \r\n' -+ 'down the indexing process, and lowering the value will speed it up.\r\n' -+ 'A value of zero causes the fastest possible indexing. Removing the\r\n' -+ 'ini parameter altogether returns it to the default (20).\r\n' -+ '\r\n' -+ 'Crashes have been known to occur with certain types of history \r\n' -+ 'bookmarks. If the Notes client seems to crash randomly, try \r\n' -+ 'disabling the \'Index note history\' option. If it crashes before,\r\n' -+ 'you can get to the preferences, add the following line to your \r\n' -+ 'notes.ini file:\r\n' -+ 'GDSNoIndexHistory=1\r\n') -+ self.assertEqual(id, '7660964495923572726') -+ -+ def testPlaceholderNameChecking(self): -+ try: -+ ph = tclib.Placeholder('BINGO BONGO', 'bla', 'bla') -+ raise Exception("We shouldn't get here") -+ except exception.InvalidPlaceholderName: -+ pass # Expect exception to be thrown because presentation contained space -+ -+ def testTagsWithCommonSubstring(self): -+ word = 'ABCDEFGHIJ' -+ text = ' '.join([word[:i] for i in range(1, 11)]) -+ phs = [tclib.Placeholder(word[:i], str(i), str(i)) for i in range(1, 11)] -+ try: -+ msg = tclib.Message(text=text, placeholders=phs) -+ self.failUnless(msg.GetRealContent() == '1 2 3 4 5 6 7 8 9 10') -+ except: -+ self.fail('tclib.Message() should handle placeholders that are ' -+ 'substrings of each other') -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/test_suite_all.py b/tools/grit/grit/test_suite_all.py -new file mode 100644 -index 0000000000..3bfe2a79d5 ---- /dev/null -+++ b/tools/grit/grit/test_suite_all.py -@@ -0,0 +1,34 @@ -+#!/usr/bin/env python3 -+# Copyright (c) 2011 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit test suite that collects all test cases for GRIT.''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+ -+ -+CUR_DIR = os.path.dirname(os.path.realpath(__file__)) -+SRC_DIR = os.path.dirname(os.path.dirname(os.path.dirname(CUR_DIR))) -+TYP_DIR = os.path.join( -+ SRC_DIR, 'third_party', 'catapult', 'third_party', 'typ') -+ -+if TYP_DIR not in sys.path: -+ sys.path.insert(0, TYP_DIR) -+ -+ -+import typ # pylint: disable=import-error,unused-import -+ -+ -+def main(args): -+ return typ.main( -+ top_level_dirs=[os.path.join(CUR_DIR, '..')], -+ skip=['grit.format.gen_predetermined_ids_unittest.*', -+ 'grit.pseudo_unittest.*'] -+ ) -+ -+if __name__ == '__main__': -+ sys.exit(main(sys.argv[1:])) -diff --git a/tools/grit/grit/testdata/GoogleDesktop.adm b/tools/grit/grit/testdata/GoogleDesktop.adm -new file mode 100644 -index 0000000000..082f56bb1a ---- /dev/null -+++ b/tools/grit/grit/testdata/GoogleDesktop.adm -@@ -0,0 +1,945 @@ -+CLASS MACHINE -+ CATEGORY !!Cat_Google -+ CATEGORY !!Cat_GoogleDesktopSearch -+ KEYNAME "Software\Policies\Google\Google Desktop" -+ -+ CATEGORY !!Cat_Preferences -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences" -+ -+ CATEGORY !!Cat_IndexAndCaptureControl -+ POLICY !!Blacklist_Email -+ EXPLAIN !!Explain_Blacklist_Email -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ VALUENAME "1" -+ END POLICY -+ -+ POLICY !!Blacklist_Gmail -+ EXPLAIN !!Explain_Blacklist_Gmail -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-pop" -+ VALUENAME "gmail" -+ END POLICY -+ -+ POLICY !!Blacklist_WebHistory -+ EXPLAIN !!Explain_Blacklist_WebHistory -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ VALUENAME "2" -+ END POLICY -+ -+ POLICY !!Blacklist_Chat -+ EXPLAIN !!Explain_Blacklist_Chat -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "3" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Text -+ EXPLAIN !!Explain_Blacklist_Text -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "4" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Media -+ EXPLAIN !!Explain_Blacklist_Media -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "5" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Contact -+ EXPLAIN !!Explain_Blacklist_Contact -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "9" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Calendar -+ EXPLAIN !!Explain_Blacklist_Calendar -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "10" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Task -+ EXPLAIN !!Explain_Blacklist_Task -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "11" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Note -+ EXPLAIN !!Explain_Blacklist_Note -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "12" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Journal -+ EXPLAIN !!Explain_Blacklist_Journal -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "13" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Word -+ EXPLAIN !!Explain_Blacklist_Word -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "DOC" -+ END POLICY -+ -+ POLICY !!Blacklist_Excel -+ EXPLAIN !!Explain_Blacklist_Excel -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "XLS" -+ END POLICY -+ -+ POLICY !!Blacklist_Powerpoint -+ EXPLAIN !!Explain_Blacklist_Powerpoint -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "PPT" -+ END POLICY -+ -+ POLICY !!Blacklist_PDF -+ EXPLAIN !!Explain_Blacklist_PDF -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "PDF" -+ END POLICY -+ -+ POLICY !!Blacklist_ZIP -+ EXPLAIN !!Explain_Blacklist_ZIP -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "ZIP" -+ END POLICY -+ -+ POLICY !!Blacklist_HTTPS -+ EXPLAIN !!Explain_Blacklist_HTTPS -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-3" -+ VALUENAME "HTTPS" -+ END POLICY -+ -+ POLICY !!Blacklist_PasswordProtectedOffice -+ EXPLAIN !!Explain_Blacklist_PasswordProtectedOffice -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-13" -+ VALUENAME "SECUREOFFICE" -+ END POLICY -+ -+ POLICY !!Blacklist_URI_Contains -+ EXPLAIN !!Explain_Blacklist_URI_Contains -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-6" -+ PART !!Blacklist_URI_Contains LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Blacklist_Extensions -+ EXPLAIN !!Explain_Blacklist_Extensions -+ PART !!Blacklist_Extensions EDITTEXT -+ VALUENAME "file_extensions_to_skip" -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Disallow_UserSearchLocations -+ EXPLAIN !!Explain_Disallow_UserSearchLocations -+ VALUENAME user_search_locations -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Search_Location_Whitelist -+ EXPLAIN !!Explain_Search_Location_Whitelist -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\policy_search_location_whitelist" -+ PART !!Search_Locations_Whitelist LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Email_Retention -+ EXPLAIN !!Explain_Email_Retention -+ PART !!Email_Retention_Edit NUMERIC -+ VALUENAME "email_days_to_retain" -+ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!Webpage_Retention -+ EXPLAIN !!Explain_Webpage_Retention -+ PART !!Webpage_Retention_Edit NUMERIC -+ VALUENAME "webpage_days_to_retain" -+ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!File_Retention -+ EXPLAIN !!Explain_File_Retention -+ PART !!File_Retention_Edit NUMERIC -+ VALUENAME "file_days_to_retain" -+ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!IM_Retention -+ EXPLAIN !!Explain_IM_Retention -+ PART !!IM_Retention_Edit NUMERIC -+ VALUENAME "im_days_to_retain" -+ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Remove_Deleted_Items -+ EXPLAIN !!Explain_Remove_Deleted_Items -+ VALUENAME remove_deleted_items -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Allow_Simultaneous_Indexing -+ EXPLAIN !!Explain_Allow_Simultaneous_Indexing -+ VALUENAME simultaneous_indexing -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ END CATEGORY -+ -+ POLICY !!Pol_TurnOffAdvancedFeatures -+ EXPLAIN !!Explain_TurnOffAdvancedFeatures -+ VALUENAME error_report_on -+ VALUEON NUMERIC 0 -+ END POLICY -+ -+ POLICY !!Pol_TurnOffImproveGd -+ EXPLAIN !!Explain_TurnOffImproveGd -+ VALUENAME improve_gd -+ VALUEON NUMERIC 0 -+ VALUEOFF NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_NoPersonalizationInfo -+ EXPLAIN !!Explain_NoPersonalizationInfo -+ VALUENAME send_personalization_info -+ VALUEON NUMERIC 0 -+ VALUEOFF NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_OneBoxMode -+ EXPLAIN !!Explain_OneBoxMode -+ VALUENAME onebox_mode -+ VALUEON NUMERIC 0 -+ END POLICY -+ -+ POLICY !!Pol_EncryptIndex -+ EXPLAIN !!Explain_EncryptIndex -+ VALUENAME encrypt_index -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Hyper -+ EXPLAIN !!Explain_Hyper -+ VALUENAME hyper_off -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Display_Mode -+ EXPLAIN !!Explain_Display_Mode -+ PART !!Pol_Display_Mode DROPDOWNLIST -+ VALUENAME display_mode -+ ITEMLIST -+ NAME !!Sidebar VALUE NUMERIC 1 -+ NAME !!Deskbar VALUE NUMERIC 8 -+ NAME !!FloatingDeskbar VALUE NUMERIC 4 -+ NAME !!None VALUE NUMERIC 0 -+ END ITEMLIST -+ END PART -+ END POLICY -+ -+ END CATEGORY ; Preferences -+ -+ CATEGORY !!Cat_Enterprise -+ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise" -+ -+ POLICY !!Pol_Autoupdate -+ EXPLAIN !!Explain_Autoupdate -+ VALUENAME autoupdate_host -+ VALUEON "" -+ END POLICY -+ -+ POLICY !!Pol_AutoupdateAsSystem -+ EXPLAIN !!Explain_AutoupdateAsSystem -+ VALUENAME autoupdate_impersonate_user -+ VALUEON NUMERIC 0 -+ VALUEOFF NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_EnterpriseTab -+ EXPLAIN !!Explain_EnterpriseTab -+ PART !!EnterpriseTabText EDITTEXT -+ VALUENAME enterprise_tab_text -+ END PART -+ PART !!EnterpriseTabHomepage EDITTEXT -+ VALUENAME enterprise_tab_homepage -+ END PART -+ PART !!EnterpriseTabHomepageQuery CHECKBOX -+ VALUENAME enterprise_tab_homepage_query -+ END PART -+ PART !!EnterpriseTabResults EDITTEXT -+ VALUENAME enterprise_tab_results -+ END PART -+ PART !!EnterpriseTabResultsQuery CHECKBOX -+ VALUENAME enterprise_tab_results_query -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_GSAHosts -+ EXPLAIN !!Explain_GSAHosts -+ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\GSAHosts" -+ PART !!Pol_GSAHosts LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_PolicyUnawareClientProhibitedFlag -+ EXPLAIN !!Explain_PolicyUnawareClientProhibitedFlag -+ KEYNAME "Software\Policies\Google\Google Desktop" -+ VALUENAME PolicyUnawareClientProhibitedFlag -+ END POLICY -+ -+ POLICY !!Pol_MinimumAllowedVersion -+ EXPLAIN !!Explain_MinimumAllowedVersion -+ PART !!Pol_MinimumAllowedVersion EDITTEXT -+ VALUENAME minimum_allowed_version -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_MaximumAllowedVersion -+ EXPLAIN !!Explain_MaximumAllowedVersion -+ PART !!Pol_MaximumAllowedVersion EDITTEXT -+ VALUENAME maximum_allowed_version -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Disallow_Gadgets -+ EXPLAIN !!Explain_Disallow_Gadgets -+ VALUENAME disallow_gadgets -+ VALUEON NUMERIC 1 -+ PART !!Disallow_Only_Non_Builtin_Gadgets CHECKBOX DEFCHECKED -+ VALUENAME disallow_only_non_builtin_gadgets -+ VALUEON NUMERIC 1 -+ VALUEOFF NUMERIC 0 -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Gadget_Whitelist -+ EXPLAIN !!Explain_Gadget_Whitelist -+ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\gadget_whitelist" -+ PART !!Pol_Gadget_Whitelist LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Gadget_Install_Confirmation_Whitelist -+ EXPLAIN !!Explain_Gadget_Install_Confirmation_Whitelist -+ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\install_confirmation_whitelist" -+ PART !!Pol_Gadget_Install_Confirmation_Whitelist LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Alternate_User_Data_Dir -+ EXPLAIN !!Explain_Alternate_User_Data_Dir -+ PART !!Pol_Alternate_User_Data_Dir EDITTEXT -+ VALUENAME alternate_user_data_dir -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_MaxAllowedOutlookConnections -+ EXPLAIN !!Explain_MaxAllowedOutlookConnections -+ PART !!Pol_MaxAllowedOutlookConnections NUMERIC -+ VALUENAME max_allowed_outlook_connections -+ MIN 1 MAX 65535 DEFAULT 400 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_DisallowSsdService -+ EXPLAIN !!Explain_DisallowSsdService -+ VALUENAME disallow_ssd_service -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_DisallowSsdOutbound -+ EXPLAIN !!Explain_DisallowSsdOutbound -+ VALUENAME disallow_ssd_outbound -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Disallow_Store_Gadget_Service -+ EXPLAIN !!Explain_Disallow_Store_Gadget_Service -+ VALUENAME disallow_store_gadget_service -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_MaxExchangeIndexingRate -+ EXPLAIN !!Explain_MaxExchangeIndexingRate -+ PART !!Pol_MaxExchangeIndexingRate NUMERIC -+ VALUENAME max_exchange_indexing_rate -+ MIN 1 MAX 1000 DEFAULT 60 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_EnableSafeweb -+ EXPLAIN !!Explain_Safeweb -+ VALUENAME safe_browsing -+ VALUEON NUMERIC 1 -+ VALUEOFF NUMERIC 0 -+ END POLICY -+ -+ END CATEGORY ; Enterprise -+ -+ END CATEGORY ; GoogleDesktopSearch -+ END CATEGORY ; Google -+ -+ -+CLASS USER -+ CATEGORY !!Cat_Google -+ CATEGORY !!Cat_GoogleDesktopSearch -+ KEYNAME "Software\Policies\Google\Google Desktop" -+ -+ CATEGORY !!Cat_Preferences -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences" -+ -+ CATEGORY !!Cat_IndexAndCaptureControl -+ POLICY !!Blacklist_Email -+ EXPLAIN !!Explain_Blacklist_Email -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ VALUENAME "1" -+ END POLICY -+ -+ POLICY !!Blacklist_Gmail -+ EXPLAIN !!Explain_Blacklist_Gmail -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-pop" -+ VALUENAME "gmail" -+ END POLICY -+ -+ POLICY !!Blacklist_WebHistory -+ EXPLAIN !!Explain_Blacklist_WebHistory -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ VALUENAME "2" -+ END POLICY -+ -+ POLICY !!Blacklist_Chat -+ EXPLAIN !!Explain_Blacklist_Chat -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "3" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Text -+ EXPLAIN !!Explain_Blacklist_Text -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "4" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Media -+ EXPLAIN !!Explain_Blacklist_Media -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "5" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Contact -+ EXPLAIN !!Explain_Blacklist_Contact -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "9" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Calendar -+ EXPLAIN !!Explain_Blacklist_Calendar -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "10" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Task -+ EXPLAIN !!Explain_Blacklist_Task -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "11" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Note -+ EXPLAIN !!Explain_Blacklist_Note -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "12" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Journal -+ EXPLAIN !!Explain_Blacklist_Journal -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-1" -+ ACTIONLISTON -+ VALUENAME "13" VALUE NUMERIC 1 -+ END ACTIONLISTON -+ END POLICY -+ -+ POLICY !!Blacklist_Word -+ EXPLAIN !!Explain_Blacklist_Word -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "DOC" -+ END POLICY -+ -+ POLICY !!Blacklist_Excel -+ EXPLAIN !!Explain_Blacklist_Excel -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "XLS" -+ END POLICY -+ -+ POLICY !!Blacklist_Powerpoint -+ EXPLAIN !!Explain_Blacklist_Powerpoint -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "PPT" -+ END POLICY -+ -+ POLICY !!Blacklist_PDF -+ EXPLAIN !!Explain_Blacklist_PDF -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "PDF" -+ END POLICY -+ -+ POLICY !!Blacklist_ZIP -+ EXPLAIN !!Explain_Blacklist_ZIP -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-2" -+ VALUENAME "ZIP" -+ END POLICY -+ -+ POLICY !!Blacklist_HTTPS -+ EXPLAIN !!Explain_Blacklist_HTTPS -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-3" -+ VALUENAME "HTTPS" -+ END POLICY -+ -+ POLICY !!Blacklist_PasswordProtectedOffice -+ EXPLAIN !!Explain_Blacklist_PasswordProtectedOffice -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-13" -+ VALUENAME "SECUREOFFICE" -+ END POLICY -+ -+ POLICY !!Blacklist_URI_Contains -+ EXPLAIN !!Explain_Blacklist_URI_Contains -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\blacklist-6" -+ PART !!Blacklist_URI_Contains LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Blacklist_Extensions -+ EXPLAIN !!Explain_Blacklist_Extensions -+ PART !!Blacklist_Extensions EDITTEXT -+ VALUENAME "file_extensions_to_skip" -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Disallow_UserSearchLocations -+ EXPLAIN !!Explain_Disallow_UserSearchLocations -+ VALUENAME user_search_locations -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Search_Location_Whitelist -+ EXPLAIN !!Explain_Search_Location_Whitelist -+ KEYNAME "Software\Policies\Google\Google Desktop\Preferences\policy_search_location_whitelist" -+ PART !!Search_Locations_Whitelist LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Email_Retention -+ EXPLAIN !!Explain_Email_Retention -+ PART !!Email_Retention_Edit NUMERIC -+ VALUENAME "email_days_to_retain" -+ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!Webpage_Retention -+ EXPLAIN !!Explain_Webpage_Retention -+ PART !!Webpage_Retention_Edit NUMERIC -+ VALUENAME "webpage_days_to_retain" -+ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!File_Retention -+ EXPLAIN !!Explain_File_Retention -+ PART !!File_Retention_Edit NUMERIC -+ VALUENAME "file_days_to_retain" -+ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!IM_Retention -+ EXPLAIN !!Explain_IM_Retention -+ PART !!IM_Retention_Edit NUMERIC -+ VALUENAME "im_days_to_retain" -+ MIN 1 MAX 65535 DEFAULT 30 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Remove_Deleted_Items -+ EXPLAIN !!Explain_Remove_Deleted_Items -+ VALUENAME remove_deleted_items -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Allow_Simultaneous_Indexing -+ EXPLAIN !!Explain_Allow_Simultaneous_Indexing -+ VALUENAME simultaneous_indexing -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ END CATEGORY -+ -+ POLICY !!Pol_TurnOffAdvancedFeatures -+ EXPLAIN !!Explain_TurnOffAdvancedFeatures -+ VALUENAME error_report_on -+ VALUEON NUMERIC 0 -+ END POLICY -+ -+ POLICY !!Pol_TurnOffImproveGd -+ EXPLAIN !!Explain_TurnOffImproveGd -+ VALUENAME improve_gd -+ VALUEON NUMERIC 0 -+ VALUEOFF NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_NoPersonalizationInfo -+ EXPLAIN !!Explain_NoPersonalizationInfo -+ VALUENAME send_personalization_info -+ VALUEON NUMERIC 0 -+ VALUEOFF NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_OneBoxMode -+ EXPLAIN !!Explain_OneBoxMode -+ VALUENAME onebox_mode -+ VALUEON NUMERIC 0 -+ END POLICY -+ -+ POLICY !!Pol_EncryptIndex -+ EXPLAIN !!Explain_EncryptIndex -+ VALUENAME encrypt_index -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Hyper -+ EXPLAIN !!Explain_Hyper -+ VALUENAME hyper_off -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Display_Mode -+ EXPLAIN !!Explain_Display_Mode -+ PART !!Pol_Display_Mode DROPDOWNLIST -+ VALUENAME display_mode -+ ITEMLIST -+ NAME !!Sidebar VALUE NUMERIC 1 -+ NAME !!Deskbar VALUE NUMERIC 8 -+ NAME !!FloatingDeskbar VALUE NUMERIC 4 -+ NAME !!None VALUE NUMERIC 0 -+ END ITEMLIST -+ END PART -+ END POLICY -+ -+ END CATEGORY ; Preferences -+ -+ CATEGORY !!Cat_Enterprise -+ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise" -+ -+ POLICY !!Pol_Autoupdate -+ EXPLAIN !!Explain_Autoupdate -+ VALUENAME autoupdate_host -+ VALUEON "" -+ END POLICY -+ -+ POLICY !!Pol_AutoupdateAsSystem -+ EXPLAIN !!Explain_AutoupdateAsSystem -+ VALUENAME autoupdate_impersonate_user -+ VALUEON NUMERIC 0 -+ VALUEOFF NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_EnterpriseTab -+ EXPLAIN !!Explain_EnterpriseTab -+ PART !!EnterpriseTabText EDITTEXT -+ VALUENAME enterprise_tab_text -+ END PART -+ PART !!EnterpriseTabHomepage EDITTEXT -+ VALUENAME enterprise_tab_homepage -+ END PART -+ PART !!EnterpriseTabHomepageQuery CHECKBOX -+ VALUENAME enterprise_tab_homepage_query -+ END PART -+ PART !!EnterpriseTabResults EDITTEXT -+ VALUENAME enterprise_tab_results -+ END PART -+ PART !!EnterpriseTabResultsQuery CHECKBOX -+ VALUENAME enterprise_tab_results_query -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_GSAHosts -+ EXPLAIN !!Explain_GSAHosts -+ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\GSAHosts" -+ PART !!Pol_GSAHosts LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Disallow_Gadgets -+ EXPLAIN !!Explain_Disallow_Gadgets -+ VALUENAME disallow_gadgets -+ VALUEON NUMERIC 1 -+ PART !!Disallow_Only_Non_Builtin_Gadgets CHECKBOX DEFCHECKED -+ VALUENAME disallow_only_non_builtin_gadgets -+ VALUEON NUMERIC 1 -+ VALUEOFF NUMERIC 0 -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Gadget_Whitelist -+ EXPLAIN !!Explain_Gadget_Whitelist -+ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\gadget_whitelist" -+ PART !!Pol_Gadget_Whitelist LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Gadget_Install_Confirmation_Whitelist -+ EXPLAIN !!Explain_Gadget_Install_Confirmation_Whitelist -+ KEYNAME "Software\Policies\Google\Google Desktop\Enterprise\install_confirmation_whitelist" -+ PART !!Pol_Gadget_Install_Confirmation_Whitelist LISTBOX -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_Alternate_User_Data_Dir -+ EXPLAIN !!Explain_Alternate_User_Data_Dir -+ PART !!Pol_Alternate_User_Data_Dir EDITTEXT -+ VALUENAME alternate_user_data_dir -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_MaxAllowedOutlookConnections -+ EXPLAIN !!Explain_MaxAllowedOutlookConnections -+ PART !!Pol_MaxAllowedOutlookConnections NUMERIC -+ VALUENAME max_allowed_outlook_connections -+ MIN 1 MAX 65535 DEFAULT 400 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_DisallowSsdService -+ EXPLAIN !!Explain_DisallowSsdService -+ VALUENAME disallow_ssd_service -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_DisallowSsdOutbound -+ EXPLAIN !!Explain_DisallowSsdOutbound -+ VALUENAME disallow_ssd_outbound -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_Disallow_Store_Gadget_Service -+ EXPLAIN !!Explain_Disallow_Store_Gadget_Service -+ VALUENAME disallow_store_gadget_service -+ VALUEON NUMERIC 1 -+ END POLICY -+ -+ POLICY !!Pol_MaxExchangeIndexingRate -+ EXPLAIN !!Explain_MaxExchangeIndexingRate -+ PART !!Pol_MaxExchangeIndexingRate NUMERIC -+ VALUENAME max_exchange_indexing_rate -+ MIN 1 MAX 1000 DEFAULT 60 SPIN 1 -+ END PART -+ END POLICY -+ -+ POLICY !!Pol_EnableSafeweb -+ EXPLAIN !!Explain_Safeweb -+ VALUENAME safe_browsing -+ VALUEON NUMERIC 1 -+ VALUEOFF NUMERIC 0 -+ END POLICY -+ -+ END CATEGORY ; Enterprise -+ -+ END CATEGORY ; GoogleDesktopSearch -+ END CATEGORY ; Google -+ -+;------------------------------------------------------------------------------ -+ -+[strings] -+Cat_Google="Google" -+Cat_GoogleDesktopSearch="Google Desktop" -+ -+;------------------------------------------------------------------------------ -+; Preferences -+;------------------------------------------------------------------------------ -+Cat_Preferences="Preferences" -+Explain_Preferences="Controls Google Desktop preferences" -+ -+Cat_IndexAndCaptureControl="Indexing and Capture Control" -+Explain_IndexAndCaptureControl="Controls what files, web pages, and other content will be indexed by Google Desktop." -+ -+Blacklist_Email="Prevent indexing of email" -+Explain_Blacklist_Email="Enabling this policy will prevent Google Desktop from indexing emails.\n\nIf this policy is not configured, the user can choose whether or not to index emails." -+Blacklist_Gmail="Prevent indexing of Gmail" -+Explain_Blacklist_Gmail="Enabling this policy prevents Google Desktop from indexing Gmail messages.\n\nThis policy is in effect only when the policy "Prevent indexing of email" is disabled. When that policy is enabled, all email indexing is disabled, including Gmail indexing.\n\nIf both this policy and "Prevent indexing of email" are disabled or not configured, a user can choose whether or not to index Gmail messages." -+Blacklist_WebHistory="Prevent indexing of web pages" -+Explain_Blacklist_WebHistory="Enabling this policy will prevent Google Desktop from indexing web pages.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index web pages." -+Blacklist_Text="Prevent indexing of text files" -+Explain_Blacklist_Text="Enabling this policy will prevent Google Desktop from indexing text files.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index text files." -+Blacklist_Media="Prevent indexing of media files" -+Explain_Blacklist_Media="Enabling this policy will prevent Google Desktop from indexing media files.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index media files." -+Blacklist_Contact="Prevent indexing of contacts" -+Explain_Blacklist_Contact="Enabling this policy will prevent Google Desktop from indexing contacts.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index contacts." -+Blacklist_Calendar="Prevent indexing of calendar entries" -+Explain_Blacklist_Calendar="Enabling this policy will prevent Google Desktop from indexing calendar entries.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index calendar entries." -+Blacklist_Task="Prevent indexing of tasks" -+Explain_Blacklist_Task="Enabling this policy will prevent Google Desktop from indexing tasks.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index tasks." -+Blacklist_Note="Prevent indexing of notes" -+Explain_Blacklist_Note="Enabling this policy will prevent Google Desktop from indexing notes.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index notes." -+Blacklist_Journal="Prevent indexing of journal entries" -+Explain_Blacklist_Journal="Enabling this policy will prevent Google Desktop from indexing journal entries.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index journal entries." -+Blacklist_Word="Prevent indexing of Word documents" -+Explain_Blacklist_Word="Enabling this policy will prevent Google Desktop from indexing Word documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index Word documents." -+Blacklist_Excel="Prevent indexing of Excel documents" -+Explain_Blacklist_Excel="Enabling this policy will prevent Google Desktop from indexing Excel documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index Excel documents." -+Blacklist_Powerpoint="Prevent indexing of PowerPoint documents" -+Explain_Blacklist_Powerpoint="Enabling this policy will prevent Google Desktop from indexing PowerPoint documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index PowerPoint documents." -+Blacklist_PDF="Prevent indexing of PDF documents" -+Explain_Blacklist_PDF="Enabling this policy will prevent Google Desktop from indexing PDF documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index PDF documents." -+Blacklist_ZIP="Prevent indexing of ZIP files" -+Explain_Blacklist_ZIP="Enabling this policy will prevent Google Desktop from indexing ZIP files.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index ZIP files." -+Blacklist_HTTPS="Prevent indexing of secure web pages" -+Explain_Blacklist_HTTPS="Enabling this policy will prevent Google Desktop from indexing secure web pages (pages with HTTPS in the URL).\n\nIf this policy is disabled or not configured, the user can choose whether or not to index secure web pages." -+Blacklist_URI_Contains="Prevent indexing of specific web sites and folders" -+Explain_Blacklist_URI_Contains="This policy allows you to prevent Google Desktop from indexing specific websites or folders. If an item's URL or path name contains any of these specified strings, it will not be indexed. These restrictions will be applied in addition to any websites or folders that the user has specified.\n\nThis policy has no effect when disabled or not configured." -+Blacklist_Chat="Prevent indexing of IM chats" -+Explain_Blacklist_Chat="Enabling this policy will prevent Google Desktop from indexing IM chat conversations.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index IM chat conversations." -+Blacklist_PasswordProtectedOffice="Prevent indexing of password-protected Office documents (Word, Excel)" -+Explain_Blacklist_PasswordProtectedOffice="Enabling this policy will prevent Google Desktop from indexing password-protected office documents.\n\nIf this policy is disabled or not configured, the user can choose whether or not to index password-protected office documents." -+Blacklist_Extensions="Prevent indexing of specific file extensions" -+Explain_Blacklist_Extensions="This policy allows you to prevent Google Desktop from indexing files with specific extensions. Enter a list of file extensions, separated by commas, that you wish to exclude from indexing.\n\nThis policy has no effect when disabled or not configured." -+Pol_Disallow_UserSearchLocations="Disallow adding search locations for indexing" -+Explain_Disallow_UserSearchLocations="Enabling this policy will prevent the user from specifying additional drives or networked folders to be indexed by Google Desktop.\n\nIf this policy is disabled or not configured, users may specify additional drives and networked folders to be indexed." -+Pol_Search_Location_Whitelist="Allow indexing of specific folders" -+Explain_Search_Location_Whitelist="This policy allows you to add additional drives and networked folders to index." -+Search_Locations_Whitelist="Search these locations" -+Email_Retention="Only retain emails that are less than x days old" -+Explain_Email_Retention="This policy allows you to configure Google Desktop to only retain emails that are less than the specified number of days old in the index. Enter the number of days to retain emails for\n\nThis policy has no effect when disabled or not configured." -+Email_Retention_Edit="Number of days to retain emails" -+Webpage_Retention="Only retain webpages that are less than x days old" -+Explain_Webpage_Retention="This policy allows you to configure Google Desktop to only retain webpages that are less than the specified number of days old in the index. Enter the number of days to retain webpages for\n\nThis policy has no effect when disabled or not configured." -+Webpage_Retention_Edit="Number of days to retain webpages" -+File_Retention="Only retain files that are less than x days old" -+Explain_File_Retention="This policy allows you to configure Google Desktop to only retain files that are less than the specified number of days old in the index. Enter the number of days to retain files for\n\nThis policy has no effect when disabled or not configured." -+File_Retention_Edit="Number of days to retain files" -+IM_Retention="Only retain IM that are less than x days old" -+Explain_IM_Retention="This policy allows you to configure Google Desktop to only retain IM that are less than the specified number of days old in the index. Enter the number of days to retain IM for\n\nThis policy has no effect when disabled or not configured." -+IM_Retention_Edit="Number of days to retain IM" -+ -+Pol_Remove_Deleted_Items="Remove deleted items from the index." -+Explain_Remove_Deleted_Items="Enabling this policy will remove all deleted items from the index and cache. Any items that are deleted will no longer be searchable." -+ -+Pol_Allow_Simultaneous_Indexing="Allow historical indexing for multiple users simultaneously." -+Explain_Allow_Simultaneous_Indexing="Enabling this policy will allow a computer to generate first-time indexes for multiple users simultaneously. \n\nIf this policy is disabled or not configured, historical indexing will happen only for the logged-in user that was connected last; historical indexing for any other logged-in user will happen the next time that other user connects." -+ -+Pol_TurnOffAdvancedFeatures="Turn off Advanced Features options" -+Explain_TurnOffAdvancedFeatures="Enabling this policy will prevent Google Desktop from sending Advanced Features data to Google (for either improvements or personalization), and users won't be able to change these options. Enabling this policy also prevents older versions of Google Desktop from sending data.\n\nIf this policy is disabled or not configured and the user has a pre-5.5 version of Google Desktop, the user can choose whether or not to enable sending data to Google. If the user has version 5.5 or later, the 'Turn off Improve Google Desktop option' and 'Do not send personalization info' policies will be used instead." -+ -+Pol_TurnOffImproveGd="Turn off Improve Google Desktop option" -+Explain_TurnOffImproveGd="Enabling this policy will prevent Google Desktop from sending improvement data, including crash reports and anonymous usage data, to Google.\n\nIf this policy is disabled, improvement data will be sent to Google and the user won't be able to change the option.\n\nIf this policy is not configured, the user can choose whether or not to enable the Improve Google Desktop option.\n\nNote that this policy applies only to version 5.5 or later and doesn't affect previous versions of Google Desktop.\n\nAlso note that this policy can be overridden by the 'Turn off Advanced Features options' policy." -+ -+Pol_NoPersonalizationInfo="Do not send personalization info" -+Explain_NoPersonalizationInfo="Enabling this policy will prevent Google Desktop from displaying personalized content, such as news that reflects the user's past interest in articles. Personalized content is derived from anonymous usage data sent to Google.\n\nIf this policy is disabled, personalized content will be displayed for all users, and users won't be able to disable this feature.\n\nIf this policy is not configured, users can choose whether or not to enable personalization in each gadget that supports this feature.\n\nNote that this policy applies only to version 5.5 or later and doesn't affect previous versions of Google Desktop.\n\nAlso note that this policy can be overridden by the 'Turn off Advanced Features options' policy." -+ -+Pol_OneBoxMode="Turn off Google Web Search Integration" -+Explain_OneBoxMode="Enabling this policy will prevent Google Desktop from displaying Desktop Search results in queries to google.com.\n\nIf this policy is disabled or not configured, the user can choose whether or not to include Desktop Search results in queries to google.com." -+ -+Pol_EncryptIndex="Encrypt index data" -+Explain_EncryptIndex="Enabling this policy will cause Google Desktop to turn on Windows file encryption for the folder containing the Google Desktop index and related user data the next time it is run.\n\nNote that Windows EFS is only available on NTFS volumes. If the user's data is stored on a FAT volume, this policy will have no effect.\n\nThis policy has no effect when disabled or not configured." -+ -+Pol_Hyper="Turn off Quick Find" -+Explain_Hyper="Enabling this policy will cause Google Desktop to turn off Quick Find feature. Quick Find allows you to see results as you type.\n\nIf this policy is disabled or not configured, the user can choose whether or not to enable it." -+ -+Pol_Display_Mode="Choose display option" -+Explain_Display_Mode="This policy sets the Google Desktop display option: Sidebar, Deskbar, Floating Deskbar or none.\n\nNote that on 64-bit systems, a setting of Deskbar will be interpreted as Floating Deskbar.\n\nIf this policy is disabled or not configured, the user can choose a display option." -+Sidebar="Sidebar" -+Deskbar="Deskbar" -+FloatingDeskbar="Floating Deskbar" -+None="None" -+ -+;------------------------------------------------------------------------------ -+; Enterprise -+;------------------------------------------------------------------------------ -+Cat_Enterprise="Enterprise Integration" -+Explain_Enterprise="Controls features specific to Enterprise installations of Google Desktop" -+ -+Pol_Autoupdate="Block Auto-update" -+Explain_Autoupdate="Enabling this policy prevents Google Desktop from automatically checking for and installing updates from google.com.\n\nIf you enable this policy, you must distribute updates to Google Desktop using Group Policy, SMS, or a similar enterprise software distribution mechanism. You should check http://desktop.google.com/enterprise/ for updates.\n\nIf this policy is disabled or not configured, Google Desktop will periodically check for updates from desktop.google.com." -+ -+Pol_AutoupdateAsSystem="Use system proxy settings when auto-updating" -+Explain_AutoupdateAsSystem="Enabling this policy makes Google Desktop use the machine-wide proxy settings (as specified using e.g. proxycfg.exe) when performing autoupdates (if enabled).\n\nIf this policy is disabled or not configured, Google Desktop will use the logged-on user's Internet Explorer proxy settings when checking for auto-updates (if enabled)." -+ -+Pol_EnterpriseTab="Enterprise search tab" -+Explain_EnterpriseTab="This policy allows you to add a search tab for your Google Search Appliance to Google Desktop and google.com web pages.\n\nYou must provide the name of the tab, such as "Intranet", as well as URLs for the search homepage and for retrieving search results. Use [DISP_QUERY] in place of the query term for the search results URL.\n\nSee the administrator's guide for more details." -+EnterpriseTabText="Tab name" -+EnterpriseTabHomepage="Search homepage URL" -+EnterpriseTabHomepageQuery="Check if search homepage supports '&&q='" -+EnterpriseTabResults="Search results URL" -+EnterpriseTabResultsQuery="Check if search results page supports '&&q='" -+ -+Pol_GSAHosts="Google Search Appliances" -+Explain_GSAHosts="This policy allows you to list any Google Search Appliances in your intranet. When properly configured, Google Desktop will insert Google Desktop results into the results of queries on the Google Search Appliance" -+ -+Pol_PolicyUnawareClientProhibitedFlag="Prohibit Policy-Unaware versions" -+Explain_PolicyUnawareClientProhibitedFlag="Prohibits installation and execution of versions of Google Desktop that are unaware of group policy.\n\nEnabling this policy will prevent users from installing or running version 1.0 of Google Desktop.\n\nThis policy has no effect when disabled or not configured." -+ -+Pol_MinimumAllowedVersion="Minimum allowed version" -+Explain_MinimumAllowedVersion="This policy allows you to prevent installation and/or execution of older versions of Google Desktop by specifying the minimum version you wish to allow. When enabling this policy, you should also enable the "Prohibit Policy-Unaware versions" policy to block versions of Google Desktop that did not support group policy.\n\nThis policy has no effect when disabled or not configured." -+ -+Pol_MaximumAllowedVersion="Maximum allowed version" -+Explain_MaximumAllowedVersion="This policy allows you to prevent installation and/or execution of newer versions of Google Desktop by specifying the maximum version you wish to allow.\n\nThis policy has no effect when disabled or not configured." -+ -+Pol_Disallow_Gadgets="Disallow gadgets and indexing plug-ins" -+Explain_Disallow_Gadgets="This policy prevents the use of all Google Desktop gadgets and indexing plug-ins. The policy applies to gadgets that are included in the Google Desktop installation package (built-in gadgets), built-in indexing plug-ins (currently only the Lotus Notes plug-in), and to gadgets or indexing plug-ins that a user might want to add later (non-built-in gadgets and indexing plug-ins).\n\nYou can prohibit use of all non-built-in gadgets and indexing plug-ins, but allow use of built-in gadgets and indexing plug-ins. To do so, enable this policy and then select the option "Disallow only non-built-in gadgets and indexing plug-ins.\n\nYou can supersede this policy to allow specified built-in and non-built-in gadgets and indexing plug-ins. To do so, enable this policy and then specify the gadgets and/or indexing plug-ins you want to allow under "Gadget and Plug-in Whitelist."" -+Disallow_Only_Non_Builtin_Gadgets="Disallow only non-built-in gadgets and indexing plug-ins" -+ -+Pol_Gadget_Whitelist="Gadget and plug-in whitelist" -+Explain_Gadget_Whitelist="This policy specifies a list of Google Desktop gadgets and indexing plug-ins that you want to allow, as exceptions to the "Disallow gadgets and indexing plug-ins" policy. This policy is valid only when the "Disallow gadgets and indexing plug-ins" policy is enabled.\n\nFor each gadget or indexing plug-in you wish to allow, add the CLSID or PROGID of the gadget or indexing plug-in (see the administrator's guide for more details).\n\nThis policy has no effect when disabled or not configured." -+ -+Pol_Gadget_Install_Confirmation_Whitelist="Allow silent installation of gadgets" -+Explain_Gadget_Install_Confirmation_Whitelist="Enabling this policy lets you specify a list of Google Desktop gadgets or indexing plug-ins that can be installed without confirmation from the user.\n\nAdd a gadget or indexing plug-in by placing its class ID (CLSID) or program identifier (PROGID) in the list, surrounded with curly braces ({ }).\n\nThis policy has no effect when disabled or not configured." -+ -+Pol_Alternate_User_Data_Dir="Alternate user data directory" -+Explain_Alternate_User_Data_Dir="This policy allows you to specify a directory to be used to store user data for Google Desktop (such as index data and cached documents).\n\nYou may use [USER_NAME] or [DOMAIN_NAME] in the path to specify the current user's name or domain. If [USER_NAME] is not specified, the user name will be appended at the end of the path.\n\nThis policy has no effect when disabled or not configured." -+ -+Pol_MaxAllowedOutlookConnections="Maximum allowed Outlook connections" -+Explain_MaxAllowedOutlookConnections="This policy specifies the maximum number of open connections that Google Desktop maintains with the Exchange server. Google Desktop opens a connection for each email folder that it indexes. If insufficient connections are allowed, Google Desktop cannot index all the user email folders.\n\nThe default value is 400. Because users rarely have as many as 400 email folders, Google Desktop rarely reaches the limit.\n\nIf you set this policy's value above 400, you must also configure the number of open connections between Outlook and the Exchange server. By default, approximately 400 connections are allowed. If Google Desktop uses too many of these connections, Outlook might be unable to access email.\n\nThis policy has no effect when disabled or not configured." -+ -+Pol_DisallowSsdService="Disallow sharing and receiving of web history and documents across computers" -+Explain_DisallowSsdService="Enabling this policy will prevent Google Desktop from sharing the user's web history and document contents across the user's different Google Desktop installations, and will also prevent it from receiving such shared items from the user's other machines. To allow reception but disallow sharing, use DisallowSsdOutbound.\nThis policy has no effect when disabled or not configured." -+ -+Pol_DisallowSsdOutbound="Disallow sharing of web history and documents to user's other computers." -+Explain_DisallowSsdOutbound="Enabling this policy will prevent Google Desktop from sending the user's web history and document contents from this machine to the user's other machines. It does not prevent reception of items from the user's other machines; to disallow both, use DisallowSsdService.\nThis policy has no effect when disabled or not configured." -+ -+Pol_Disallow_Store_Gadget_Service="Disallow storage of gadget content and settings." -+Explain_Disallow_Store_Gadget_Service="Enabling this policy will prevent users from storing their gadget content and settings with Google. Users will be unable to access their gadget content and settings from other computers and all content and settings will be lost if Google Desktop is uninstalled." -+ -+Pol_MaxExchangeIndexingRate="Maximum allowed Exchange indexing rate" -+Explain_MaxExchangeIndexingRate="This policy allows you to specify the maximum number of emails that are indexed per minute. \n\nThis policy has no effect when disabled or not configured." -+ -+Pol_EnableSafeweb="Enable or disable safe browsing" -+Explain_Safeweb="Google Desktop safe browsing informs the user whenever they visit any site which is a suspected forgery site or may harm their computer. Enabling this policy turns on safe browsing; disabling the policy turns it off. \n\nIf this policy is not configured, the user can select whether to turn on safe browsing." -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/README.txt b/tools/grit/grit/testdata/README.txt -new file mode 100644 -index 0000000000..a683b3b9e3 ---- /dev/null -+++ b/tools/grit/grit/testdata/README.txt -@@ -0,0 +1,87 @@ -+Google Desktop for Enterprise -+Copyright (C) 2007 Google Inc. -+All Rights Reserved -+ -+--------- -+Contents -+--------- -+This distribution contains the following files: -+ -+GoogleDesktopSetup.msi - Installation and setup program -+GoogleDesktop.adm - Group Policy administrative template file -+AdminGuide.pdf - Google Desktop for Enterprise administrative guide -+ -+ -+-------------- -+Documentation -+-------------- -+Full documentation and installation instructions are in the -+administrative guide, and also online at -+http://desktop.google.com/enterprise/adminguide.html. -+ -+ -+------------------------ -+IBM Lotus Notes Plug-In -+------------------------ -+The Lotus Notes plug-in is included in the release of Google -+Desktop for Enterprise. The IBM Lotus Notes Plug-in for Google -+Desktop indexes mail, calendar, task, contact and journal -+documents from Notes. Discussion documents including those from -+the discussion and team room templates can also be indexed by -+selecting an option from the preferences. Once indexed, this data -+will be returned in Google Desktop searches. The corresponding -+document can be opened in Lotus Notes from the Google Desktop -+results page. -+ -+Install: The plug-in will install automatically during the Google -+Desktop setup process if Lotus Notes is already installed. Lotus -+Notes must not be running in order for the install to occur. The -+Class ID for this plug-in is {8F42BDFB-33E8-427B-AFDC-A04E046D3F07}. -+ -+Preferences: Preferences and selection of databases to index are -+set in the 'Google Desktop for Notes' dialog reached through the -+'Actions' menu. -+ -+Reindexing: Selecting 'Reindex all databases' will index all the -+documents in each database again. -+ -+ -+Notes Plug-in Known Issues -+--------------------------- -+ -+If the 'Google Desktop for Notes' item is not available from the -+Lotus Notes Actions menu, then installation was not successful. -+Installation consists of writing one file, notesgdsplugin.dll, to -+the Notes application directory and a setting to the notes.ini -+configuration file. The most likely cause of an unsuccessful -+installation is that the installer was not able to locate the -+notes.ini file. Installation will complete if the user closes Notes -+and manually adds the following setting to this file on a new line: -+AddinMenus=notesgdsplugin.dll -+ -+If the notesgdsplugin.dll file is not in the application directory -+(e.g., C:\Program Files\Lotus\Notes) after Google Desktop -+installation, it is likely that Notes was not installed correctly. -+ -+Only local databases can be indexed. If they can be determined, -+the user's local mail file and address book will be included in the -+list automatically. Mail archives and other databases must be -+added with the 'Add' button. -+ -+Some users may experience performance issues during the initial -+indexing of a database. The 'Perform the initial index of a -+database only when I'm idle' option will limit the indexing process -+to times when the user is not using the machine. If this does not -+alleviate the problem or the user would like to continually index -+but just do so more slowly or quickly, the GoogleWaitTime notes.ini -+value can be set. Increasing the GoogleWaitTime value will slow -+down the indexing process, and lowering the value will speed it up. -+A value of zero causes the fastest possible indexing. Removing the -+ini parameter altogether returns it to the default (20). -+ -+Crashes have been known to occur with certain types of history -+bookmarks. If the Notes client seems to crash randomly, try -+disabling the 'Index note history' option. If it crashes before, -+you can get to the preferences, add the following line to your -+notes.ini file: -+GDSNoIndexHistory=1 -diff --git a/tools/grit/grit/testdata/about.html b/tools/grit/grit/testdata/about.html -new file mode 100644 -index 0000000000..8e5fad7b2b ---- /dev/null -+++ b/tools/grit/grit/testdata/about.html -@@ -0,0 +1,45 @@ -+[HEADER] -+
    -+
     [TITLE]
    -+
    Google Desktop Search: Search your own computer.

    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
      Outlook Email   Netscape Mail / Thunderbird
      Outlook Express   Netscape / Firefox / Mozilla
      Word   PDF
      Excel   Music
      PowerPoint   Images
      Internet Explorer   Video
      AOL Instant Messenger   Even more with these plug-ins
      Text and others
    -+
    -+

    -+ -+ -+ -+ -+ -+
    Getting Started - Learn more about using Google Desktop Search
    Online Help - Up-to-date answers to your questions
    Privacy - A few words about privacy and Google Desktop Search
    Uninstall - How to uninstall Google Desktop Search
    Submit Feedback - Send us your comments and ideas

    Google Desktop Search [$~BUILDNUMBER~$]

    -+[FOOTER] -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/android.xml b/tools/grit/grit/testdata/android.xml -new file mode 100644 -index 0000000000..cc3b141f70 ---- /dev/null -+++ b/tools/grit/grit/testdata/android.xml -@@ -0,0 +1,24 @@ -+ -+ -+ -+ -+ -+ Open %s? -+ -+ -+ -+ A simple string. -+ -+ -+ Contains a comment. -+ -+ -+ Another simple string. -+ -+ -+ Do not translate me. -+ -diff --git a/tools/grit/grit/testdata/bad_browser.html b/tools/grit/grit/testdata/bad_browser.html -new file mode 100644 -index 0000000000..e8cf34664d ---- /dev/null -+++ b/tools/grit/grit/testdata/bad_browser.html -@@ -0,0 +1,16 @@ -+

    We're sorry, but we don't seem to be compatible.

    -+

    Our software suggests that you're using a browser incompatible with Google Desktop Search. -+ Google Desktop Search currently supports the following:

    -+ -+ -+

    You may click here to use your -+ unsupported browser, though you likely will encounter some areas that don't -+ work as expected. You need to have Javascript enabled, regardless of the -+ browser you use. -+

    We hope to expand this list in the near future and announce new -+ browsers as they become available. -diff --git a/tools/grit/grit/testdata/browser.html b/tools/grit/grit/testdata/browser.html -new file mode 100644 -index 0000000000..45d364d56f ---- /dev/null -+++ b/tools/grit/grit/testdata/browser.html -@@ -0,0 +1,42 @@ -+ -+[$~TITLE~$] -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    [$~IMAGE~$] -+   -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+
     [$~CHROME_TITLE~$]
    -+
    -+ -+ -+ -+ -+ -+
    -+ [$~BODY~$] -+
    -+[$~FOOTER~$] -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/buildinfo.grd b/tools/grit/grit/testdata/buildinfo.grd -new file mode 100644 -index 0000000000..80458a8265 ---- /dev/null -+++ b/tools/grit/grit/testdata/buildinfo.grd -@@ -0,0 +1,46 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Copyright 2008 Google Inc. All Rights Reserved. -+ -+ -+ Google Desktop News gadget -+[IDS_COPYRIGHT_GOOGLE_LONG] -+View news that is personalized based on the articles you read. -+ -+For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles. -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/cache_prefix.html b/tools/grit/grit/testdata/cache_prefix.html -new file mode 100644 -index 0000000000..b1f91dd82b ---- /dev/null -+++ b/tools/grit/grit/testdata/cache_prefix.html -@@ -0,0 +1,24 @@ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+
    This is one version of -+[URL-DISP] from your personal cache.
    -+The page may have changed since that time. Click here for the current page.
    -+Since this page is stored on your computer, publicly linking to this page will not work.[$~EXTRA~$]

    -+Google may not be affiliated with the authors of this page nor responsible for its content. This page may be protected by copyright. -+
    -+ -+ -+


    -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/cache_prefix_file.html b/tools/grit/grit/testdata/cache_prefix_file.html -new file mode 100644 -index 0000000000..f3eb8e0f11 ---- /dev/null -+++ b/tools/grit/grit/testdata/cache_prefix_file.html -@@ -0,0 +1,25 @@ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+
    This is one version of [URL-DISP] -+from your personal cache.
    -+The file may have changed since that time. Click here for the current file.
    -+Since this file is stored on your computer, publicly linking to it will not work.[$~EXTRA~$]

    -+Google may not be affiliated with the authors of this page nor responsible for its content. This page may be protected by copyright. -+
    -+
    -+ -+ -+
    -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/chat_result.html b/tools/grit/grit/testdata/chat_result.html -new file mode 100644 -index 0000000000..318078bc3d ---- /dev/null -+++ b/tools/grit/grit/testdata/chat_result.html -@@ -0,0 +1,24 @@ -+[HEADER] -+[CHROME] -+ -+ -+
    [$~STARTCHAT~$]
    -+
    -+
    -+   [$~TITLE~$] -+

    Participants: [USERNAME], [BUDDYNAME]
    -+Date: [TIME]
    -+
    -+ -+
    -+ -+ -+
    [$~STARTCHAT~$]
    -+ -+ -+[FOOTER] -diff --git a/tools/grit/grit/testdata/chrome/app/generated_resources.grd b/tools/grit/grit/testdata/chrome/app/generated_resources.grd -new file mode 100644 -index 0000000000..c2efb77fd8 ---- /dev/null -+++ b/tools/grit/grit/testdata/chrome/app/generated_resources.grd -@@ -0,0 +1,199 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ New background app installed -+ -+ -+ $1Background App will launch at system startup and continue to run in the background even once you've closed all other $2Google Chrome windows. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/chrome_html.html b/tools/grit/grit/testdata/chrome_html.html -new file mode 100644 -index 0000000000..7f7633c5cf ---- /dev/null -+++ b/tools/grit/grit/testdata/chrome_html.html -@@ -0,0 +1,6 @@ -+ -+ -diff --git a/tools/grit/grit/testdata/default_100_percent/a.png b/tools/grit/grit/testdata/default_100_percent/a.png -new file mode 100644 -index 0000000000000000000000000000000000000000..5d5089038ca71172e95db9e7aae1e1fa5cebd505 -GIT binary patch -literal 159 -zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>0wld=oSO}#(mY)pLnNjq|2Y3)zGGzYPN&L+ -zMSC}CcCfp=Dtxv4%6W%G#Q=|R|L;6pCCLUWO)Z<5eoL%TkDTw=s4X!^d(Qa<2khAN -zZPy!XToBAic1Ss}vcWiD27B3&`Zj^H6CO>7R1{ToQ;=ggdEYbV=IISvfHpFCy85}S -Ib4q9e0O9jEh5!Hn - -literal 0 -HcmV?d00001 - -diff --git a/tools/grit/grit/testdata/default_100_percent/b.png b/tools/grit/grit/testdata/default_100_percent/b.png -new file mode 100644 -index 0000000000..6178079822 ---- /dev/null -+++ b/tools/grit/grit/testdata/default_100_percent/b.png -@@ -0,0 +1 @@ -+b -diff --git a/tools/grit/grit/testdata/del_footer.html b/tools/grit/grit/testdata/del_footer.html -new file mode 100644 -index 0000000000..4e19950bfc ---- /dev/null -+++ b/tools/grit/grit/testdata/del_footer.html -@@ -0,0 +1,8 @@ -+ -+ -+ -+
     Remove checked results and return to search.Check all - Uncheck all   -+ -+
    -+

    [$~BOTTOMLINE~$] - ©2005 Google
    -+ -diff --git a/tools/grit/grit/testdata/del_header.html b/tools/grit/grit/testdata/del_header.html -new file mode 100644 -index 0000000000..72bc6756eb ---- /dev/null -+++ b/tools/grit/grit/testdata/del_header.html -@@ -0,0 +1,60 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    Go to Google Desktop Search  -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+ -+
     Remove Specific ItemsHelp  
    -+
    -+ -+ -+ -+ -+ -+ -+
     Remove checked results and return to search.Check all - -+Uncheck all  
    -+
    -+ -+ -+ -+ -+
     Remove -+checked items from Google Desktop Search. Other copies of the same items will not be -+affected.
    -+ If you view the item again, it will be added back to Google Desktop Search.
    -+
    -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/deleted.html b/tools/grit/grit/testdata/deleted.html -new file mode 100644 -index 0000000000..5ae5f355fa ---- /dev/null -+++ b/tools/grit/grit/testdata/deleted.html -@@ -0,0 +1,21 @@ -+ -+Database Deleted -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+
    Google Desktop Search -+

    -+
    The database has been deleted. Click here to continue.
    -+ -+ -+
    [$~BOTTOMLINE~$]

    -+

    ©2005 Google

    -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/depfile.grd b/tools/grit/grit/testdata/depfile.grd -new file mode 100644 -index 0000000000..e2f7191218 ---- /dev/null -+++ b/tools/grit/grit/testdata/depfile.grd -@@ -0,0 +1,18 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/details.html b/tools/grit/grit/testdata/details.html -new file mode 100644 -index 0000000000..0ab0e2a90c ---- /dev/null -+++ b/tools/grit/grit/testdata/details.html -@@ -0,0 +1,10 @@ -+[!] -+title Improve Google Desktop Search by Sending Non-Personal Information -+template -+bottomline -+hp_image -+ -+

    This documentation is not yet available

    -+

    -+[$~BOTTOMLINE~$] - ©2005 Google -+
    -diff --git a/tools/grit/grit/testdata/duplicate-name-input.xml b/tools/grit/grit/testdata/duplicate-name-input.xml -new file mode 100644 -index 0000000000..cc4d1d65c5 ---- /dev/null -+++ b/tools/grit/grit/testdata/duplicate-name-input.xml -@@ -0,0 +1,26 @@ -+ -+ -+ -+ -+ -+ Hello %sJoi, how are you doing today? -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/email_result.html b/tools/grit/grit/testdata/email_result.html -new file mode 100644 -index 0000000000..8bb04b988c ---- /dev/null -+++ b/tools/grit/grit/testdata/email_result.html -@@ -0,0 +1,34 @@ -+[HEADER] -+[CHROME] -+ -+ -+
    [CONV] -+Reply | Reply to All[$~FORWARD_URL~$] | Compose[$~OUTLOOKVIEW~$] -+
    -+
    -+
    -+   [SUBJECT] -+

    [FROM-DISP] -+[TO-DISP] -+[CC-DISP] -+[BCC-DISP] -+[REPLYTO-DISP] -+[DATE-DISP] -+[VIEW-DISP] -+[$~ATTACH~$] -+

    -+

    -+ -+
    -+ -+
    [CONV] -+Reply | Reply to All[$~FORWARD_URL~$] | Compose[$~OUTLOOKVIEW~$] -+
    -+ -+ -+[FOOTER] -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/email_thread.html b/tools/grit/grit/testdata/email_thread.html -new file mode 100644 -index 0000000000..3c7279b841 ---- /dev/null -+++ b/tools/grit/grit/testdata/email_thread.html -@@ -0,0 +1,10 @@ -+[HEADER] -+[CHROME] -+
    -+   [SUBJECT]

    -+ -+[CONTENTS] -+
    -+
    -+[NEXT_PREV] -+[FOOTER] -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/error.html b/tools/grit/grit/testdata/error.html -new file mode 100644 -index 0000000000..66875a234c ---- /dev/null -+++ b/tools/grit/grit/testdata/error.html -@@ -0,0 +1,8 @@ -+[HEADER] -+[CHROME] -+
    -+
    -+[ERROR]

    -+If you think this is an error, please contact us. -+
    -+[FOOTER] -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/explicit_web.html b/tools/grit/grit/testdata/explicit_web.html -new file mode 100644 -index 0000000000..1424adc617 ---- /dev/null -+++ b/tools/grit/grit/testdata/explicit_web.html -@@ -0,0 +1,11 @@ -+[HEADER] -+ -+[WEB_TOP_CHROME] -+[$~STATUS~$] -+[$~MESSAGE~$] -+[WEB_FILES] -+
    [NEXT_PREV] -+[FOOTER] -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/footer.html b/tools/grit/grit/testdata/footer.html -new file mode 100644 -index 0000000000..3372d6afac ---- /dev/null -+++ b/tools/grit/grit/testdata/footer.html -@@ -0,0 +1,14 @@ -+


    -+
    -+ -+ -+

    -+ -+ -+ -+
    [$~BOTTOM~$]

    -+
    -+

    -+[$~BOTTOMLINE~$] - ©2005 Google
    -+[SCRIPT] -+ -diff --git a/tools/grit/grit/testdata/generated_resources_fr.xtb b/tools/grit/grit/testdata/generated_resources_fr.xtb -new file mode 100644 -index 0000000000..373c40feea ---- /dev/null -+++ b/tools/grit/grit/testdata/generated_resources_fr.xtb -@@ -0,0 +1,3079 @@ -+ -+ -+ -+Salut! -+Salut -+Supprime&r -+Activer la barre de favoris -+Déconnexion du réseau privé -+ sur  -+Déconnecter ce compte... -+&Vérifier l'orthographe dans ce champ -+Aucune donnée reçue. -+Une erreur s'est produite lors de la tentative de lecture du fichier : . -+Le mot de passe multiterme est obligatoire. -+Importer les données d'un autre navigateur... -+Saisie automatique -+API P2P -+Exécuter automatiquement (recommandé) -+Le certificat de sécurité du site a expiré ! -+Clé publique de l'objet -+Importer -+Afficher dan&s un onglet -+ID : -+Le certificat n'indique aucun mécanisme permettant de vérifier s'il a été révoqué. -+Touches de modification... -+Signé par : -+Utiliser un service Web pour résoudre les erreurs de navigation -+Guillemet -+Une nouvelle tentative de connexion avec SSL 3.0 a dû être effectuée. Cette opération indique généralement que le serveur utilise un logiciel très ancien et qu'il est susceptible de présenter d'autres problèmes de sécurité. -+Autoriser le stockage des données locales (recommandé) -+Ouvrir dans une fenêtre -+Google pense qu'un logiciel malveillant pourrait être installé sur votre ordinateur si vous continuez. Nous vous conseillons de ne pas continuer, même si vous avez déjà consulté ce site auparavant ou si vous avez confiance en celui-ci. Il se peut qu'il ait été piraté récemment. Réessayez demain ou utilisez un autre site. -+&Rechercher : -+Échec de génération de clé privée RSA aléatoire -+Certificat en attente -+Technologie réseau : -+Le certificat du serveur ne figure pas dans le DNS. -+Demander le mot de passe au retour de veille -+Désactiver la synchronisation -+Base de données indexée -+Ne pas enregistrer -+ synchronise vos données avec votre compte Google en toute sécurité. Synchronisez toutes vos données ou personnalisez les types de données synchronisées et les options de chiffrement. -+Le délai imparti à l'opération est dépassé. -+Nordique -+Créer des raccourcis vers des applications -+Pas encore chargé -+Confirmer le nouveau code PIN : -+L2TP/IPSec + Certificat utilisateur -+Préfecture -+Extraction de l'image de récupération... -+Terminé -+Il se peut que la page Web à l'adresse soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web. -+Cache des scripts -+Barre d'outils Google -+Importés depuis Safari -+Le plug-in n'est pas autorisé. -+Vous exécutez à partir de son image disque. Si vous l'installez sur votre ordinateur, vous pourrez l'utiliser sans image disque et bénéficierez de mises à jour automatiques. -+Certificat du serveur SSL -+Z&oom arrière -+Indique si la suggestion du moteur de recherche doit être entrée immédiatement via la saisie semi-automatique lorsque la fonctionnalité Recherche instantanée est activée. -+Mise à jour du système : % téléchargés -+Les informations d'identification associées au partage de vos imprimantes via sont arrivées à expiration. Cliquez ici pour saisir à nouveau votre nom d'utilisateur et votre mot de passe. -+Erreur de définition du paramètre de confiance du certificat -+ peut maintenant synchroniser vos mots de passe. -+Sélectionnez le certificat à présenter pour l'identification : -+ a planté. Cliquez sur cette info-bulle pour actualiser l'extension. -+Compatibilité expérimentale avec des méthodes Wi-Fi Extensible Authentication Protocol supplémentaires, telles que EAP-TLS et LEAP. -+Échec de lecture de la clé privée -+Les plug-ins suivants ont été bloqués sur cette page : -+Configuration de la synchronisation -+Case d'option cochée -+Très petite -+URL de révocation de l'autorité de certification Netscape -+Style de pavé numérique -+Active les feuilles de style CSS 3D et la composition graphique haute performance des pages Web via le processeur graphique. -+&Rétablir -+Redémarrer -+La connexion n'est pas compressée. -+Fin -+&Nouvelle fenêtre -+Configuration automatique du proxy -+Afficher l'orthographe et la grammaire -+Aucune imprimante n'a été trouvée. Veuillez en installer une. -+Saisissez les caractères visibles dans l'image ci-dessous. -+Certificat d'authentification de client SSL incorrect -+Le certificat du serveur ou un certificat AC intermédiaire présenté au navigateur a été signé avec un algorithme de signature faible tel que RSA-MD2. D'après des études récentes menées par des informaticiens, les algorithmes de signature seraient plus faibles qu'on ne le pensait jusqu'alors. Aujourd'hui, ils sont très rarement utilisés par les sites Web jugés dignes de confiance. Ce certificat a peut-être été contrefait. Nous vous déconseillons vivement de continuer. -+Rechercher le précédent -+I&nspecter l'élément -+État d'itinérance : -+&Non -+Effacer les données de navigation... -+Nombre maximal de suggestions -+L'accessibilité est désactivée. -+Sélectionner par domaine -+Tout réduire... -+Ne jamais traduire les pages rédigées en -+Non confirmé -+Avant de vous connecter, démarrez une session en tant qu'invité afin d'activer le réseau . -+La gravure de l'image est terminée. -+Si vous supprimez le certificat d'une autorité de certification, votre navigateur ne fera plus confiance aux certificats émis par cette autorité de certification. -+Synchronisez toutes les données de cet ordinateur ou sélectionnez celles que vous souhaitez synchroniser. -+ hours ago -+Domaine : -+Aperçu -+Associe chaque fenêtre du navigateur à un profil et ajoute une option de sélection des profils en haut à droite. Chaque profil possède ses propres favoris, extensions, applications, etc. -+Ignorer le verrouillage des majuscules et saisir des minuscules par défaut -+Aucune parole détectée -+Changer de moteur de recherche par défaut -+Cliquer pour revenir en arrière, maintenir pour voir l'historique -+ secondes restantes -+Unicode -+Ouverture à la fin du téléchargement -+Les extensions, les applications et les thèmes peuvent endommager votre ordinateur. Voulez-vous vraiment continuer ? -+Schéma du pinyin double -+Déconnecter ce compte... -+&Fichier -+Microsoft Internet Explorer -+Aucune correspondance trouvée -+État de votre commentaire -+Mise à jour terminée. Veuillez redémarrer le système. -+Lorsque vous supprimez un certificat de serveur, vous rétablissez les contrôles de sécurité habituels du serveur et un certificat valide lui est demandé. -+Essayez d'ajouter -+ -+ aux programmes autorisés dans les paramètres de votre pare-feu ou de votre antivirus. S'il -+ est déjà autorisé, tentez de le supprimer de la liste et de l'ajouter à nouveau à -+ la liste des programmes autorisés. -+Réseaux sans fil -+Masquer -+Zoom arrière -+Méthode EAP : -+Développer -+Veuillez vous connecter -+de n'importe quand -+Désactiver la validation des formulaires interactifs HTML5 -+Le suivi de votre position géographique sur cette page a été bloqué pour les sites suivants : -+La gravure de l'image a été interrompue. -+&Afficher dans le dossier -+Continuer à bloquer JavaScript -+Enregistrer la page sous... -+Le serveur à l'adresse requiert un nom d'utilisateur et un mot de passe. -+Exceptions de géolocalisation -+13px -+Contenu : -+Le plug-in a été bloqué, car il n'est plus à jour. -+Taille ré&elle -+Échec de la connexion au serveur proxy. -+Vérification de pilote matériel Microsoft Windows -+Paysage -+Détecter automatiquement -+Page -+Nom d'utilisateur : -+Nous aider à améliorer en envoyant automatiquement les statistiques d'utilisation et les rapports d'erreur à Google -+Réseau -+Connexion en cours -+Ajouter tous les onglets aux favoris... -+Onglets ou fenêtres -+Sites récemment consultés -+Ouvrir dans une fenêtre de navigation privée -+Préférences de saisie automatique... -+Compteur d'images par seconde -+Mot de passe -+Afficher le compte -+ : -+Le suivi de votre position géographique a été bloqué pour cette page. -+Connexion à l'aide de votre compte Google -+Le mot de passe multiterme entré est incorrect. -+télécopie : # -+Le navigateur par défaut est actuellement . -+ secondes restantes -+Mot de passe précédent -+Code PIN incorrect -+Modifier l'adresse -+Zoom avant -+Micrologiciel -+Une erreur s'est produite lors de l'affichage de cette page Web. Pour continuer, actualisez cette page ou ouvrez-en une autre. -+Récupération de clé Microsoft -+recto verso -+Fichier ou répertoire introuvable -+Aucun forfait de données actif -+Tout sélectionner -+Le fichier manifeste est incorrect. -+Les pages suivantes ne répondent plus. Vous pouvez attendre qu'elles soient de nouveau accessibles ou les supprimer. -+ minutes restantes -+Le certificat du serveur n'est pas encore valide. -+Menu contenant des extensions masquées -+Enregistrer les infos -+Configuration de l'accès à distance à cet ordinateur. -+Point -+Ajouter un moteur de recherche -+Impossible d'atteindre le serveur. -+Importer mes favoris... -+Enregistrer le &cadre sous... -+Vous n'êtes pas autorisé à accéder à la page Web . Votre connexion peut être requise. -+Envoyer la capture d'écran du dernier onglet actif -+Erreur -+Utiliser le thème GTK+ -+Ouvrir une fenêtre du navigateur -+ a planté. Cliquez sur cette info-bulle pour redémarrer l'application. -+Définir comme navigateur par défaut -+Certificat de courrier électronique -+Clavier en superposition -+La connexion est compressée avec . -+Exporter mes favoris... -+Format : -+Ignorer -+Déplacer un mot -+Index de -+Mémoire -+Impossible d'utiliser cette langue pour corriger l'orthographe. -+Recherche -+Ajouter une autre carte de paiement... -+Envoyer la dernière capture d'écran enregistrée -+Ce fichier contient du code malveillant. Voulez-vous vraiment continuer ? -+Erreur de synchronisation... -+Clavier brésilien -+Utiliser TLS 1.0 -+&Signaler un problème... -+Créer des raccourci&s vers des applications... -+Le certificat "" a été émis par : -+ ne contrôlant pas la façon dont les extensions gèrent vos données personnelles, toutes les extensions sont désactivées dans les fenêtres de navigation privée. Vous pouvez les réactiver individuellement dans le gestionnaire des extensions. -+Logiciels malveillants -+Mise en page ou mise en forme de la page -+Acheter davantage... -+Traduire -+Tout -+Créé : -+Annuler l'importation -+Le mode indiqué est incorrect. -+ copié(s) sur -+L'accès à distance à cet ordinateur est activé pour . -+Options... -+Un problème est survenu lors de la création du support de récupération du système d'exploitation. Le périphérique de stockage utilisé est introuvable. -+Toujours &afficher la barre de favoris -+Erreur SSL -+Confirmer les préférences de synchronisation -+Utiliser les valeurs par défaut -+Code secret manquant -+L'accès à distance à cet ordinateur est désactivé. -+API des extensions expérimentales -+Inclure les informations système -+Date d'expiration -+Autorité de certification compromise -+À propos de la saisie automatique -+Activer la fonction "Taper pour cliquer" -+Accès à la page Web refusé -+&Gestionnaire de favoris -+Erreur serveur -+Cette carte SIM est désactivée et ne peut être utilisée. Veuillez demander à votre fournisseur de services de la remplacer. -+Outils -+Clavier néerlandais -+EAP-TTLS -+Choisissez une image à associer à votre compte. Celle-ci s'affichera sur l'écran de connexion. -+Configurer le blocage des fenêtres pop-up... -+des 4 dernières semaines -+Une situation inattendue s'est produite tandis que le serveur tentait de traiter la demande. -+Impossible d'afficher certaines parties de ce document PDF. Souhaitez-vous l'ouvrir dans Adobe Reader ? -+Proxy FTP -+Si vous utilisez la version PPAPI de Flash, exécutez-la dans chaque processus de moteur du rendu plutôt que dans un processus de plug-in dédié. -+Cela signifie que le certificat présenté à votre navigateur contient des erreurs et qu'il ne peut pas être compris. Il est possible que les informations sur l'identité du certificat ou que d'autres informations du certificat relatives à la sécurité de la connexion soient incompréhensibles. Ne poursuivez pas. -+Activer l'onglet 1 -+Communication à distance -+Importer les favoris et les paramètres... -+À propos -+Modifier le favori de cette page -+Ajouter un format d'exception -+Configurer l'accès à distance... -+Supprimer le certificat "" ? -+Cache des images -+Configuration du proxy -+En l'absence de connexion Wi-Fi, Google Chrome utilise les données 3G. -+Appuyez sur pour sélectionner le mode de saisie précédent. -+La création du support de récupération du système d'exploitation a été annulée. -+Le plug-in suivant est bloqué : -+Erreur de connexion réseau -+Mot de passe multiterme -+Internet -+Configurer les paramètres de blocage des plug-ins... -+Afficher dan&s un onglet -+Synchroniser vos mots de passe -+Le serveur proxy agit comme un intermédiaire entre votre ordinateur et les autres serveurs. Votre configuration système utilise actuellement un proxy, mais -+ -+ ne parvient pas à s'y connecter. -+Sélectionner par type d'application -+Procéder à l'i&nspection de l'élément -+Impossible de valider entièrement l'identité du serveur auquel vous êtes connecté. Le nom utilisé pour cette connexion n'est valide que sur votre réseau et aucune autorité de certification externe ne peut en vérifier la propriété. Certaines autorités de certification délivrent tout de même des certificats pour ces types de nom, par conséquent nous ne sommes pas en mesure de vérifier que vous êtes connecté au site voulu et non à un site malveillant. -+Impossible de déplacer le répertoire d'extensions dans le profil. -+Supprimer ces paramètres pour les prochaines visites -+L'accessibilité est activée. -+Appuyer sur la touche Espace pour sélectionner la suggestion -+Vos favoris -+ () -+Fermer les onglets -+Applications en arrière-plan -+Favoris -+Supprimer les données synchronisées de Google Dashboard -+Veuillez patienter pendant que installe les dernières mises à jour système. -+Utilisez les touches Maj gauche et droite pour sélectionner les 2e et 3e propositions -+WEP -+Mode Zhuyin complet. La sélection automatique de la suggestion et les options associées sont désactivées ou ignorées. -+&Paramètres linguistiques... -+CRX-less Web Apps -+Connexion au réseau -+Reliure bord long -+ utilise les paramètres proxy du système pour se connecter au réseau. -+Application : -+&Descendre -+? Toutes les données présentes sur le périphérique seront supprimées. -+Adresse IP -+Active le nouveau design de la page "Nouvel onglet" (en cours de développement). -+Échec de l'activation -+Ne pas vérifier -+Le chinois simplifié est le mode de saisie initial -+Paramètres SSL sur tout l'ordinateur : -+Votre connexion à n'est pas chiffrée. -+matériel requis -+Gérer les exceptions... -+Rechercher des mises à jour -+Utiliser un mot de passe multiterme pour chiffrer mes données de synchronisation -+Connexion en cours... -+Le serveur ne parvient pas à traiter la demande pour le moment. Ce code indique une situation temporaire. Le serveur sera de nouveau opérationnel ultérieurement. -+Historique -+Destination -+Web audio -+Cookies placés par cette page -+Accès partagé -+Afficher... -+Veuillez vous connecter à . -+Ajouter un nouvel e-mail -+Personnaliser les polices... -+Matériel : -+Erreur de connexion au réseau. -+Cette page Web est introuvable. -+En&registrer la vidéo sous... -+Le certificat du serveur n'est pas approuvé. -+Cop&ier l'image -+Sebeol-sik 390 -+ mins ago -+Autre réseau mobile... -+Erreur HTTP () : -+Signature du code -+Aide -+<sans nom> -+Version du micrologiciel : -+La page ne se charge pas -+Attention, ces fonctionnalités expérimentales peuvent mordre. -+Verrouiller l'écran ou éteindre -+La connexion est chiffrée au moyen de , avec pour l'authentification des messages et pour la méthode d'échange de clés. -+Clavier portugais -+Importation -+Connexion au réseau -+Langues -+Cette erreur peut se produire lors de la connexion à un serveur sécurisé (HTTPS). -+ Elle indique que le serveur tente d'établir une connexion sécurisée, mais -+ que celle-ci ne sera pas du tout sécurisée en raison d'une grave erreur de configuration. -+ Dans ce cas, une intervention -+ est requise sur le serveur. -+ -+ n'utilise pas de connexion non sécurisée pour protéger la confidentialité -+ de vos données. -+La synchronisation de vous permet de partager vos données (favoris, préférences) sur vos ordinateurs en toute simplicité. Pour ce faire, enregistre vos données en ligne via Google lorsque vous vous connectez à votre compte. -+Format ou mise en forme de la page -+Clavier suisse -+En&registrer l'image sous... -+Basculer en mode pleine chasse ou demi-chasse -+Sélectionner... -+Effacer les paramètres d'ouverture automatique -+Ajouter un réseau privé -+ secondes -+Ne pas envoyer de capture d'écran -+Hébreu -+Toujours afficher la barre de favoris -+Impossible de trouver le chemin d'accès absolu du répertoire à empaqueter. -+Créer un profil -+Diners Club -+Paramètres de contenu... -+Activer la recherche instantanée pour accélérer la recherche et la navigation ? -+Plus d'extensions >> -+La valeur d'entrée de la clé privée est obligatoire. -+PEAP -+Fonctionnalités de localisation expérimentales -+Ou&vrir la vidéo dans un nouvel onglet -+Toujours afficher la barre de favoris -+Reliure -+Utilisation de la clé du certificat -+Clavier belge -+ heures restantes -+Afficher toutes les images (recommandé) -+Cliquez sur -+ Démarrer, -+ puis sur -+ Exécuter. -+ Saisissez -+ et cliquez sur -+ OK. -+Nom de volume -+Reliure bord court -+ va configurer les mises à jour automatiques pour tous les utilisateurs de cet ordinateur. -+Effacer les éléments datant : -+Interdire à tous les sites d'afficher des notifications sur le Bureau -+Appuyez sur pour passer d'un mode de saisie à l'autre. -+Ajouter un nouveau fax -+Recherche de contenu en cours... -+Style d'entrée avec Espace -+Vous avez tenté d'accéder à , mais, au lieu de cela, vous communiquez actuellement avec un serveur identifié comme . Cela est peut-être dû à un défaut de configuration du serveur ou à quelque chose de plus grave. Un pirate informatique sur votre réseau cherche peut-être à vous faire visiter une version falsifiée de , donc potentiellement préjudiciable. Nous vous déconseillons vivement de continuer. -+Masquer le bouton -+Modifier l'image -+Ne pas synchroniser mes mots de passe -+JavaScript -+Activer les notifications de -+Afficher les incompatibilités -+Nouvel onglet -+Impossible de charger l'icône "" d'action de page. -+Fermer l'onglet -+Nom d'hôte du serveur : -+Ajouter une carte de paiement -+ : type de fichier inconnu -+Non défini -+Gérer les paramètres de saisie automatique... -+Respecter la &casse -+Autoriser tous les sites à exécuter JavaScript (recommandé) -+Gérer vos périphériques depuis le cloud -+Clavier catalan -+Me demander lorsqu'un site essaie de stocker des données -+Menu -+Sélectionnez le périphérique de stockage amovible à utiliser. -+La traduction a échoué, car nous n'avons pas pu déterminer la langue de la page. -+Vous pouvez créer des profils supplémentaires pour autoriser plusieurs personnes à utiliser et personnaliser Google Chrome. -+Deux-points -+Toujours traduire en -+(désactivée) -+Cela signifie que le certificat n'a pas été vérifié par un tiers reconnu par votre ordinateur. N'importe qui peut émettre un certificat en se faisant passer pour un autre site Web. Ce certificat doit donc être vérifié par un tiers approuvé. Sans cette vérification, les informations sur l'identité du certificat sont sans intérêt. Par conséquent, il nous est impossible de vérifier que vous communiquez bien avec et non avec un pirate informatique ayant émis son propre certificat en prétendant être . Nous vous déconseillons vivement de continuer. -+ requiert que vous cryptiez vos données à l'aide de votre mot de passe Google ou de votre propre mot de passe multiterme. -+ -+N'est pas une autorité de certification -+Date et heure : -+Impossible de charger "" pour le thème. -+Rechercher à nouveau -+En attente de ... -+Masquer ce plug-in -+Enregistrer &sous... -+Ajouter une langue : -+Annuler -+Ouvrir une &adresse... -+Supprimer le mot -+Vous devez saisir deux fois le même mot de passe multiterme. -+Ouvrir dans un onglet épinglé -+Page Web, tout type de contenu -+Activer -+Considérer ce certificat comme fiable pour identifier les développeurs de logiciels. -+Ajouter tous les onglets aux favoris -+Impossible de créer le dossier de favoris. -+Copier l'URL -+Si vous pensez ne pas avoir à utiliser de serveur proxy, procédez comme suit : -+ -+Définir les utilisateurs autorisés à se connecter à un périphérique et autoriser les sessions de navigation en tant qu'invité -+Sélectionnez le répertoire racine de l'extension à empaqueter. Pour mettre à jour une extension, sélectionnez également le fichier de clé privée à réutiliser. -+Pool restreint : -+&Rafraîchir cette page -+&Normal -+PKCS #1 SHA-384 avec chiffrement RSA -+Numéro de série : -+HTTPS/SSL -+Toutes les données de votre ordinateur et des sites Web que vous visitez -+Ceci est une installation secondaire de et ce dernier ne peut pas être défini comme navigateur par défaut. -+Erreur lors de la signature de l'extension -+ permet d'effectuer des recherches sur Internet à l'aide du champ polyvalent. Sélectionnez le moteur de recherche à utiliser : -+Sécurité : -+Adobe Reader n'est pas à jour -+Extensions ou applications -+Effacer les cookies et autres données de site et de plug-in lorsque je ferme le navigateur -+Téléchargement de l'image terminé. -+Favoris -+Afficher les vignettes -+Ne plus afficher ce message -+Agent de récupération de clé Microsoft -+Page de diagnostic de navigation sécurisée -+Adresse ligne 2 -+Décrivez-nous le problème recontré. (Champ obligatoire) -+Cela peut prendre quelques minutes. -+Options de base -+Niveau de zoom par défaut : -+Stockage externe -+Modifi&er les moteurs de recherche... -+Cartes de paiement -+Nom du fichier -+Arrêter la synchronisation -+Actualiser le cadre -+Connexion -+Mémoire privée -+Tout effacer -+Activer la correction orthographique automatique -+Afficher les &infos sur la page -+favoris_.html -+Autoriser uniquement les utilisateurs suivants à se connecter : -+&Muet -+Nouvel ongle&t -+Erreur de synchronisation -+Zoom -+ sur -+Type de clavier -+Délai d'expiration atteint au niveau de la passerelle ou du serveur proxy en attente d'une réponse d'un serveur en amont. -+Déplacer -+Mode de saisie du vietnamien (VIQR) -+Ajouter la page actuelle aux favoris -+<aucun cookie sélectionné> -+Le mot de passe de l'application est incorrect. -+Sélectionner "un mot à la fois" -+Tout bloquer -+Chargement en cours… -+&Rouvrir la fenêtre fermée -+Gérer les exceptions... -+URL -+Katakana demi-chasse -+Ouvrir une adresse -+Données de navigation -+Code PIN incorrect. Veuillez réessayer. -+Non -+Utiliser cette langue pour corriger l'orthographe -+Fermer les autres onglets -+Clé privée non valide. -+Une erreur réseau s'est produite pendant la communication avec le service de gestion des périphériques. -+Importer les données d'un autre navigateur... -+&Ajouter au dictionnaire -+Voulez-vous vraiment ouvrir  onglets ? -+Fabricant du périphérique : -+Afficher l'historique complet -+Illimité -+Clavier Neo2 allemand -+Liste déroulante -+Clé : -+Coller en texte brut -+Afficher les &commandes -+Cette page suit votre position géographique. -+Certificat de chiffrement de courrier électronique -+&Profilage activé -+En savoir plus sur la récupération du système -+Essentielle -+Type MIME -+Autoriser le téléchargement ? -+Clavier croate -+Interdire à tous les sites de suivre ma position géographique -+Utiliser la barre de titre du système et les bordures de la fenêtre -+En bas à gauche -+Informations sur l'erreur : -+Essayez : saisissez "orchidées", puis appuyez sur Entrée. -+Pour utiliser Chrome Web Store, vous devez être connecté à un compte Google. -+Configurer -+Petit problème... Nous n'avons pas réussi à vous authentifier. Veuillez vérifier vos identifiants de connexion puis réessayer. -+Pour gérer à distance la configuration de ce périphérique depuis le cloud, connectez-vous avec votre compte Google Apps. -+Réactiver -+Fermer la fenêtre -+Présentation -+Vous avez saisi un trop grand nombre de codes PIN incorrects. Veuillez contacter pour obtenir une nouvelle clé de déverrouillage du code PIN à 8 chiffres. -+Bloquer le contenu inapproprié -+Configuration avancée -+Utiliser SSL 3.0 -+Règles de confidentialité liées à la navigation sécurisée -+Vous devez être connecté à votre compte Google pour importer les favoris de la barre d'outils Google dans Google Chrome. Connectez-vous et relancez l'importation. -+Ouvrir le lien dans une nouvelle &fenêtre -+Les cookies de ont été bloqués. -+Copies -+&Ouvrir le fichier audio dans un nouvel onglet -+Afficher les noms d'utilisateurs et leur photo sur la page de connexion -+URL de révocation de certificat Netscape -+Ajoute des options de regroupement des onglets dans le menu contextuel des onglets. -+Clavier finnois -+Vérifiez votre connexion Internet. Redémarrez votre routeur, votre modem -+ ou tout autre périphérique réseau que vous utilisez. -+&Afficher le code source de la page -+Le serveur ne prend pas en charge la version HTTP utilisée dans la demande. -+Vos mots de passe enregistrés s'afficheront ici. -+Fermer les onglets sur la droite -+ heures -+ -+ indique qu'un produit ESET intercepte les connexions sécurisées. -+ En général, cela ne constitue pas un problème de sécurité car le -+ logiciel ESET s'exécute souvent sur le même ordinateur. Toutefois, en raison -+ de certaines incompatibilités avec les connexions sécurisées -+ , -+ vous devez configurer les produits ESET de manière à éviter ces -+ interceptions. Cliquez sur le lien En savoir plus pour obtenir des instructions. -+Les requêtes adressées au serveur ont été temporairement limitées. -+Impossible de télécharger l'image. Gravure annulée. -+Activer/désactiver le mode Hanja -+Effacer les paramètres d'ouverture automatique -+Pas après le -+Manifeste : -+Visa -+Clavier anglais canadien -+Récupération de fichier Microsoft -+En&registrer l'image sous... -+Zone -+Chemin : -+Prendre la photo -+Inactif -+Certains de vos certificats enregistrés identifient ces autorités de certification : -+Impossible d'afficher la page Web, car le serveur n'a envoyé aucune donnée. -+Considérer ce certificat comme fiable pour identifier les utilisateurs de messageries. -+Ce type de fichier peut endommager votre ordinateur. Voulez-vous vraiment télécharger  ? -+Importés depuis la barre d'outils Google -+Recherche instantanée et saisie semi-automatique -+Tout synchroniser -+Dvorak (Hsu) -+Exécuter la commande  : -+Le fichier contenait un certificat, qui n'a pas été importé : -+Vous utilisez actuellement un mot de passe multiterme. Si vous l'oubliez, vous pouvez réinitialiser la synchronisation afin de supprimer vos données des serveurs Google à l'aide de Google Dashboard. -+Impossible de détecter les modules chargés. -+Cette fonctionnalité affiche une bordure autour des couches de rendu afin de déboguer et d'étudier leur composition. -+Processus de traitement Web : -+Invité -+Nom du fichier : -+Un élément est manquant. -+Échec de la tentative de connexion au serveur. -+Des fenêtres pop-up ont été bloquées sur cette page. -+Personnaliser les langues et la saisie... -+Proxy HTTP -+Mot de passe multiterme de chiffrement -+Nouvelle fenêtre -+Certains certificats provenant de ces organisations vous identifient : -+Autoriser l'itinérance des données mobiles -+Alt -+Utiliser les pages actuelles -+Version -+En&registrer le fichier audio sous... -+Itinérance -+Romaji -+ minutes -+Synchroniser uniquement les paramètres et\ndonnées qui ont changé depuis la dernière connexion\n(requiert votre mot de passe précédent) -+Autoriser tous les sites à afficher des notifications sur le Bureau -+Ouvrir le fichier... -+Changer de fenêtre -+Chèvres téléportées -+Si vous arrêtez la synchronisation, les données stockées sur cet ordinateur et dans votre compte Google demeureront à ces deux emplacements. Toutefois, les nouvelles données ou les modifications apportées au contenu existant ne seront pas synchronisées. -+Le certificat du serveur ne correspond pas à l'URL. -+Commune -+Impossible d'activer les plug-ins désactivés par une stratégie d'entreprise. -+Ne pas afficher sur cette page -+Méthodes EAP en Wi-Fi expérimentales -+Disque dur -+Nouveau dossier -+intégration sur -+Autorité de certification de messagerie -+Cache CSS -+En haut à gauche -+Saisissez le nom du nouveau dossier. -+L'extension de renégociation SSL était introuvable lors de la négociation sécurisée. Avec certains sites, connus pour leur prise en charge de l'extension de renégociation, Google Chrome exige une négociation mieux sécurisée afin de prévenir certaines attaques. L'absence de cette extension suggère que votre connexion a été interceptée et manipulée au cours du transfert. -+Petit problème... Une erreur de communication avec le réseau est survenue lors de la tentative d'inscription de ce périphérique. Veuillez vérifier votre connexion réseau et réessayer. -+pause -+Afficher tous les téléchargements... -+Connexion à -+Impossible de résoudre l'adresse DNS du serveur. -+En attente de l'affichage du cache -+Thèmes -+Impossible de se connecter au serveur proxy. -+Ignorer la synchronisation des données chiffrées ? -+Oui -+Nombre de suggestions par page -+Modifier le code PIN -+Un problème est survenu lors de la copie de l'image de récupération sur le périphérique. -+ jours restants -+La connexion Internet a été interrompue. -+Début -+« Précédent -+C&opier l'URL de la vidéo -+Vos données sur et -+Langue -+Mappages des stratégies de certificat -+ minutes restantes -+Sélectionner la position -+Le site Web à l'adresse contient des éléments provenant de sites signalés comme étant des sites de phishing. Ces derniers incitent les internautes à divulguer leurs informations personnelles en se faisant passer pour des institutions de confiance, telles que des banques. -+ -+Hors de portée -+Effacer l'historique de navigation -+Aucune page Web trouvée à l'adresse : -+Nouveau moteur de recherche : -+Jamais pour ce site -+ jours restants -+Impossible d'accéder au réseau. -+Modifier l'adresse -+&Masquer le panneau de la vérification orthographique -+1 cookie -+Activer ces fonctionnalités... -+ secondes restantes -+Cou&per -+Fermer la barre de recherche -+Signataire de la liste de révocation de certificats -+Afficher des informations à propos du site -+UC -+Fermer les pages -+MSPY -+ () -+Très petite -+Afficher les réseaux privés dans le menu Réseau pour activer la connexion à un VPN -+Vérification de la mise à jour du système... -+L'entrée demandée est introuvable dans le cache. -+Connectez-vous à pour importer le certificat client. -+Modifier la mise en page -+Se déconnecter -+Espace insuffisant. -+Préférences synchronisées -+Imp&rimer le cadre... -+MSCHAP -+Continuer à bloquer les images -+Lorsqu'un site utilise des plug-ins : -+Échec d'exportation de la clé publique -+Choisir les éléments à synchroniser -+Paramètres de saisie du Pinyin -+Ouvrir les pages suivantes : -+Déconnexion -+Moteurs de recherche -+Erreur de suppression de certificat -+Ne rien faire -+Épingler l'onglet -+réinitialiser la synchronisation -+PKCS #1 SHA-256 avec chiffrement RSA -+Katakana -+Choisir un réseau mobile -+&Historique -+Mode développeur : -+Lien -+Système -+Sélectionnez le fichier de clé privée. -+Insérez une carte SD ou une carte mémoire USB. -+Temps restant : -+Cliquez ici pour exécuter le plug-in . -+Hanyu -+pages -+Configuration en cours -+Erreur inconnue -+ days ago -+La langue utilisée pour Google Chrome est passée de "" à "" après la synchronisation de vos paramètres. -+&Aucune suggestion orthographique -+Erreur de protocole SSL -+Mode de saisie du thaï (clavier Pattachote) -+Ce compte utilisateur n'est pas compatible avec ce service. -+ ne peut pas être exécuté en tant que root. -+C&oller -+Paramètres de contenu... -+Dimensions de l'image -+Sélectionner le fichier à enregistrer sous -+Disque Flash -+Moteur de recherche actuel : -+L'identité de situé à a été vérifiée par . -+Version de l'autorité de certification Microsoft -+Enregistrer une capture d'écran -+Page sur -+Console &JavaScript -+Réponse reçue incorrecte lors de la tentative de chargement de . -+ Cela peut être dû à une opération de maintenance ou à une configuration incorrecte sur le serveur. -+Serveur DNS : -+Pré-rendu : -+Impossible d'accéder à la bibliothèque réseau. -+Des images ont été bloquées sur cette page. -+Toujours autoriser à afficher les images -+Copier l'adr&esse du lien -+Ouvrir dans une fenêtre de navigation privée -+Mode développeur -+Chiffrement des données -+Activer la protection contre le phishing et les logiciels malveillants -+Appuyez sur pour rechercher sur -+Voulez-vous utiliser () au lieu de pour gérer les liens :// à partir de maintenant ? -+Démarrer une session en tant qu'invité -+Nombre maximal de caractères chinois dans la mémoire tampon de pré-édition, notamment les entrées de symboles Zhuyin -+Barre de menus GNOME expérimentale disponible -+Effacer l'historique des téléchargements -+Navigateur bloqué... -+Parenthèse drte -+Calcul du temps de chargement -+Ajouter une carte de paiement... -+Itinérance : -+Arrêter -+Erreur de synchronisation... -+ID de clé de l'autorité de certification -+Extensions -+Imprimez où que vous soyez. -+Un problème est survenu lors du téléchargement de l'image de récupération. -+Cloud Print Proxy -+Une erreur s'est produite lors de la configuration de la synchronisation. -+Fichiers personnalisés -+Impossible de définir le mode une fois la fenêtre créée. -+Date et heure -+Personnaliser les préférences de synchronisation -+Aucune information disponible sur le forfait -+Signaler un problème -+Importer mes favoris et paramètres -+Sélectionnez le menu clé à molette > Paramètres > Options avancées > Modifier les paramètres du proxy et vérifiez que vos paramètres sont définis sur "sans proxy" ou "direct". -+Fermer et annuler les téléchargements -+Autres moteurs de recherche -+ peut maintenant synchroniser vos mots de passe. Pour protéger vos données, vous devez confirmer les informations relatives à votre compte. -+Cette fonctionnalité active les API P2P Pepper et P2P JavaScript. L'API est en cours de développement et n'est pas encore opérationnelle. -+L'identité de ce site Web n'a pas été vérifiée. -+Sessions à l'étranger -+Cette page répertorie tous les modules chargés dans le processus principal et les modules enregistrés de manière à être chargés ultérieurement. -+Afficher les &infos sur le cadre -+Connecté -+Paramètres d'entrée en Chewing -+Conserver sur cette page -+Votre support de récupération est prêt. Vous pouvez le retirer du système. -+Copi&er l'adresse e-mail -+Interdire à tous les sites d'afficher des fenêtres pop-up (recommandé) -+Console &JavaScript -+Empêcher cette page de générer des boîtes de dialogue supplémentaires -+En haut à droite -+Entrez le mot de passe associé à votre application : -+Mode de saisie Google du japonais (pour clavier japonais) -+ est à jour () -+Le serveur a mis fin à la connexion de manière inattendue. -+Il est possible que le serveur hébergeant la page Web soit surchargé ou ait rencontré une erreur. Pour éviter de générer -+ trop de trafic et d'aggraver la situation, -+ a temporairement -+ bloqué l'acceptation des requêtes adressées au serveur. -+ -+ Si vous pensez que ce comportement n'est pas souhaitable, (par exemple, dans le cas où vous déboguez votre propre site Web), vous pouvez -+ consulter la page , -+ sur laquelle vous pourrez trouver plus d'informations ou désactiver cette fonctionnalité. -+Gestionnaire de &fichiers -+Arrêter la synchronisation du compte -+Ajouter -+Sélectionnez le fichier à ouvrir -+Aucun forfait de données -+Créer un compte Google -+Code postal -+&Gestionnaire de tâches -+Téléphone -+Sélectionner l'onglet précédent -+Sélectionner un certificat -+Mots de passe enregistrés -+Autoriser l'accès aux URL de fichier -+Modifi&er les moteurs de recherche... -+Gérer les moteurs de recherche... -+PKCS #7, chaîne de certificats -+Clé pré-partagée : -+Contrôlez et partagez l'accès à vos imprimantes depuis n'importe quel compte Google. -+Ajoute l'option "Utiliser les onglets latéraux" au menu contextuel de la barre d'onglets. Utilisez cette option pour déplacer les onglets du haut de l'écran (affichage par défaut) vers le côté. Particulièrement utile sur les grands écrans. -+S'inscrire -+, -+Saisissez un nouveau nom. -+ ne peut pas être affiché dans cette langue. -+Erreur : impossible de décoder l'extension. -+Clavier bulgare -+Accès aux informations de l'autorité -+Ajouter un réseau privé... -+C&opier l'URL du fichier audio -+Masque de sous-réseau : -+Impossible d'accéder à votre compte ? -+Utiliser les touches - et = pour paginer une liste d'entrées -+Le serveur ne prend pas en charge l'extension de renégociation TLS. -+Résolution de l'hôte... -+Récemment fermés -+Le certificat de sécurité du site a été signé avec un algorithme de signature faible. -+Votre mot de passe a été modifié -+Gérer les paramètres de saisie automatique... -+La page Web n'est pas disponible pour le moment. Cela peut être dû à une surcharge ou à une opération de maintenance. -+Éjecter -+Impossible de lancer le processus de service. -+ Mo restants -+Nouvelle fenêtre -+Sélectionnez -+ -+ Applications > Préférences système > Réseau > Avancé > Proxys -+ -+ et désélectionnez les serveurs proxy sélectionnés. -+Gravure en cours d'initialisation... -+Téléchargement de l'image de récupération... -+il y a  minutes -+Mode de saisie du chinois (cangjie) -+Comté -+Ouvrir l'adresse dans un nouvel onglet -+&Rouvrir l'onglet fermé -+Impossible d'afficher la page Web, car votre ordinateur est passé en mode -+ veille ou hibernation. Dans ce cas, les connexions réseau sont -+ coupées et les requêtes réseau échouent. L'actualisation de la page -+ devrait permettre de résoudre ce problème. -+Certificat utilisateur : -+Autoriser -+Appuyer sur Entrée pour revenir en arrière et sur la touche de menu contextuel pour afficher l'historique -+ZRM -+Cookies et autres données -+Page(s) ne répondant pas -+Paramètres d'entrée hangûl -+Configurer la synchronisation... -+Modules (). Conflits connus : , conflits probables : -+Date de renouvellement du certificat Netscape -+Ouvrir tous les favoris dans une nouvelle fenêtre -+bouton radio concernant l'étendue de pages -+Saisissez votre mot de passe -+ est conçu pour rendre l'impression plus intuitive, accessible et utile. vous permet de rendre vos imprimantes accessibles depuis n'importe quelle application Web ou mobile associée à . -+Dictionnaire de kanji unique -+Rétablir tous les onglets -+Échec de l'installation de l'extension -+En savoir plus sur la manière de se protéger des logiciels malveillants en ligne -+Toujours afficher les fenêtres pop-up de -+Authentification phase 2 : -+Aucun résultat de recherche trouvé -+Ouvrir une fois le téléchargement &terminé -+ cookies -+Mode de saisie du japonais (pour clavier américain) -+Continuer à bloquer les plug-ins -+Épingler sur la barre des tâches -+Les certificats ont une période de validité, comme tous les documents relatifs à votre identité (tel qu'un passeport). Le certificat présenté à votre navigateur n'est pas encore valide ! Lorsqu'un certificat est en dehors de sa période de validité, il n'est pas nécessaire d'assurer la maintenance de certaines informations relatives à son état (s'il a été révoqué ou s'il n'est plus approuvé). Par conséquent, il est impossible de vérifier que le certificat est fiable. Ne poursuivez pas. -+Fermer la session d'invité -+Contrôlez vos tâches d'impression et l'état de connexion de vos imprimantes en ligne. -+Désinstallation -+Empreinte SHA-1 -+Modifier le code PIN de la carte SIM -+État du réseau : -+sans limite -+(Choisir une autre capture d'écran) -+Désactivation -+Aucune erreur n'a été signalée récemment. Les erreurs n'apparaissent ici que lorsque l'envoi de rapports d'erreur est activé. -+Rouvrir les dernières pages ouvertes -+Ouvrir en mode plein écran -+Ajouter une carte de paiement -+Désactivé -+Chargement des informations sur votre forfait Internet mobile, veuillez patienter... -+Acheter un forfait de données... -+Inclure cet e-mail : -+Le titre doit comporter au moins un caractère. -+Espaces de noms réseau -+ n'a pas pu terminer l'installation, mais va poursuivre son exécution à partir de son image disque. -+Gestion des services Internet mobiles -+Utiliser les onglets latéraux -+Non -+Saisir le code PIN de la carte SIM -+&Afficher dans le Finder -+Maintenez la touche Ctrl, Alt ou Maj enfoncée<br>pour afficher le raccourci clavier qui lui est associé. -+Vraiment désolé, aucun prototype n'est disponible pour le moment. -+&Afficher dans le Finder -+Informations relatives au certificat -+/ -+La synchronisation des mots de passe requiert votre attention. -+Veuillez saisir l'ancien et le nouveau code PIN. -+Langue : -+Résultats de recherche -+Serveur SSL avec fonction d'optimisation -+Enregistrer en PDF -+Mémoire USB détectée -+M'avertir lorsque le flux de données est faible ou presque inexistant -+Saisir le mot de passe multiterme -+Clavier lituanien -+Les éléments saisis dans le champ polyvalent peuvent être enregistrés. -+Les informations de connexion à votre compte sont obsolètes. Cliquez ici pour saisir à nouveau votre mot de passe. -+Vietnamien -+feuilles de papier -+URL de mot de passe perdu Netscape -+Rouvrir l'onglet fermé -+Effacer les mots de passe enregistrés -+Créer un nouveau dossier... -+Basculer en mode ponctuation pleine chasse ou demi-chasse -+Gérer les paramètres de localisation... -+Synchronisé... -+Options de recherche par défaut -+Aucune sélection -+Mode de saisie du vietnamien (TELEX) -+ minute restante -+Le nombre maximal d'autorités de certification intermédiaires a été dépassé : -+Saisissez un mot de passe pour chiffrer ce fichier de certificat. -+Organiser -+Votre mot de passe a changé. Veuillez réessayer avec votre nouveau mot de passe. -+PKCS #1 MD5 avec chiffrement RSA -+Utiliser le thème classique -+Échap efface toute la mémoire tampon de pré-édition -+Ajouter aux favoris -+Un incident est survenu sur une partie de cette page (HTML WebWorker). Elle risque de ne pas fonctionner correctement. -+Clavier américain -+Signataire de code -+Adobe Reader n'est pas à jour et risque de ne plus être sécurisé. -+Personnaliser les paramètres de synchronisation... -+Co&ller et rechercher -+Détails du certificat sélectionné : -+Impossible de se connecter -+Activation : -+Système de révocation introuvable dans le certificat du serveur -+Numéro de série -+Afficher la page "Nouvel onglet" -+il y a  heure -+Votre ordinateur redémarrera une fois la mise à jour effectuée. -+Verr. maj. -+L'accès au répertoire de l'hôte de communication à distance a été refusé. Essayez avec un autre compte. -+Accessible aux scripts : -+Cette page place des cookies. -+Proxy -+Avec sous-menu -+Afficher dans le dossier -+il y a  minutes -+<saisir une requête> -+Appuyez sur pour envoyer des commandes à . -+Prévisualiser le rapport -+Activer le dernier onglet -+Lorsque je quitte le navigateur -+Continuer sans mettre à jour Adobe Reader (non recommandé) -+Le champ de mot clé doit être vide ou comporter un mot unique -+Déplacer le curseur automatiquement au caractère suivant -+Enregistrer -+Ouvrir le lien dans un nouvel ongle&t -+Nouvelle fenêtre de navigation privée -+Celtique -+Réinitialiser le zoom -+Prototypes -+Mémoriser mes choix pour tous les liens de ce type -+Les plug-ins de cette page ont été bloqués. -+Site -+Sélectionner -+Couper -+Restaurer toutes les miniatures supprimées -+Utiliser les onglets latéraux -+Se connecter au dispositif de sécurité -+Enregistrer le fichier -+Pages -+Options de -+Barre de lancement rapide -+Annuler -+Choisir un fichier -+&Rechercher avec -+(pas encore valide) -+Mettre à jour le plug-in... -+Police Sans-Serif -+Impossible de charger le JavaScript "" du script de contenu. -+Connexion... -+Mots de passe -+Fichiers PKCS #12 -+Options de saisie automatique de -+Fenêtre précédente -+Astuce -+ / fichiers -+Localisation utilisée, mais les paramètres régionaux par défaut (default_locale) n'ont pas été indiqués dans le manifeste. -+Si vous n'êtes pas à l'origine de cette requête, il s'agit probablement d'une attaque contre votre système. Si vous n'avez pas lancé cette requête de manière intentionnelle, cliquez sur Ne rien faire. -+Votre commentaire a bien été envoyé. -+Fonction d'optimisation internationale Netscape -+Taille de police minimale -+Suivant -+Utilitaire : -+Cette opération peut prendre une minute... -+Le format du mot de passe est incorrect. -+Chargement... -+Ajouter la page... -+Masquer ce plug-in -+&Paramètres linguistiques... -+Créer un support de récupération du système d'exploitation -+Le fichier de clé privée est incorrect. -+Valeur : -+Stable -+Grande -+Certificat serveur invalide -+Jamais enregistrés -+Cette page a été préchargée. -+Google Chrome ne peut pas afficher l'aperçu avant impression lorsque la visionneuse de documents PDF intégrée est désactivée. Pour l'afficher, veuillez accéder à chrome://plugins, activer "Chrome PDF Viewer" et réessayer. -+Nouveau ! -+Vous êtes passé en navigation privée. Les pages que vous consultez dans cette fenêtre n'apparaîtront ni dans l'historique de votre navigateur, ni dans l'historique des recherches, et ne laisseront aucune trace (comme les cookies) sur votre ordinateur une fois que vous aurez fermé la fenêtre de navigation privée. Tous les fichiers téléchargés et les favoris créés seront toutefois conservés. Passer en navigation privée n'a aucun effet sur les autres utilisateurs, serveurs ou logiciels. Méfiez-vous : Des sites Web qui collectent ou partagent des informations vous concernant Des fournisseurs d'accès Internet ou des employeurs qui conservent une trace des pages que vous visitez Des programmes indésirables qui enregistrent vos frappes en échange d'émoticônes gratuites Des personnes qui pourraient surveiller vos activités Des personnes qui se tiennent derrière vous En savoir plus sur la navigation privée -+Le certificat du serveur a été révoqué. -+&Reprendre -+Sélectionnez un réseau : -+Impossible d'extraire les fichiers de l'extension. Pour effectuer cette opération en toute sécurité, vous devez disposer d'un chemin d'accès à votre répertoire de profils ne contenant pas de lien symbolique. Aucun chemin de ce type n'existe pour votre profil. -+Effacer les données de navigation -+Si vous êtes conscient que la visite de ce site peut être préjudiciable à votre ordinateur, vous pouvez . -+Votre périphérique est inscrit pour bénéficier de la gestion d'entreprise. -+Serveur de mise à jour non disponible (erreur : ) -+Module client natif : -+Rechercher sur  : -+Style de symboles -+ hours -+Département -+Continuer à utiliser -+OK -+Essayez de désactiver les prédictions d'actions du réseau en procédant comme suit : -+ Sélectionnez le -+ -+ menu clé à molette > -+ -+ > -+ -+ -+ et désélectionnez "". -+ Si le problème n'est pas résolu, nous vous conseillons de sélectionner de nouveau -+ cette option pour améliorer les performances. -+Date -+Sélectionnez un certificat pour vous authentifier sur . -+Barre latérale -+La clé publique éphémère Diffie-Hellman associée au serveur est peu sûre. -+Rechercher dans Dictionnaire -+Sélectionnez un moteur de recherche -+Clavier russe -+Nom Microsoft principal -+Clavier polonais -+Clavier serbe -+ minute -+Erreur lors de la lecture des données du cache. -+Canary -+Commentaire du certificat Netscape -+Page suivante -+ est à jour. -+Paramètres de saisie automatique... -+Tout ramener au premier plan -+Sélectionner le dossier à ouvrir -+Activer le mode Pinyin fuzzy -+Résolution du proxy... -+Le téléchargement de l'image a été interrompu. -+Eten 26 -+URI -+Clavier Dvorak américain -+Rechercher sur le Web... -+Si vous utilisez un serveur proxy, vérifiez les paramètres associés ou demandez à votre administrateur réseau -+ si ce serveur fonctionne. -+Impossible de charger l'icône de l'extension "". -+Définir un proxy pour se connecter au réseau -+zone de texte concernant l'étendue de pages -+Activation -+Clavier Dvorak britannique -+ jours -+MS-IME -+Aucun forfait de données -+Les fenêtres pop-up suivantes ont été bloquées sur cette page : -+ heures restantes -+Impossible de charger le modèle du favori. -+Échec d'exportation de la clé privée -+Utiliser comme page d'accueil -+Compte -+Plein écran -+Autoriser tous les sites à suivre ma position géographique -+Si la restauration du système d'exploitation de votre ordinateur s'avère nécessaire, une carte SD ou une clé USB de récupération vous sera demandée. -+Les cookies suivants ont été bloqués : -+Inclure les adresses de ma fiche de Carnet d’adresses -+Le certificat de sécurité du site n'est pas approuvé ! -+Votre liste d'applications, d'extensions et de thèmes installés -+Exécuter tous les plug-ins de cette page -+Augmente la taille du texte -+Accepter et continuer » -+Fichiers -+ -+Appliquer uniquement à cette session de navigation privée -+Latin large -+Exécuter ce plug-in -+MasterCard -+Sur le Web, Tab permet de sélectionner les liens, ainsi que les champs de formulaire. -+À propos de -+Paramètres de sécurité du système -+Images -+Cyrillique -+Pas maintenant -+Attendre la fin du téléchargement -+Thème "" installé -+&Supprimer -+Menu Démarrer -+&Zoom -+Transfert en cours ( %)... -+Géré par -+&Rafraîchir -+Configuration du module de plate-forme sécurisée (TPM) en cours. Veuillez patienter, cela peut prendre quelques minutes. -+Vous avez acheté une quantité illimitée de données le . -+Confirmer avant de quitter () -+Mémoire partagée -+Rech. dans les paramètres -+mot de passe d'accès au réseau -+Activer la vérification orthographique -+Types de données -+Bloquer -+Certificat de l'autorité de certification du serveur : -+Clavier grec -+Taille réelle -+Toujours en haut -+Aucun plug-in installé. -+Alerte JavaScript -+Autoriser en mode navigation privée -+Rétablir -+, expire le : -+Confirmer la désinstallation -+Impossible de désactiver les plug-ins ayant été activés par une stratégie d'entreprise. -+Cette fonctionnalité active l'option "Lire en un clic" dans les paramètres de contenu du plug-in. -+Attendre la fin des téléchargements -+Synchronisation -+&Rouvrir l'onglet fermé -+Votre mot de passe de compte Google a changé depuis votre dernière connexion à partir de cet ordinateur. -+Le fichier contenait plusieurs certificats, aucun d'eux n'a été importé : -+Afficher le bouton -+La saisie dans le champ polyvalent d'une URL déjà ouverte dans un autre onglet entraîne l'affichage de l'onglet en question, et non l'affichage de l'URL dans l'onglet actuel. -+Configuration en cours... -+Rechercher dans les téléchargements -+Me demander lorsqu'un site tente de suivre ma position géographique (recommandé) -+La nouvelle version de "" a été désactivée, car elle nécessite davantage d'autorisations. -+Clavier phonétique russe -+American Express -+Ce serveur exige un certificat d'authentification et n'a pas accepté celui envoyé par le navigateur. -+Votre certificat a peut-être expiré ou le serveur n'a pas approuvé l'émetteur. -+Réessayez avec un autre certificat si vous en avez un. -+Sinon, vous devrez en obtenir un nouveau d'un autre émetteur. -+Lorsque vous vous connectez à un site Web sécurisé, le serveur hébergeant ce site présente à votre navigateur un "certificat" afin de vérifier l'identité du site. Ce certificat contient des informations d'identité, telles que l'adresse du site Web, laquelle est vérifiée par un tiers approuvé par votre ordinateur. En vérifiant que l'adresse du certificat correspond à l'adresse du site Web, il est possible de s'assurer que vous êtes connecté de façon sécurisée avec le site Web souhaité et non pas avec un tiers (tel qu'un pirate informatique sur votre réseau). -+À l'instant -+Votre carte SIM sera définitivement désactivée si vous ne saisissez pas correctement la clé de déverrouillage du code PIN. Nombre de tentatives restantes : -+ / octets, Interrompu -+Importés depuis Firefox -+Détection automatique -+&Aide -+Les codes PIN sont différents ! -+Contenu Web -+Vider le cache -+Rétablir le thème par défaut -+Le service de communication à distance a démarré correctement. Vous devriez maintenant pouvoir vous connecter à distance à cet ordinateur. -+Outils de développement -+Police Serif -+Copier -+Adresse e-mail ou mot de passe incorrect. Veuillez réessayer. -+Le plug-in suivant ne répond pas : souhaitez-vous interrompre ? -+Sens -+ secondes -+Clavier tchèque -+Voulez-vous que "" soit considérée comme une autorité de certification fiable ? -+Gestionnaire de sécurité natif du client -+<p>Lorsque vous exécutez dans un environnement de bureau pris en charge, les paramètres proxy du système sont utilisés. Toutefois, soit votre système n'est pas pris en charge, soit un problème est survenu lors du lancement de votre configuration système.</p> -+ -+ <p>Vous avez toujours la possibilité d'effectuer la configuration via la ligne de commande. Pour plus d'informations sur les indicateurs et les variables d'environnement, veuillez vous reporter à <code>man </code>.</p> -+La page Web à l'adresse a déclenché trop de redirections. Pour résoudre le problème, effacez les cookies de ce site ou autorisez les cookies tiers. Si le problème persiste, il peut être dû à une mauvaise configuration du serveur et n'être aucunement lié à votre ordinateur. -+SSID : -+Nom du forfait : -+Adresse X.400 -+Fermer l'onglet -+Impossible de trouver un navigateur pris en charge. -+Le compte associé à la boutique en ligne est le suivant : . L'utilisation d'un autre compte pour la synchronisation provoque des erreurs. -+Enregistrer la p&age sous... -+ importe actuellement les éléments suivants à partir de  : -+Appuyez sur Entrée pour avancer et sur la touche de menu contextuel pour afficher l'historique -+Actualiser le cadre -+Annulé -+Autorités -+Sélectionnez votre clavier : -+Signaler un problème... -+Ignorer ce réseau -+Nouveau matériel détecté -+Vous disposez de certificats qui n'appartiennent à aucune autre catégorie : -+&Profilage activé -+(Navigation privée) -+&Nouveau dossier -+Types MIME : -+Afficher les pages en arrière-plan () -+Fichiers audio -+Plug-ins -+Plus d'informations... -+Se connecter automatiquement à ce réseau -+Titulaire de la carte -+Elle peut désormais accéder à : -+Noir et blanc -+Ignorer la connexion et naviguer en tant qu'invité -+Toutefois, cette page inclut d'autres ressources qui ne sont pas sécurisées. Ces ressources peuvent être consultées par des tiers pendant leur transfert, et modifiées par un pirate informatique dans le but de changer l'aspect et le comportement de cette page. -+Accès réseau interrompu -+La dernière version de l'extension "" requiert d'autres permissions. Elle a donc été désactivée. -+Dans ce cas, le certificat du serveur ou un certificat d'autorité intermédiaire présenté à votre navigateur n'est pas valide. Cela peut signifier que le certificat est incorrect, qu'il contient des champs non valides ou qu'il n'est pas compatible. -+Veuillez saisir la clé de déverrouillage du code PIN à 8 chiffres fournie par . -+Exceptions... -+Connexion à -+Voulez-vous vraiment quitter alors qu'un téléchargement est en cours ? -+Le site Web ne parvient pas à gérer la demande associée à . -+Précédent -+&Arrêter -+Lorsque l'option permettant de bloquer l'enregistrement des cookies tiers est activée, la lecture de ces cookies est également bloquée. -+ : -+Console JavaScript -+Les sites pour lesquels vos mots de passe ne seront jamais enregistrés s'afficheront ici. -+Inconnu -+Mode de saisie du thaï (clavier TIS-820.2538) -+&Favoris -+Désinstaller -+Voulez-vous vraiment quitter alors que  téléchargements sont en cours ? -+Configurer le blocage des cookies... -+ABC -+L'application hébergée par est inaccessible, car vous êtes déconnecté du réseau. Cette page s'affichera dès que la connexion réseau sera rétablie. <br> -+Gestionnaire de favoris -+ secs ago -+Quitter le mode plein écran -+Ouvrir l'&image dans un nouvel onglet -+Favori ajouté ! -+Choisir un autre dossier... -+Kotoeri -+Hier -+Synchroniser automatiquement les éléments suivants : -+Votre ordinateur intègre un périphérique de sécurité TPM (module de plate-forme sécurisée) qui permet de mettre en œuvre plusieurs fonctionnalités de sécurité critiques dans Google Chrome OS. -+Contraintes des stratégies de certificat -+Créer un support de récupération -+Emplacement : -+Toutes les pages que vous consultez apparaîtront ici à moins que vous ne les ouvriez dans une fenêtre en navigation privée. Vous pouvez utiliser le bouton Rechercher de cette page pour rechercher dans toutes les pages de votre historique. -+Options pour les développeurs -+Cookies -+Toujours exécuter pour ce site -+Afficher le dossier -+Autres favoris -+Clavier français -+ ne parvient pas à déterminer ou à définir le navigateur par défaut. -+Sélectionner l'onglet suivant -+Voulez-vous vraiment supprimer ces pages de votre historique ? -+Déverrouiller -+ID de clé : -+Exécuter ce plug-in -+Utilisateurs -+Ajouter un moteur -+Répondeur OCSP : -+Ignorer -+Champs de certificat -+Modules () : aucun conflit détecté. -+Onglet : -+Impossible de charger la page d'options "". -+Coller en adaptant le style -+Veuillez ajouter une autre langue avant de supprimer celle-ci. -+nom du réseau -+ synchronise de manière sécurisée vos données avec votre compte Google. -+Taille -+Activer... -+Recherche -+Poursuivre quand même -+Nouveau code PIN : -+La capacité du périphérique doit être d'au moins 4 Go. -+De droite à gauche -+Activer le mode Pinyin double -+Menu contenant des favoris masqués -+Utiliser le dictionnaire système -+Vous avez choisi de chiffrer les données à l'aide de votre mot de passe Google. Vous pouvez modifier vos paramètres de synchronisation à tout moment, si vous changez d'avis. -+Personnaliser les polices... -+Enregistrement des informations de date -+&Vérifier l'orthographe du texte de ce champ -+Ceci est un modèle expérimental qui permet aux enregistrements DNS (utilisant le protocole de sécurité DNSSEC) d'autoriser ou de refuser des certificats HTTPS. Ce message s'affiche lorsque vous activez des fonctionnalités expérimentales via des options de ligne de commande. Vous pouvez supprimer ces options de ligne de commande pour ignorer cette erreur. -+ minutes restantes -+Île -+Contraintes de base du certificat -+Autres... -+Activer l'onglet 4 -+Données personnelles -+Afficher l'original -+Nom de la société -+Définir Adobe Reader comme visionneuse de documents PDF par défaut ? -+Pour gérer les extensions installées, cliquez sur Extensions dans le menu Fenêtre. -+Accédez à vos imprimantes depuis n'importe quel ordinateur ou smartphone. En savoir plus -+Me &le rappeler plus tard -+Opération réussie ! -+Carte SD détectée. -+ - Propriétaire -+Clavier japonais -+WPA -+janv.^févr.^mars^avr.^mai^juin^juil.^août^sept.^oct.^nov.^déc. -+Sélectionnez -+ -+ Applications > Préférences système > Réseau > Assistant -+ -+ pour tester votre connexion. -+&Afficher le code source de la page -+Micrologiciel : -+Créer un profil -+Date de modification -+Sandbox seccomp -+Signale&r un problème... -+Entrée de symboles simplifiée -+Chinois simplifié -+Hôte SOCKS -+Considérer ce certificat comme fiable pour identifier les sites Web. -+Exceptions de localisation -+Hiragana -+Le mot de passe TPM ci-dessous, généré de façon aléatoire, a été attribué à votre ordinateur : -+Importer mes favoris maintenant... -+ -+Avertissement : Un problème a été détecté sur cette page. -+Avec Google Chrome OS for business, vous pouvez connecter votre périphérique à Google Apps, ce qui vous permet de le rechercher et de le contrôler depuis le panneau de configuration de Google Apps. -+Ajouter tous les onglets aux favoris... -+Émis le -+Lorsque je ferme le navigateur -+Localisation -+Attendre -+Infos sur la clé publique de l'objet -+Plug-in inconnu -+Connexion en mode invité -+Toujours autoriser à paramétrer les cookies -+Résumé -+Le certificat du serveur n'est pas valide. -+Chaîne de certificats codés Base 64 ASCII -+Choisir mon propre mot de passe multiterme -+Certificat de serveur non répertorié -+Rechercher la sélection -+Activer -+L'accès à ce réseau est protégé. -+E-mail -+Erreur () : -+Signature permanente Microsoft -+Sélectionnez -+ -+ Démarrer > Panneau de configuration > Réseau et Internet > Centre Réseau et partage > Résolution des problèmes (en bas) > Connexions Internet. -+ -+Gestionnaire de &fichiers -+Service client -+Impossible de se connecter au réseau "". -+J'accepte ces termes -+Copier l'adr&esse du lien -+Veuillez démarrer en tant qu'utilisateur normal. Pour l'exécuter en tant que root, vous devez indiquer un autre répertoire de données utilisateur pour stocker les informations du profil. -+Le processus du connecteur est bloqué. Voulez-vous le redémarrer ? -+Contenu Web -+Clé compromise -+Supprimer -+Si vous fermez maintenant, ces téléchargements seront annulés. -+Dachen 26 -+Voulez-vous vraiment graver l'image sur le périphérique suivant : -+Mémoire SQLite -+/, -+ est affiché dans cette langue. -+Fenêtre pop-up bloquée -+ : -+Ouvrir tous les favoris -+Effacer les cookies et autres données de site et de plug-in lorsque je ferme le navigateur -+Page d'accueil -+Onglet -+Non configuré -+Opération réussie ! -+Relancez pour terminer la mise à jour. -+Chiffrer toutes mes données -+Veuillez patienter pendant que nous configurons votre réseau pour mobile. -+Points de distribution de listes de révocation des certificats -+Association -+Appuyez sur Maj+Alt pour changer la disposition du clavier. -+Utiliser l'horloge au format 24 heures -+ est prêt à terminer l'installation. -+Lancez votre recherche à partir d'ici -+OK, synchroniser tout -+Afin d'être correctement affichée, cette page requiert des données que vous avez précédemment entrées. Vous pouvez de nouveau transmettre ces données, mais, en procédant ainsi, vous devrez répéter chaque action que cette page a effectuée auparavant. Cliquez sur Rafraîchir pour transmettre de nouveau ces données et pour afficher cette page. -+Cela signifie que le certificat présenté à votre navigateur a été révoqué par son émetteur. L'intégrité de ce certificat a certainement été compromise, et il ne doit donc pas être approuvé. Ne poursuivez pas. -+Clavier slovaque -+Nom de partie EDI -+Vous avez déjà chiffré des données avec un mot de passe multiterme. Saisissez-le ci-dessous. -+Informations sur le site -+Créer un raccourci vers l'application... -+Authentification requise -+ n'est pas parvenu à se connecter à . Sélectionnez un autre réseau ou réessayez. -+Votre compte n'est pas compatible avec . Contactez l'administrateur de votre domaine ou utilisez un compte Google standard pour vous connecter. -+Adresse e-mail -+Client natif -+Chargé depuis : -+Active les balises canvas hautes performances dans un contexte 2D, pour effectuer le rendu via le processeur graphique. -+Cette page ena été traduite en -+Seule une personne en possession de votre mot de passe multiterme peut lire vos données chiffrées. Google ne reçoit ni n'enregistre votre mot de passe multiterme. Si vous oubliez votre mot de passe multiterme, vous devrez -+Autorité de certification SSL -+ contient un logiciel malveillant. Votre ordinateur pourrait être infecté par un virus si vous consultez ce site. -+Aucune donnée disponible. -+Im&primer... -+Description -+Voix non reconnue. -+Aucun fichier sélectionné -+Souhaitez-vous installer  ? -+Activité récente -+de la dernière semaine -+Profil -+Actualiser sans utiliser le cache -+Logiciels malveillants et sites de phishing détectés ! -+Onglet fermé ! -+il y a  jours -+Paramètres -+Ce site exige que vous vous identifiiez avec un certificat : -+Supprimer... -+&Aucune suggestion orthographique -+Clavier franco-canadien -+Clavier étendu américain -+Le serveur a mis fin à la connexion sans envoyer de données. -+Autoriser à afficher des notifications sur le Bureau ? -+Pour gérer les extensions installées, cliquez sur Extensions dans le menu Outils. -+Erreur de synchronisation, veuillez vous connecter à nouveau. -+La liste suivante fait état des éléments dangereux détectés sur la page. Cliquez sur le lien "Diagnostic" pour obtenir plus d'informations sur un élément particulier. -+Émirat -+Synchroniser tous les paramètres et toutes les données\n(peut prendre un certain temps) -+Toujours demander où enregistrer les fichiers -+Créer un raccourci -+Tous les fichiers -+Sebeol-sik No-shift -+Anglais (pleine chasse) -+2D avec canvas et accélération matérielle -+Cette fonctionnalité autorise l'installation d'applications Google Chrome déployées à partir d'un manifeste situé sur une page Web, plutôt qu'avec un fichier crx contenant le manifeste et les icônes. -+Nouvelle connexion -+GPU -+Moins de 1 Mo disponible -+Nouvelle fenêtre de navigation privée -+Europe du Sud -+Sélectionner les éléments à synchroniser -+Attributs du répertoire de l'objet du certificat -+Accédez à vos imprimantes et partagez-les en ligne via . -+&Ajouter... -+Afficher dans cette langue -+il y a  jour -+Police Sans-Serif -+Ne rien faire -+ seconde -+Configurer les mises à jour automatiques pour tous les utilisateurs -+Échec de la création du répertoire des données -+Fermer et annuler le chargement -+ -+Adresse : -+Détails -+Notification : -+Cette opération peut prendre quelques minutes. -+Géré par () -+Type de certificat Netscape -+Impossible d'afficher certaines parties de ce document PDF. Souhaitez-vous installer Adobe Reader ? -+Vos certificats -+Vos données personnelles sur , et -+URL de stratégie de l'autorité de certification Netscape -+Dernier accès : -+Synchroniser les mots de passe -+&Quitter -+&Fermer l'onglet -+, -+Le site Web à l'adresse contient des éléments provenant de sites qui semblent héberger des logiciels malveillants. Ces derniers peuvent nuire à votre ordinateur ou agir à votre insu. Le simple fait de visiter un site hébergeant ce type de logiciels peut infecter votre ordinateur. -+Total : -+Les cookies de plusieurs sites ont été autorisés pour la session uniquement. -+Nom du service : -+Imprimer une page de test -+Aperçu avant impression - -+ -+ ne peut pas à afficher la page Web, car votre ordinateur n'est pas connecté à Internet. -+Exécuter cette fois -+Chiffrement de la clé -+Échec de la vérification AAA -+Ouverture dans ... -+&Copier -+Logiciel -+Moteurs de recherche -+&Méthodes d'entrée -+Jamais enregistrés -+Impossible d'analyser le fichier. -+Subordination qualifiée Microsoft -+Bureau -+Toujours traduire en les pages en -+Thaï -+Activer l'onglet suivant -+: de chargement -+Style de mappage du clavier -+Un problème lié à votre microphone s'est produit. -+ vous permet d'accéder aux imprimantes de cet ordinateur, où que vous soyez. Connectez-vous pour l'activer. -+District -+Ethernet -+Erreur de réseau inconnue. -+Nom du certificat -+Plus d'informations -+Mise à jour du système disponible. Préparation du téléchargement… -+Galerie des thèmes Google Chrome -+Copi&er l'adresse e-mail -+Activer l'onglet 3 -+Adresses -+Plug-in : () -+Pas maintenant -+Pays -+<Ne fait pas partie du certificat> -+il y a  seconde -+Fichiers image -+Europe centrale -+Certificat client SSL -+Pour accélérer l'affichage des pages Web, -+ -+ enregistre temporairement les fichiers téléchargés sur le disque. Si -+ -+ ne s'arrête pas correctement, ces fichiers peuvent être endommagés, ce qui -+ génère cette erreur. L'actualisation de la page devrait permettre de résoudre -+ ce problème ; celui-ci ne se reproduira vraisemblablement plus si l'arrêt s'effectue -+ correctement. -+ -+ Si le problème persiste, essayez de supprimer le contenu du cache. Cette -+ erreur peut aussi indiquer que le matériel est sur le point de tomber -+ en panne. -+Thème créé par -+Données de navigation -+Ajouter cette page aux favoris -+Le serveur a refusé la connexion. -+Module ( bits) :\n\n\nExposant public ( bits) :\n -+ secondes restantes -+Vous utilisez un indicateur de ligne de commande non pris en charge : . La stabilité et la sécurité en seront affectées. -+Emplacement de téléchargement -+À propos de Google Traduction -+Les lettres ne sont pas sensibles à la casse. -+Mot clé -+Connexion -+Redémarrez pour appliquer la mise à jour. -+Sélectionner un carré dans l'image -+Bases de données Web -+Codage -+Mise en route -+Utiliser les pages actuelles -+Signaler une erreur -+Recherche de réseaux en cours -+Effacer les données de navigation -+Ouvrir le lien dans une nouvelle &fenêtre -+Nom d'utilisateur -+Clavier letton -+Forcer l'actualisation de cette page -+Disposition du clavier : -+Non utilisé -+ minutes -+Chiffrement RSA PKCS #1 -+Ce n'est probablement pas le site que vous recherchez ! -+&Général -+Configurer la synchronisation -+État de connexion : -+Ancien code PIN : -+Désactiver le contrôle des liens hypertexte -+&Modifier -+Chinois -+Navigateur par défaut -+Extension en mode navigation privée : -+Mot clé : -+Un problème est survenu lors du téléchargement de l'image de récupération. La connexion réseau a été perdue. -+Votre administrateur a désactivé certaines préférences. -+Forfait de données épuisé -+Veuillez indiquer à quel niveau vous rencontrez des problèmes avant d'envoyer vos commentaires. -+Authentification du serveur WWW TLS -+Le service de synchronisation n'est pas disponible pour votre domaine. -+Modifier les paramètres du proxy... -+Cette fonctionnalité active les API des extensions expérimentales. Notez que vous ne pouvez pas mettre en ligne des extensions qui font appel aux API expérimentales dans la galerie d'extensions. -+Un logiciel malveillant a été détecté ! -+Forfait de données presque épuisé -+des dernières 24 heures -+Une fois activée, la recherche instantanée charge la plupart des pages Web dès que vous saisissez l'URL dans le champ polyvalent, avant même que vous n'appuyiez sur Entrée. Si votre moteur de recherche par défaut est compatible, toute lettre saisie dans ce champ offre de nouveaux résultats et les prédictions intégrées vous guident dans vos recherches.\n\nChaque touche utilisée fait l'objet d'une requête, par conséquent il se peut que les éléments saisies dans le champ polyvalent soient enregistrés par votre moteur de recherche par défaut.\n -+ hours left -+poursuivre quand même -+Autorisé -+Retirer l'onglet -+Moins de -+Impossible de charger l'icône "" d'action du navigateur. -+Consulter Google Dashboard -+Plus d'informations -+Ajoutez des langues puis faites-les glisser pour les classer dans l'ordre souhaité. -+ sera lancé au démarrage du système et continuera de s'exécuter en arrière-plan, même toutes les fenêtres de sont fermées. -+Non (HttpOnly) -+Saisir votre mot de passe multiterme pour la synchronisation -+Police standard -+ (par défaut) -+Cette fonctionnalité active la prise en charge du client natif. -+La puce du module de plate-forme sécurisée (TPM) est désactivée ou inexistante. -+L'index de l'onglet indiqué est incorrect. -+Nom du serveur SSL du certificat Netscape -+Est une autorité de certification -+Wi-Fi -+Connexion à -+Confirmer le mot de passe : -+Aperçu avant impression -+Clavier italien -+Impossible d'établir une connexion sécurisée à cause de l'antivirus ESET. -+(expiré) -+Voulez-vous vraiment quitter cette page ? -+Faire défiler d'une page vers le haut -+Empreintes -+Le plus récent -+ heures -+Agrandir -+La page Web est introuvable dans le cache. Certaines ressources ne sont restituées fidèlement que si elles sont extraites du cache, notamment les pages générées à partir de données que vous avez envoyées. Cette erreur peut également être due à un cache endommagé lors d'une fermeture incorrecte. Si le problème persiste, essayez d'effacer le cache. -+Le plug-in n'est plus à jour. -+Vous avez changé de position. Souhaitez-vous utiliser  ? -+EAP-TLS -+ heures -+Rafraîchir cette page -+Non-répudiation -+Extension : -+Active l'API Web audio. -+Zone de saisie de mot de passe -+Effacer les cookies et autres données de site lorsque je quitte le navigateur -+Ajouter l'option de regroupement au menu contextuel des onglets -+Version -+Latin -+Le connecteur requiert l'installation du pack Microsoft XML Paper Specification Essentials. -+Effacer les cookies et autres données de site lorsque je ferme le navigateur -+Case décochée -+Mise en page -+Saisir un nom ou une adresse -+Choix de l'image du compte -+Me montrer -+ minutes restantes -+De : -+Ouvrir un rapport de phishing -+Page de phishing -+Inspecter le pop-up -+Importer... -+Modifier la carte de paiement -+Cette langue est utilisée pour corriger l'orthographe. -+Le type d'enregistrement indiqué est incorrect. -+Forfait de données arrivé à expiration -+Exporter mes favoris... -+Clavier britannique -+Importer des favoris... -+ -+Nom d'utilisateur ou mot de passe incorrect -+&Tout sélectionner -+Erreur inconnue liée au certificat du serveur. -+Envoyer une capture d'écran enregistrée -+Émis pour : -+Page précédente -+Hsu -+Réduire -+Navigateur par défaut -+Afficher le mot de passe -+Activer les fonctionnalités d'accessibilité -+Inclure la capture d'écran actuelle : -+ - -+(cette extension est gérée et ne peut être désinstallée ni désactivée) -+OID enregistré -+Importés depuis IE -+Fichier de clé privée (facultatif) : -+Autoriser pour la session uniquement -+ mins -+Mise à jour en cours -+Aucun microphone trouvé. -+Connexion à -+ n'est pas votre navigateur par défaut. -+Forfait -+Cette page contient des éléments des sites ci-dessous qui suivent votre position géographique : -+Plusieurs profils -+Plantages -+Par défaut -+ jours -+PKCS #1 MD4 avec chiffrement RSA -+Modifier le moteur de recherche -+ minutes -+Indiquez le mot de passe approprié ci-dessus, puis saisissez les caractères figurant dans l'image ci-dessous. -+Expiration de imminente -+Activer l'onglet précédent -+Désactiver l'accès à distance -+Afficher les incompatibilités -+Carte de débit Solo -+Actualisez cette page Web ultérieurement. -+Pour utiliser cette extension, saisissez "", TAB, puis votre commande ou votre recherche. -+ synchronisera les applications installées, afin que vous puissiez y accéder en vous connectant depuis tout navigateur . -+Langues et paramètres du correcteur orthographique... -+Erreur de sécurité -+Applications -+La ressource demandée n'existe plus et aucune adresse de transfert n'est disponible. Il semble que cet état de fait soit permanent. -+Certificat unique binaire codé DER -+&Plein écran -+Fichiers vidéo -+ indique que -+ NetNanny intercepte les connexions sécurisées. En général, cela -+ ne constitue pas un problème de sécurité, car le logiciel NetNanny s'exécute souvent -+ sur le même ordinateur. Toutefois, en raison de certaines incompatibilités avec -+ les connexions sécurisées Google Chrome, vous devez configurer NetNanny -+ de manière à éviter ces interceptions. Cliquez sur le lien En savoir plus pour obtenir des instructions. -+Vos onglets et activités de navigation -+Créer -+Turc -+Une erreur s'est produite lors de la tentative d'enregistrement du certificat client. Erreur  () -+Bienvenue dans -+Sélectionner -+Nom du modèle de certificat Microsoft -+Configuration de l'adresse IP pour -+Immortalisez votre plus beau sourire et utilisez la photo comme image de compte. -+Extension créée : -+ -+ -+Mot de passe incorrect. Veuillez réessayer. -+LEAP -+Échec de la connexion aux serveurs de reconnaissance vocale. -+Très grande -+Sélectionner le répertoire de l'extension -+&Téléchargements -+Gestionnaire des certificats -+ souhaite suivre votre position géographique -+Quitter -+ sur -+Proposer d'enregistrer les mots de passe -+Modification de l'affiliation -+par exemple : 1-5, 8, 11-13 -+(Activé par une stratégie d'entreprise) -+Qu'est-ce que c'est ? -+Les cookies de plusieurs sites ont été bloqués. -+Serveur DNS spécifié par l'utilisateur et utilisé par Google Chrome, à la place du paramètre système par défaut, pour les résolutions DNS. -+Désactivé -+Annuler -+Répertoire racine de l'extension : -+Mode de saisie du vietnamien (TCVN6064) -+Échec de l'activation -+Ajouter cette page aux favoris -+L'identité de ce site Web a été vérifiée par . -+Adresse e-mail : -+Activation... -+PAP -+Sites de phishing -+ secs ago -+Interdire à tous les sites d'exécuter JavaScript -+Vouliez-vous accéder à  ? -+La connexion avec le service de configuration a été perdue. Veuillez réinitialiser votre périphérique ou contacter votre représentant de l'assistance technique. -+Paramètres des fenêtres pop-up : -+Tout exporter... -+Barre de favoris -+Stocké dans : -+Développer... -+Gin Yieh -+Rechercher sur -+Modifier la carte de paiement -+Au démarrage -+Nous examinons actuellement le problème. -+Notifications -+Navigateur -+Case d'option décochée -+ days -+Anglais -+Modifier le nom du dossier -+Grammaire et orthographe -+Réseaux privés -+Toutes sortes de connexions -+Exceptions liées aux notifications -+Épingler les onglets -+Barre d'onglets -+Activer l'onglet 6 -+Gestionnaire de &tâches -+Paramètres de stockage d'Adobe Flash Player... -+Connexion au réseau -+Mode de saisie du vietnamien (VNI) -+L'application suivante va être lancée si vous acceptez cette requête :\n\n -+Importation... -+N° de carte -+Gérer les moteurs de recherche... -+Utiliser un moniteur externe -+Gravure de l'image en cours... -+État -+Éteindre -+Enregistrer les fichiers dans le dossier : -+Fermer les autres onglets -+Répertoire de fichiers -+Masquer les autres -+Annuler l'épinglage des onglets -+Plus -+Échec de la vérification de la révocation -+Ajouter www. et .com, puis ouvrir la page -+Pour inspecter un pop-up, cliquez avec le bouton droit sur la page ou sur l'icône d'action du navigateur, puis sélectionnez Inspecter le pop-up. -+&Répéter -+ est à présent activé. a enregistré les imprimantes installées sur cette machine en les associant à <b></b>. Vous pouvez désormais utiliser vos imprimantes depuis n'importe quelle application Web ou mobile associée à . -+Le serveur de -+ est introuvable, car la résolution DNS a échoué. DNS est le service Web qui -+ traduit les noms de site Web en adresses Internet. Cette erreur est -+ généralement due à l'absence de connexion Internet ou à une configuration -+ incorrecte du réseau. Cela peut également venir d'un serveur DNS qui ne -+ répond pas ou d'un pare-feu interdisant l'accès de -+ -+ au réseau. -+ZGPY -+Impossible de charger le fichier css "" du script de contenu. -+Créer des raccourcis vers des applications aux emplacements suivants : -+Moyenne -+Envoyé pour : -+Aider Google à détecter les logiciels malveillants en envoyant des données supplémentaires concernant les sites pour lesquels cet avertissement s'affiche. Ces données seront gérées conformément aux règles définies sur la page . -+[répertoire parent] -+Touches de sélection du clavier Hsu -+Copie de l'image de récupération... -+Tout supprimer -+Seule une personne en possession de votre mot de passe multiterme peut lire vos données chiffrées. Google ne reçoit ni n'enregistre votre mot de passe multiterme. Si vous oubliez votre mot de passe multiterme, vous devrez réinitialiser la synchronisation. -+Ouvrir dans une nouvelle fenêtre -+Dommage... Aucune extension n'est installée. :-( -+Style de ponctuation -+Historique de navigation -+Ce site tente de télécharger plusieurs fichiers. Voulez-vous autoriser le chargement ? -+Établissement de la liaison avec le service de gestion des périphériques en attente... -+ heures -+Ne pas utiliser les paramètres du proxy pour les hôtes et domaines suivants : -+&Avancer -+Impossible de charger "" pour le plug-in. -+À propos du système -+Utilisation de la clé du certificat : -+Mode de saisie du chinois (quick) -+Une erreur s'est produite lors de la tentative d'écriture du fichier : . -+Renommer -+La synchronisation requiert votre attention. -+Aujourd'hui -+Imp&rimer le cadre... -+Le site a déjà été informé qu'un logiciel malveillant a été détecté sur ses pages. Pour plus d'informations concernant les problèmes rencontrés sur , consultez notre Google. -+Adresse de serveur DNS spécifiée par l'utilisateur. -+&Rechercher... -+, -+&Afficher dans le dossier -+Non connecté à Internet. -+Sélectionnez -+ -+ Démarrer > Panneau de configuration > Connexions réseau > Assistant Nouvelle connexion -+ -+ pour tester votre connexion. -+Cette icône s'affiche lorsque l'extension peut agir sur la page active. -+Reconnexion -+Réponses OCSP de signature -+Erreur d'importation de l'autorité de certification -+Gravure de l'image terminée. -+&Historique -+Installer -+Ajouter des utilisateurs -+Enregistrer l'authentification et le mot de passe -+Clavier norvégien -+Basculer en mode chinois/anglais -+Traduction de la page en ... -+À propos de & -+ onglets -+il y a  minutes -+Qu'est-ce que c'est ? -+Tout &sélectionner -+&Ajouter au dictionnaire -+Utilisation étendue de la clé -+Le chinois est la langue de saisie initiale -+Agent utilisateur -+Émetteurs de l'autorité de certification : -+ jours -+Code source -+Redémarrer maintenant -+La largeur de caractères initiale est Complète -+Pour masquer l'accès à ce programme, vous devez le désinstaller au moyen de \n du Panneau de configuration.\n\nSouhaitez-vous exécuter  ? -+Paramètres du microphone -+Port -+&Toujours ouvrir les fichiers de ce type -+Uniquement les connexions sécurisées -+Les informations de connexion au compte sont obsolètes. -+La traduction a échoué, car la page est déjà en . -+Sandbox SUID -+(vide) -+Échec de l'authentification basée sur le certificat -+Envoyer le code source de la page actuelle -+Votre administrateur a désactivé certains paramètres. -+Coréen -+Avertissement : Il s'agit peut-être d'un site de phishing ! -+Dvorak -+Étendue de pages incorrecte -+ heures restantes -+Exceptions liées aux cookies et aux données de site -+ n'est pas accessible -+P&lus grand -+Connecté à -+Le certificat de sécurité du site a été révoqué ! -+Désactiver -+ risque de ne pas rester à jour. -+intégré sur tout autre site -+ -+ ne parvient pas à atteindre le site Web. Cela vient probablement d'un problème de réseau, -+ mais peut également être dû à un pare-feu ou à un serveur proxy mal configuré. -+À propos de la reconnaissance vocale -+Langues et paramètres du correcteur orthographique... -+ seconde restante -+Nom d'utilisateur : -+Le stockage des cookies n'est pas autorisé pour cette page. -+JavaScript -+La connexion utilise . -+Échec de l'installation -+Afficher les &infos sur la page -+Serveurs -+Système de fichiers de chiffrement Microsoft -+Un plug-in supplémentaire est requis pour afficher certains éléments sur cette page. -+Appuyez sur Ctrl+Alt+/ ou sur Échap pour masquer -+Cette fonctionnalité effectue des vérifications en arrière-plan et vous avertit en cas d'incompatibilité logicielle (modules tiers bloquant le navigateur, par exemple). -+Connexion avec -+Imprimer depuis la boîte de dialogue système… -+ heure restante -+Échec de l'initialisation de l'appareil photo -+Importés -+Type de fournisseur : -+IP restreinte : -+Refuser -+Démarrage du téléchargement en cours... -+Une nouvelle version de est disponible. -+Clavier hébreu -+Police à largeur fixe -+Safari -+Les champs obligatoires ne doivent pas rester vides. -+Ouvrir une fois le téléchargement &terminé -+Stratégies de certificat -+Pavé tactile -+Aucun -+Activer la barre d'adresse en mode recherche -+Exceptions pour JavaScript -+Ouvrir dans une nouvelle fenêtre -+Veuillez saisir le code PIN. -+Options de saisie automatique... -+Arabe -+Nouveau dossier -+E/S réseau interrompue -+Rechercher le précédent -+Ne jamais enregistrer les mots de passe -+Ouvrir dans un nouvel onglet -+Fenêtre suivante -+&Rechercher le suivant -+JCB -+Signature de liste d'approbation Microsoft -+Gérer les certificats... -+Sélectionnez le fichier de certificat. -+Fabricant : -+Bloquer le contenu inapproprié -+Le fichier contenait plusieurs certificats, dont certains n'ont pas été importés : -+Exceptions pour les images -+Autoriser tous les sites à afficher des fenêtres pop-up -+Vous devez indiquer un chemin valide comme valeur de clé privée. -+Sans mot de passe multiterme, vos mots de passe et autres données chiffrées ne seront pas synchronisés sur cet ordinateur. -+Extensions ou applications -+Ce site recommande Google Chrome Frame (déjà installé). -+Les plus visités -+Vous n'êtes pas autorisé à vous connecter. Consultez le propriétaire de cet ordinateur portable. -+Remarque : Lorsque vous cliquez sur "Envoyer", Google Chrome joint à votre -+ envoi un journal indiquant votre version de Google Chrome et celle du système -+ d'exploitation utilisé, ainsi que l'URL associée à votre rapport. Vous pouvez -+ également joindre une capture d'écran. Ces informations nous -+ permettent de diagnostiquer les problèmes et d'améliorer les performances de -+ Google Chrome. Les informations personnelles fournies sciemment dans vos -+ commentaires ou involontairement dans le journal, l'URL ou la capture -+ d'écran sont protégées conformément à nos règles de -+ confidentialité. Si vous ne souhaitez pas indiquer d'URL et/ou de capture -+ d'écran, décochez les cases "Inclure cette URL" et/ou "Inclure cette capture d'écran". Vous acceptez que Google utilise vos commentaires pour améliorer ses produits ou services. -+Vos modifications seront prises en compte au prochain démarrage de . -+Taille de police minimale -+Entrée directe -+Fermer la fenêtre -+Mode de saisie du japonais (pour clavier japonais) -+Inscription réussie -+Échec de création du fichier zip temporaire lors de la création du pack -+Modifier les paramètres de confiance : -+Votre historique de navigation -+&Masquer le panneau de la vérification orthographique -+Plug-in ne répondant pas -+IBM -+Les paramètres seront effacés lors de la prochaine actualisation. -+ introuvable -+Démarrage... -+Nouvelle fenêtre de nav&igation privée -+Ajouter une adresse postale... -+Authentification en cours... -+Ouvrir dans un nouvel onglet -+Déconnecté -+Action du navigateur -+Le mot de passe multiterme saisi ne peut pas être utilisé, car vous avez déjà chiffré des données avec un mot de passe multiterme. Entrez ci-dessous le mot de passe multiterme actuellement défini pour la synchronisation. -+Ouvrir cette page : -+Voulez-vous vraiment supprimer tous les mots de passe ? -+Sélectionner par domaine -+Ouvrir le lien dans une fenêtre en navi&gation privée -+Émetteur -+Options de saisie automatique -+Les nouveaux paramètres des cookies seront appliqués quand vous aurez actualisé la page. -+Votre connexion à est sécurisée par un chiffrement bits. -+Menu Applications -+Outi&ls -+Onglets latéraux -+Reprendre -+Zoom -+Inspecteur de DOM -+Document sans titre -+Police standard -+Activer -+Opération en cours... -+C&opier l'URL de l'image -+La saisie automatique des numéros de carte de paiement est désactivée, car la connexion utilisée par ce formulaire n'est pas sécurisée. -+Enregistrer le &cadre sous... -+Général -+Défaillance -+Demander -+Coller l'URL et y a&ccéder -+Pour plus de sécurité, va chiffrer vos mots de passe. -+Si vous avez oublié votre mot de passe multiterme, vous devrez arrêter la synchronisation via Google Dashboard. -+ sur  -+Adresse ligne 1 -+Impossible de créer le favori. -+Basculer en mode chinois simplifié/traditionnel -+Votre système Sandbox n'est pas correctement configuré. -+Sélectionnez le menu clé à molette > Préférences > Options avancées > Modifier les paramètres du proxy et vérifiez que vos paramètres sont définis sur "sans proxy" ou "direct". -+Impossible de vérifier si le certificat a été révoqué. -+Stockage des données -+/, Interrompu -+Acheter un forfait -+Installer le plug-in... -+Afficher le code source -+Fermer les onglets sur la droite -+Afficher le bouton "Accueil" -+Version  -+Parenthèse gche -+Microsoft Server Gated Cryptography -+Zoom avant -+Protection du courrier électronique -+Les cookies suivants ont été bloqués (tous les cookies tiers sont bloqués, sans exception) : -+Connectez-vous à pour importer le certificat client de -+La batterie est chargée. -+Créer un nouveau profil... -+Maintenez la touche enfoncée pour quitter. -+Masquer ce plug-in -+Ouvrir le fichier -+Conteneur de barres d'infos -+Le certificat du serveur a expiré. -+Utiliser -+Réduit la taille du texte -+Épingler l'onglet -+Mise à jour du système -+ days left -+Inclure les informations système -+Google Chrome n'avait pas suffisamment de mémoire ou le processus de la page Web a été arrêté pour une autre raison. Pour continuer, actualisez la page ou ouvrez-en une autre. -+Impossible de valider votre mot de passe sur le réseau actuel. Sélectionnez un autre réseau. -+Cette page n'est pas rédigée en  ? Signaler l'erreur -+Certificat unique codé Base 64 ASCII -+Activer le mode plein écran -+Codag&e -+ est déjà utilisé pour gérer les liens ://. -+Touches de sélection -+Clavier international américain -+Je comprends que la visite de ce site peut être préjudiciable à mon ordinateur. -+Ressource cache manquante. -+Impossible d'accéder à mon compte -+C&opier l'URL de la vidéo -+Vous préférez parcourir la galerie ? -+Impossible de vérifier le certificat du serveur. -+Outils de &développement -+Exporter... -+Paramètres de saisie automatique -+Téléchargement de l'image en cours... -+&Options du vérificateur d'orthographe -+Impossible d'ouvrir votre profil correctement.\n\nIl est possible que certaines fonctionnalités ne soient pas disponibles. Vérifiez que ce profil existe et que vous disposez d'une autorisation d'accès à son contenu en lecture et en écriture. -+Vérifier le document maintenant -+Zone de liste -+Clavier slovène -+Sens de l'écriture -+Vos données sur -+Ouvrir une fenêtre du navigateur -+Conversion de la date et de l'heure -+PKCS #1 SHA-512 avec chiffrement RSA -+Clavier coréen -+Dupliquer -+Ne pas conserver sur cette page -+Désactiver -+ATOK -+téléchargement -+E-mail : -+Ouvrir tous les favoris dans une nouvelle &fenêtre -+Rafraîchir la page actuelle -+Accessibilité -+Exceptions pour les plug-ins -+Remplissage automatique des formulaires -+Nom d'utilisateur -+Enregistrer le lie&n sous... -+Réessayer -+Personnaliser et configurer -+Préférences de saisie automatique -+Votre position géographique -+Afficher les pages en arrière-plan () -+Configurer les mises à jour automatiques -+il y a  heures -+Valeur du champ -+Les dernières versions d'Unity et GNOME (ainsi que la prochaine version d'Ubuntu, Natty Narwhal) affichent une barre de menus de type OSX sur toute la largeur supérieure de l'écran. -+Index erroné. -+Préparation du module de plate-forme sécurisée (TPM) en cours. Veuillez patienter, l'opération peut prendre quelques minutes. -+Nombre de copies incorrect -+Personnaliser -+Prédire les actions du réseau pour améliorer les performances de chargement des pages -+Données restantes : -+N'est pas une autorité de certification. -+L'URL doit être valide. -+Envoyer automatiquement les statistiques d'utilisation et les rapports d'erreur à Google -+Cette fonctionnalité active la géolocalisation dans les extensions expérimentales. Cela implique l'utilisation des API de localisation du système d'exploitation (si disponibles) et l'envoi de données sur la configuration réseau locale au service de localisation de Google afin de déterminer une position précise. -+Impossible de charger le profil. -+Toujours exécuter JavaScript sur -+Version PRL : -+Confirmer la réactivation -+Ajouter une adresse postale... -+PKCS #1 MD2 avec chiffrement RSA -+Dim.^Lun.^Mar.^Mer.^Jeu.^Ven.^Sam. -+Zone de saisie -+Trier par nom -+Fenêtre -+Nouvel onglet -+Vous tentez d'accéder au site , mais le certificat présenté par le serveur a été révoqué par son émetteur. Cela signifie que les informations d'identification présentées par le serveur ne sont pas approuvées. Vous communiquez peut-être avec un pirate informatique. Nous vous déconseillons vivement de continuer. -+Composition hors écran -+ mins left -+Technologie : -+Accédez à la page d'accueil du site : -+Configurer la communication à distance -+L'émetteur d'un certificat n'ayant pas expiré est tenu d'assurer la maintenance de ce qui s'appelle "une liste de révocation". Si un certificat est compromis, l'émetteur peut le révoquer en l'ajoutant à la liste de révocation. Ce certificat n'est alors plus approuvé par votre navigateur. Il n'est pas nécessaire d'assurer la maintenance de l'état "révoqué" des certificats expirés. Donc, bien qu'un certificat ait été qualifié de valide pour le site Web que vous visitez actuellement, il est impossible de déterminer s'il a été, depuis, compromis puis révoqué ou s'il est toujours valide. Par conséquent, il n'est pas possible de s'assurer si vous communiquez avec un site Web légitime ou si le certificat a été compromis et se trouve maintenant en la possession d'un pirate informatique avec lequel vous communiquez. Ne poursuivez pas. -+Néanmoins, si vous travaillez dans une entreprise qui génère ses propres certificats, et que vous essayez de vous connecter au site Web interne de l'entreprise avec un certificat de ce type, vous pouvez résoudre ce problème en toute sécurité. Pour ce faire, importez le certificat racine de l'entreprise en tant que "certificat racine". Par la suite, les certificats émis ou vérifiés par votre entreprise seront approuvés et vous ne verrez plus cette erreur lorsque vous tenterez de vous connecter à nouveau au site Web interne. Contactez le support informatique de votre entreprise pour savoir comment ajouter un nouveau certificat racine sur votre ordinateur. -+Définir en tant que navigateur par défaut -+Avertissement -+Préférences de recherche -+Clavier Colemak américain -+Activer la navigation en tant qu'invité -+Utiliser les paramètres par défaut -+Rétablir -+Désinstaller "" ? -+Établissement de la connexion sécurisée... -+Dossier : -+Erreur non reconnue -+Consultez les conflits connus avec des modules tiers. -+Co&ller et rechercher -+&Remonter -+Échec de la traduction en raison d'une erreur de serveur -+Version : -+Polices et codage -+ - -+Signature du code commercial Microsoft -+Sélectionnez les éléments à importer : -+De gauche à droite -+Votre connexion à est sécurisée par le biais d'un faible chiffrement. -+sans objet -+Toujours afficher la barre de favoris -+Activer l'onglet 2 -+Aperçu des onglets -+Redémarrer -+Configuration en cours... -+Une erreur s'est produite lors de la récupération des fonctions de l'imprimante . Cette imprimante n'a pas pu être enregistrée dans . -+Exceptions pour les fenêtres pop-up -+Signataire du certificat -+La page Web n'existe plus. -+Vous n'avez jamais visité ce site auparavant. -+Personnaliser... -+Fe&rmer la fenêtre -+Arrêter le chargement de cette page -+Autres favoris -+ a été mis à jour. -+Mode hors connexion -+Erreur d'importation de fichier PKCS #12 -+Algorithme de clé publique de l'objet -+Le site Web a rencontré une erreur lors de l'extraction de . -+ Cela peut être dû à une opération de maintenance ou à une configuration incorrecte. -+Échec du chargement de la page -+Mot de passe : -+Conserver en tant que moteur de recherche par défaut -+Fichier manifeste absent ou illisible -+La connexion a été réinitialisée. -+Le mot de passe choisi vous sera demandé pour restaurer le fichier. Veillez à le conserver en lieu sûr. -+La vérification de la provenance du certificat DNS est activée, ce qui peut entraîner l'envoi d'informations privées à Google. -+À propos de la reconnaissance vocale -+Aller à la sélection -+Ajouter un certificat -+Espaces de noms PID -+Préférences de saisie automatique -+Activer l'onglet 8 -+Le certificat "" représente une autorité de certification. -+Envoyer par e-mail l'emplacement de la page -+Enregistrement des informations de date Microsoft -+Validité -+&Traduire en -+Batterie :  % -+Désactivé -+Japonais -+ () -+L'application est actuellement inaccessible. -+Lecteur du certificat : -+ jour restant -+Gestionnaire de tâches -+Gérer les extensions... -+Continuer -+Synchronisation avec effectuée. Dernière synchronisation : -+Le certificat de sécurité du site n'est pas encore valide ! -+Ouverture de session par carte à puce Microsoft -+Format -+Tapez votre requête ou saisissez une URL pour commencer la navigation : c'est à vous de choisir. -+Enregistrer &sous... -+Le serveur requiert un nom d'utilisateur et un mot de passe. -+Supprimer tous les mots de passe -+Le certificat du serveur contient des erreurs. -+Recherche de réseaux Wi-Fi... -+Description : -+Séparateur -+Si vous supprimez l'un de vos propres certificats, vous ne pouvez plus l'utiliser pour vous identifier. -+Rafraîchir cette page -+État d'activation : -+Créer des raccourcis vers des applications -+Clavier franco-suisse -+GUID de domaine Microsoft -+Entrer -+Supprimer -+Échec de l'enregistrement de cet ordinateur pour l'accès à distance. -+Ouvrir l'&image dans un nouvel onglet -+Préférences... -+L'administrateur a désactivé les mises à jour. -+À propos de la version -+Veuillez nous indiquer ce qu'il se passe avant d'envoyer votre rapport. -+Connectez-vous à afin de générer une clé pour . -+Clavier roumain -+Autres -+Sécurité : -+Imprimer -+Mode de saisie standard -+Signature -+Erreur lors de la connexion -+Pour cette session uniquement -+Une erreur s'est produite. -+(Désactivé par une stratégie d'entreprise) -+Erreur lors de la tentative d'impression. Vérifiez votre imprimante et réessayez. -+Grec -+Ignorer les exceptions et bloquer l'enregistrement des cookies tiers -+Cet outil vous permet de sélectionner une capture d'écran enregistrée. Aucune capture d'écran n'est disponible pour le moment. Appuyez simultanément sur Ctrl et sur la touche "Mode Présentation" pour enregistrer une capture d'écran. Vos trois dernières captures apparaissent ici. -+Activation effectuée -+Aucun système de révocation trouvé -+Bouton -+Interrompu -+Dictionnaire de symboles -+Technologie EvDo requise -+Internet mobile -+Envoyer le commentaire -+Associé au profil Chrome . Dernière synchronisation : -+Carte de crédit (autre) -+Langues et saisie -+Utiliser la barre de titre et les bordures de fenêtre du système -+Ann&uler -+ () -+Le serveur a refusé d'exécuter la demande. -+ Ko -+ a été mis à jour vers la version . -+Navigateur de contenu -+&Rouvrir la fenêtre fermée -+Se connecter directement à Internet -+Émis pour -+Ouverture de en cours -+Cibles disponibles pour l'image -+Signaler un problème -+Taille de police : -+Aide pour la configuration de proxy -+Petite -+ hours ago -+Rester sur cette page -+Type de bug : -+Inclure cette URL : -+Cookies et données de site... -+Police Serif -+Avertissement : ne peut pas empêcher les extensions d'enregistrer votre historique de navigation. Pour désactiver cette extension en mode navigation privée, désélectionnez-la. -+ChromiumOs Image Burn -+Services -+Paramètres du proxy... -+1 onglet -+Vous naviguez en tant qu'invité. Les pages que vous consultez dans cette fenêtre n'apparaîtront pas dans l'historique de votre navigateur ni dans votre historique des recherches. Les autres traces telles que les cookies seront supprimées de l'ordinateur à la fin de votre session. En revanche, les fichiers téléchargés et les favoris créés seront conservés. -+ -+ En savoir plus sur le mode invité -+Chargement des pages impossible -+Inclure cette capture d'écran : -+Certificat -+&Effacer les données de navigation... -+Valeur de signature du certificat -+URL de renouvellement du certificat Netscape -+Afficher la s&ource -+ - , -+Reprendre -+ secs ago -+Activé -+Carte SIM désactivée -+Compatibilité avec VPN -+Développement - Instable -+Échec de création du raccourci vers l'application -+Barre de favoris -+Le serveur est en mesure de répondre à la demande. -+Modifier les paramètres du proxy... -+(non empaquetée) -+Rechercher le suivant -+Paramètres réseau -+Votre service Internet mobile est activé et prêt à l'emploi. -+Modifier la police et la langue par défaut des pages Web -+Composition graphique avec accélération matérielle -+Autre nom de l'émetteur du certificat -+ -+&Afficher le code source du cadre -+Mode de saisie du persan (clavier ISIRI 2901) -+OpenVPN -+Arrêter le processus -+Votre compte a peut-être été supprimé ou désactivé. Veuillez vous déconnecter. -+Authentification anonyme : -+Bases de données indexées -+En savoir plus sur les escroqueries par phishing -+Page à l'apparence anormale -+Adresse e-mail ou mot de passe incorrect. Essayez tout d'abord de vous connecter à un réseau. -+Périphérique -+Informations sur la connexion -+Confirmer la navigation -+Nom du point d'accès : -+Rechercher -+Au démarrage -+Paramètres... -+Lire en un clic -+Connectez-vous à pour vous authentifier auprès de avec votre certificat. -+Votre administrateur informatique a désactivé certaines options. -+Supprimer le certificat de serveur ""? -+Configurer la synchronisation... -+Valider automatiquement une chaîne -+Empreinte SHA-256 -+Retour -+Réseau domestique, sans itinérance -+ - -+Gérer les mots de passe enregistrés... -+Sélectionnez -+ -+ Menu clé à molette > Options > Options avancées > Modifier les paramètres du proxy > Paramètres réseau -+ -+ et désélectionnez l'option "Utiliser un serveur proxy pour votre réseau local". -+Ne jamais traduire ce site -+(suite) -+Trop de redirections -+Ces paramètres ne peuvent être modifiés que par le propriétaire : -+Active la protection XSS Auditor de WebKit (protection contre le Cross-site Scripting), une fonctionnalité qui vous protège de certaines attaques de sites malveillants et offre une sécurité accrue, mais qui n'est pas compatible avec tous les sites Web. -+Clavier latino-américain -+Phishing détecté ! -+Voulez-vous utiliser () pour gérer les liens :// à partir de maintenant ? -+ (Navigation privée) -+Prendre une photo -+Non merci -+Ne pas afficher les images -+Toujours autoriser ces plug-ins sur -+Sélectionner un dossier -+&Paramètres -+Informations sur l'erreur : -+Toujours autoriser les plug-ins sur -+Effacer les données de saisie automatique enregistrées -+Changer de moteur de recherche -+En attente du tunnel proxy... -+Veuillez ajouter un autre mode de saisie avant de supprimer celui-ci. -+ secondes -+Paramètres de contenu -+Impossible d'extraire les fichiers de l'extension. Pour effectuer cette opération en toute sécurité, vous devez disposer d'un chemin d'accès à votre répertoire de profils commençant par une lettre de lecteur et ne contenant ni jonction, ni point de montage, ni lien symbolique. Aucun chemin de ce type n'existe pour votre profil. -+ va être installé. -+Code postal -+En bas à droite -+&Ouvrir -+ téléchargé(s) sur -+Commentaires d'ordre général/Autres -+Ou&vrir la vidéo dans un nouvel onglet -+Identité : -+Échec de l'opération OTASP -+Action sur la page -+Modifier des éléments... -+Le répertoire d'extensions est obligatoire. -+ Mo disponibles -+Ancien -+ fournit du contenu provenant de , un site connu pour distribuer des logiciels malveillants. Votre ordinateur pourrait être infecté par un virus si vous consultez ce site. -+Ces fonctionnalités expérimentales sont susceptibles d'être modifiées, interrompues ou supprimées à tout moment. Nous ne fournissons aucune garantie quant aux effets de leur activation. Votre navigateur pourrait bien prendre feu. Trêve de plaisanterie, il est possible que votre navigateur supprime toutes vos données ou que votre sécurité et votre vie privée soient compromises de manière inattendue. Nous vous prions d'agir avec précaution. -+Configuration manuelle du proxy -+Mettre à jour Adobe Reader maintenant -+ days ago -+Désactiver les plug-ins individuels... -+Envoyer une capture d'écran de la page en cours -+Point d'exclamation -+ n'est plus à jour, car il n'a pas été relancé depuis quelque temps. La mise à jour disponible sera installée dès que vous le relancerez. -+Petit problème... Tentons de le résoudre. -+Cette fonctionnalité permet d'établir des correspondances entre les sous-chaînes et plusieurs fragments d'URL figurant dans l'historique. -+Page "Nouvel onglet" expérimentale -+Les cookies suivants étaient autorisés lorsque vous avez consulté cette page : -+votre opérateur -+Activer ces fonctionnalités... -+Quitter Firefox avant l'importation -+Ajouter un nouveau téléphone -+Proxy HTTP sécurisé -+Accès à refusé. -+Finalisation de la mise à jour du système... -+Voulez-vous continuer ? -+ Ko ( Ko effectifs) -+Autre réseau Wi-Fi... -+Choisir un autre répertoire... -+L'extension indiquée est déjà associée à une clé privée. Utilisez cette clé ou supprimez-la. -+Ajouter une adresse -+Stockage local -+Afficher tous les téléchargements -+Navigateur de contenu -+Magasin de certificats -+Émis par -+Quitter le mode plein écran () -+Le certificat du serveur a été signé avec un algorithme de signature faible. -+Ajouter un utilisateur -+Me proposer de traduire les pages qui sont écrites dans une langue que je ne sais pas lire -+Récemment fermés -+Saisir la clé de déverrouillage du code PIN -+ jours -+Rechercher du texte -+Sans-Serif -+Zoom &avant -+Confirmer le nouvel envoi du formulaire -+ heure -+Cet élément doit être installé depuis . -+Mise en veille ou reprise -+Mettre à jour maintenant -+Ajouter une page -+Chiffrer seulement -+Ne jamais intervertir les touches de modification -+Conversion des numéros spéciaux -+Relancer maintenant -+Synchronisation avec effectuée -+il y a  minute -+Édition -+Préférences synchronisées -+ hours ago -+Personnalisé -+Rechercher à partir de la barre d'adresse -+Ouvrir -+Inspecter les vues actives : -+Contraintes de nom du certificat -+Ajouter une adresse -+Mot de passe incorrect. -+Statistiques avancées -+Clavier espagnol -+Sélectionnez votre réseau -+ jour -+Le serveur de synchronisation est occupé. Veuillez réessayer ultérieurement. -+Quitter cette page -+Naviguer en tant qu'invité -+Discover -+&Toujours afficher la barre de favoris -+Options de recherche -+Taille : -+il y a  secondes -+La liste suivante fait état des éléments dangereux détectés sur la page. Cliquez sur le lien "Diagnostic" pour obtenir plus d'informations sur une ressource particulière. Si une ressource a été signalée comme site de phishing alors que vous êtes certain de sa fiabilité, cliquez sur le lien "Signaler une erreur". -+Cette page rédigée dans une langue non identifiée a été traduite en . -+Les exceptions ci-dessous s'appliquent uniquement à la session de navigation privée actuelle. -+Ne plus afficher la boîte de dialogue pour les liens de ce type -+ secondes restantes -+Insérez dans l'URL où les termes de recherche devraient apparaître. -+En&registrer la vidéo sous... -+Nom : -+Si vous rencontrez des problèmes fréquents avec ce module, vous pouvez tenter d'y remédier en suivant la procédure ci-après : -+Informations relatives au certificat -+Activer l'onglet 7 -+En savoir plus sur ce problème. -+Version du matériel : -+Le site Web à l'adresse contient des éléments provenant de sites qui semblent héberger des logiciels malveillants. Ces derniers peuvent nuire à votre ordinateur ou agir à votre insu. Le simple fait de visiter un site hébergeant ce type de logiciels peut infecter votre ordinateur. Ce site héberge également des informations provenant de sites signalés comme étant des sites de phishing. Ces derniers incitent les internautes à divulguer des informations personnelles en se faisant passer pour des institutions de confiance, telles que des banques. -+Afficher la liste -+Désactivez l'affichage des messages de confirmation et le blocage de l'envoi des formulaires. -+Ce cadre a été bloqué, car il contient des éléments non sécurisés. -+Tout -+Kana -+Gérer les mots de passe enregistrés... -+Boîte de dialogue "Effacer les données de navigation" -+Mettre à jour les extensions maintenant -+Nouvelle application en arrière-plan installée -+Envoyer une capture d'écran de la page actuelle -+L'URL indiquée est incorrecte. -+Un problème est survenu lors de l'affichage de la liste des imprimantes. Certaines de vos imprimantes ne sont peut-être pas correctement enregistrées dans . -+Actuellement connecté -+La page que vous recherchez a utilisé des informations que vous avez envoyées. Si vous revenez sur cette page, chaque action précédemment effectuée sera répétée. Souhaitez-vous continuer ? -+Cette fonctionnalité indique la vitesse d'affichage réelle d'une page, en images par seconde, lorsque l'accélération matérielle est active. -+E&xporter... -+&Ouvrir un fichier... -+Configurer le contrôle d'accès pour vos périphériques -+Ouvrir un rapport de phishing -+Activer la barre d'adresse -+ secs ago -+Cartes de paiement -+Code opérateur : -+Erreur de connexion -+Vous avez la possibilité de désactiver ces services. -+Essayer d'afficher la page malgré tout -+Impossible d'établir une connexion sécurisée avec le serveur. Le serveur a peut-être rencontré un problème ou exige un certificat d'authentification du client dont vous ne disposez pas. -+Ajouter un nouveau nom -+Obtenir d'autres thèmes -+Rétablir les valeurs par défaut -+Aucun Plug-in installé. -+Action -+Extensions de fichier -+Les plus visités -+&Gestionnaire de favoris -+Caches des applications -+Cette langue est actuellement utilisée par . -+ % -+Empaqueter l'extension -+Activer l'onglet 5 -+Sélectionner le mode de saisie précédent -+Configurer le blocage de JavaScript... -+Réseaux mémorisés -+Impossible de se connecter à Internet. -+URL incorrecte -+Informations sur la sécurité -+Impossible d'installer l'application, car elle est en conflit avec "", qui est déjà installé. -+Votre périphérique n'est pas connecté. -+Fermer -+Accord de la clé -+ mins ago -+Vous ne trouvez pas ce que vous recherchez ? -+Désactivez l'envoi des pings de contrôle des liens hypertexte. -+En&registrer le fichier audio sous... -+Accédez rapidement à vos favoris en les ajoutant à la barre de favoris. -+Vérifier la grammaire et l'orthographe -+Épingler les onglets -+Sélectionner par type d'application -+assembler -+ souhaite devenir votre moteur de recherche. -+Utiliser l'historique d'entrée -+Fermer les onglets -+Voici quelques suggestions : -+Sélectionnez un ou plusieurs fichiers -+Afficher le panneau de la &vérification orthographique -+Veuillez relancer . -+Sans titre -+Pour saisir du texte, sélectionnez une langue et consultez la liste des modes de saisie disponibles. -+Ville -+Modifier... -+Réinitialiser la synchronisation -+Inclure une capture d'écran enregistrée : -+Tout supprimer -+Passer automatiquement en demi-chasse -+&Accéder à -+La capacité de ce périphérique de stockage est de . Veuillez insérer une carte SD ou une clé USB d'au moins 4 Go. -+Rouvrir le dernier onglet fermé -+(blocage) -+Erreurs () -+Traitement de la sélection... -+Aide -+Désolé ! La visionneuse de documents PDF intégrée à Google Chrome, nécessaire à l'affichage de l'aperçu avant impression, n'est pas incluse dans Chromium. -+Impossible d'ouvrir , car vous êtes déconnecté du réseau. Cette page s'affichera dès que la connexion réseau sera rétablie. <br> -+Télécopie -+version -+La passerelle ou le serveur proxy a reçu une réponse incorrecte d'un serveur en amont. -+Nouvelle fenêtre ouverte dans la session du navigateur -+Réessayer -+ peut maintenant synchroniser vos mots de passe. Vos données seront chiffrées avec le mot de passe de votre compte Google ou le mot de passe multiterme de votre choix. -+Les paramètres réseau de votre proxy sont gérés par une extension. -+Retirer l'onglet -+Valable du au -+Case cochée -+Mode de saisie -+AVERTISSEMENT -+Clavier estonien -+Ajout de bordures aux couches de rendu composées -+Imp&rimer... -+Paramètres de saisie automatique -+Rafraîchir -+Barre d'outils -+Nom de la base de données : -+Certificat du répondeur d'état -+Utiliser le mot de passe de mon compte Google -+Vos favoris sont maintenant synchronisés avec Google Documents ! -+Pour fusionner et synchroniser vos favoris dans sur un autre ordinateur, procédez de la même manière que précédemment sur l'ordinateur voulu. -+Renommer... -+ a été désactivé. Si vous arrêtez la synchronisation des favoris, vous pouvez la réactiver sur la page des extensions, via le menu Outils. -+Affichage des pages impossible -+Utiliser par défaut -+La carte SIM est verrouillée. Veuillez saisir votre code PIN. Nombre de tentatives restantes : -+Point-virgule -+Réseau domestique requis -+PKCS #7, certificat unique -+Langues baltes -+Vous avez saisi un trop grand nombre de clés de verrouillage du code PIN incorrectes. Votre carte SIM est définitivement désactivée. -+Données de diagnostic système -+Page Web, contenu HTML uniquement -+Continuer » -+Gérez vos imprimantes. -+(Choisir un problème dans la liste ci-dessous) -+&Afficher le code source du cadre -+Authentification du client WWW TLS -+Les cookies de plusieurs sites sont autorisés. -+Impossible d'afficher la page de la barre latérale "". -+Vous avez acheté de données le . -+Enregistrer le mot de passe -+Configurer... -+Mode de saisie du pinyin -+Intervertir les touches Ctrl et Alt de gauche -+Confirmer le mot de passe multiterme -+Activer -+Ajouter... -+Voulez-vous que Google Chrome enregistre ces informations de carte de paiement pour le remplissage de formulaires Web ? -+Continuer à bloquer les fenêtres pop-up -+Échec de la vérification DHCP -+Choisir un autre dossier... -+Le profil semble être utilisé par le processus sur l'hôte . Si vous êtes certain qu'aucun autre processus n'utilise ce profil, supprimez le fichier et relancez . -+Chinois traditionnel -+Effacer les données de navigation... -+Ré&activer le son -+Aucun réseau trouvé. -+&Ouvrir le fichier audio dans un nouvel onglet -+&Méthodes d'entrée -+Onglets ou fenêtres -+Toutefois, cette page inclut d'autres ressources qui ne sont pas sécurisées. Ces ressources peuvent être consultées par des tiers pendant leur transfert, et modifiées par un pirate informatique dans le but de changer le comportement de cette page. -+Automatique -+&Extensions -+Roumain -+Paramètres du réseau... -+Changer... -+Clé privée -+Format : -+Se connecter -+ : -+Vous avez tenté de contacter , mais le certificat présenté par le serveur est incorrect. -+Nouvelle fenêtre de nav&igation privée -+La page à l'adresse indique : -+Le serveur associé à n'a pas répondu à temps. Cela peut être dû à une surcharge. -+L2TP/IPSec + Clé pré-partagée -+XSS Auditor -+Durée de validité -+WebGL -+Mot de passe multiterme erroné -+Corriger automatiquement la saisie -+Unité d'organisation -+Compte Google -+&Aide -+Utiliser un service de prédiction afin de compléter les recherches et les URL saisies dans la barre d'adresse -+Certificat du signataire de courrier électronique -+En savoir plus -+Vous avez enregistré vos imprimantes sur via le compte . -+il y a  jours -+: restantes -+Cette page est enVoulez-vous la traduire ? -+Saisie automatique des formulaires -+Clavier ukrainien -+Ouvrir tous les favoris dans une fenêtre de navigation privée -+Ctrl -+ minutes -+Le certificat de sécurité du serveur contient des erreurs ! -+avec votre compte Google -+Rechercher dans les favoris -+MSCHAPv2 -+Avertissement utilisateur -+&Options du vérificateur d'orthographe -+Échec de la connexion -+Identifiant de l'erreur -+ jours restants -+Émis par : -+Mode de saisie du thaï (clavier Kesmanee) -+Passerelle : -+Chiffrement -+Autre... -+Pas avant le -+ n'a pas pu synchroniser vos données, car la connexion avec le serveur de synchronisation n'a pas pu être établie. Nouvel essai... -+Me demander lorsqu'un site souhaite afficher des notifications sur le Bureau (recommandé) -+Source : -+Erreur de lecture du cache -+Raccourci de sélection -+Vérifier la révocation du certificat serveur -+Vous rencontrez des problèmes lors de l'installation ? -+Bêta -+Pointeur de la déclaration CPS (Certification Practice Statement) -+Le , vous avez reçu à utiliser librement. -+Nom complet -+Inscription d'entreprise -+Clavier allemand -+Impossible de lancer l'impression. -+&Lire -+Récent -+Cette page Web présente une boucle de redirection. -+Supprimer le certificat "" émis par l'autorité de certification ? -+Mots de passe enregistrés -+Moins -+Options avancées -+Vérifiez vos paramètres DNS. Contactez votre administrateur réseau si vous n'êtes pas sûr de vous. -+Une erreur inconnue s'est produite. -+Émetteur : -+Passer d'un mode de saisie à l'autre -+Organisation (O) -+PKCS #1 SHA-1 avec chiffrement RSA -+Entrez la requête de recherche ici. -+Application en mode navigation privée : -+La largeur de ponctuation initiale est Complète -+Installer  ? -+Installation d'une nouvelle version... -+Ouvrir le lien dans un nouvel ongle&t -+Pour accéder aux paramètres de sécurité, saisissez le code PIN de la carte SIM. -+Jamais -+Impossible d'accéder au réseau. -+Effacer le formulaire -+Échec de la mise à jour du système -+Saisissez le mot de passe utilisé pour chiffrer ce fichier de certificat. -+CHAP -+Enregistrer le lie&n sous... -+Effacer les données de navigation... -+Options de reconnaissance vocale -+Réseau câblé -+Nouvel ongle&t -+R&etour -+Téléchargement suspendu -+Ouvrir la page d'accueil -+Connexion -+L'installation de est terminée. -+&Outils -+Page d'accueil -+Clavier phonétique bulgare -+Cookies et données de site... -+Batterie faible -+Commentaires -+Package incorrect : "". -+ heures restantes -+Configurer les paramètres de blocage des images... -+Options -+ hours ago -+&Détails -+Masquer la barre de titre du système et utiliser les bordures -+Elle peut accéder aux éléments suivants : -+Confidentialité -+Objets : -+Paramètres d'entrée du japonais -+Sebeol-sik Final -+Veuillez vous connecter à Internet pour continuer. -+Afficher les &infos sur le cadre -+Fichier -+Cop&ier l'image -+Utiliser le même proxy pour tous les protocoles -+Masquer -+Requête de protocole externe -+Afficher -+Certains de vos certificats enregistrés identifient ces serveurs : -+Vous avez visité ce site pour la première fois le . -+Cliquer pour avancer, maintenir pour voir l'historique -+La dernière version de l'application "" requiert d'autres autorisations. Elle a donc été désactivée. -+ secondes -+Vous avez choisi d'ouvrir automatiquement certains types de fichiers après leur téléchargement. -+EAP-MD5 -+&Nouvelle fenêtre -++ -+Vous avez essayé d'accéder au site , mais le serveur a présenté un certificat signé avec un algorithme de signature faible. Il se peut que les informations d'identification fournies par le serveur aient été falsifiées. Le serveur n'est peut-être pas celui auquel vous souhaitez accéder (il peut s'agir d'une tentative de piratage). Nous nous déconseillons vivement de continuer. -+L'envoi de rapports d'erreur est désactivé. -+Clé WEP incorrecte -+Date d'expiration : -+URL de base du certificat Netscape -+Réduire... -+Rechercher dans l'historique -+Ouvrir le lien dans la fenêtre de navi&gation privée -+ secondes -+Historique avancé pour le champ polyvalent -+Active l'utilisation de graphismes 3D dans les éléments canvas via l'API WebGL. -+Occident -+État non reconnu -+ -+Impossible de vérifier si le certificat du serveur a été révoqué. -+Se connecter -+Fuseau horaire : -+Cette option est soumise à une stratégie d'entreprise. Contactez votre administrateur pour plus d'informations. -+Résultats de recherche pour "" -+Revenir à "" (redémarrage requis) -+ va exécuter les tâches suivantes : -+Ajouter la page -+Changement de mode via la touche Maj -+Options de date et d'heure... -+Nom DNS -+Build de développement -+ sur ... -+Verrouiller la carte SIM (code PIN obligatoire pour utiliser les données mobiles) -+Sélectionnez le répertoire racine de l'extension. -+Les cookies de sont autorisés uniquement pour cette session. -+Confirmer les préférences de synchronisation -+RSN -+Ajuster la conversion en fonction de l'entrée précédente -+Afficher le panneau de la &vérification orthographique -+(Revenir à la capture d'écran d'origine) -+Mettre à jour & -+SSID -+- -+Les informations de connexion au compte n'ont pas encore été saisies. -+URL de configuration automatique -+URL : -+Avancer -+ jours restants -+Vous avez choisi de ne pas synchroniser les mots de passe. Vous pouvez à tout moment modifier vos paramètres de synchronisation, si vous changez d'avis. -+Lancer -+ -+ ne parvient pas à accéder au réseau. -+ -+ Il est possible que votre pare-feu ou votre antivirus considère -+ -+ comme un intrus dans votre ordinateur et qu'il bloque ses tentatives de connexion à Internet. -+Ce certificat a été vérifié pour les utilisations suivantes : -+Petit problème ! Une erreur est survenue lors de l'inscription de ce périphérique. Veuillez réessayer ou contacter votre représentant de l'assistance technique. -+Ajouter aux favoris -+Gérer les certificats... -+Analyse du périphérique... -+PYJJ -+Web Store -+Annuler l'épinglage des onglets -+Favori -+Sélectionnez votre langue : -+Réessayer le téléchargement -+Configurer la synchronisation des mots de passe -+Nom d'utilisateur : -+Enregistrer la p&age sous... -+Vos données sur tous les sites Web -+Un problème est survenu lors de l'extraction de l'image sur l'ordinateur. -+Lancer l'application -+Dubeol-sik -+Remplacé -+Afficher les cookies et autres données de site... -+Si vous pensez avoir cerné les risques, vous pouvez . -+Apparence -+Créer des raccourci&s vers des applications... -+Exécuter le flash PPAPI dans le processus du moteur de rendu -+Définir en tant que navigateur par défaut -+Veuillez choisir un nouveau code PIN. -+ () -+Autre -+&Options -+Impossible de charger la page d'arrière-plan "". -+À quel niveau rencontrez-vous des problèmes ? (Champ obligatoire) -+Retour à la sécurité -+Eten -+Ce site répertorie tous ses certificats valides dans le système DNS. Un certificat non répertorié a cependant été utilisé par le serveur. -+Options de reconnaissance vocale -+Tout sélectionner -+Impossible de charger le fichier "" pour le script de contenu, car ce fichier n'est pas codé en UTF-8. -+&Annuler -+Désactiver temporairement la personnalisation des conversions, les suggestions basées sur l'historique et le dictionnaire utilisateur -+Les cookies de sont autorisés. -+Au fil du temps, la zone ci-dessous affichera les huit sites que vous avez le plus visités. -+Le plug-in a besoin de votre autorisation pour s'exécuter. -+Échec de création de clé privée -+Ouvrir tous les favoris dans une fenêtre de navigation privée -+Placer dans la file d'attente -+Erreur de certificat serveur inconnue -+Mode de saisie du coréen -+&Plein écran -+ -+ -+ Vous pouvez essayer de diagnostiquer le problème en procédant comme suit : -+ -+ -+Bienvenue sur votre page d'accueil ! -+Vos modifications seront prises en compte au prochain démarrage de . -+Adresse du matériel : -+Lecture seule -+Erreur d'importation du certificat serveur -+Données stockées localement -+Tous les fichiers de vont être effacés. -+Modèle du périphérique : -+Afficher dans le Finder -+Nom X.500 -+Vous devez sélectionner au moins un type de données à synchroniser. -+Tout afficher -+Ouvrir tous les favoris -+Clavier danois -+Cette fonctionnalité permet de réaliser un rendu hors écran de la texture, au lieu d'un affichage direct. -+Partiellement activé -+Votre système Sandbox est correctement configuré. -+Ne pas installer -+Activer la recherche instantanée pour accélérer la recherche et la navigation -+Utiliser par défaut -+Non essentielle -+Fenêtres pop-up -+Dernière modification : -+Désélectionné -+Sécurité -+Rechercher... -+Le script de la page utilisait trop de mémoire. Rafraîchissez la page pour réactiver le script. -+Signature du code individuel Microsoft -+Mozilla Firefox -+Page Web inaccessible -+Recadrer l'image -+Si vous fermez maintenant, le téléchargement sera annulé. -+Coller -+Retour -+Impossible de graver l'image. -+Mode de saisie du Chewing -+Province -+JavaScript a été bloqué sur cette page. -+Remarque : Lorsque vous cliquez sur "Envoyer", Google Chrome OS -+ joint à votre envoi un journal des événements système de -+ votre périphérique. Ces informations nous permettent de diagnostiquer les -+ problèmes, de comprendre comment vous interagissez avec votre -+ périphérique et d'améliorer les performances de ce dernier. Les -+ informations personnelles fournies sciemment dans vos commentaires ou -+ involontairement dans les journaux système et la capture d'écran sont -+ protégées conformément à nos Règles de confidentialité. -+ Si vous ne souhaitez pas envoyer de journaux système, décochez la case -+ "Inclure les informations système". -+Interdire à tous les sites de stocker des données -+Trier par nom -+Afficher un aperçu des onglets... -+Annuler l'importation -+Ce serveur envoie des données que ne comprend pas. Veuillez signaler un bug et inclure la liste des raw. -+Calcul de la durée restante -+Mode de saisie Google du japonais (pour clavier américain) -+Envoi de la requête... -+Parlez maintenant -+Impossible d'installer le package : "" -+Modèle : -+Bloquer tous les cookies tiers -+Remplacer par -+Espace -+Arrêt du fonctionnement -+Préférences -+Nom inconnu -+Nom -+Choisir un nouveau code PIN -+ [] -+Erreur d'exportation de fichier PKCS #12 -+Le répertoire racine de l'extension doit être indiqué. -+Miniature supprimée -+Tout développer... -+Aie aie aie -+Choisir les expressions en arrière-plan, sans déplacer le pointeur -+Plu&s petit -+Afficher le clavier en superposition -+C&opier l'URL de l'image -+OK -+Aucun réseau détecté -+Charger l'extension non empaquetée... -+page -+Active l'interface utilisateur et le code de support pour le processus du service de communication à distance, de même que le plug-in client. Avertissement : ce service n'est actuellement disponible que pour les tests de développeurs. Si vous ne faites pas partie de l'équipe de développement et ne figurez pas sur la liste blanche, aucun élément de l'interface utilisateur activée ne fonctionnera. -+Clavier turc -+Modifier le favori -+Couleur -+Personnaliser les paramètres de synchronisation... -+Activation de votre service Internet mobile -+ -+Ouvrir dans un onglet standard -+ - -+Portrait -+ days ago -+Active un service en arrière-plan qui connecte le service aux éventuelles imprimantes installées sur cet ordinateur. Une fois ce labo activé, vous pouvez lancer en vous connectant à votre compte Google via Options/Préférences dans la section Options avancées. -+Outils de &développement -+Le répertoire racine de l'extension est incorrect. -+ID de clé de l'objet du certificat -+Téléchargements -+Le stockage du certificat client généré par a réussi. -+Sélectionnée -+Suspendre -+Taille sur le disque : -+ID du processus -+Réduire -+Expire le -+Votre administrateur a désactivé l'accès aux fichiers locaux sur votre ordinateur. -+Erreur de connexion SSL -+Envoyer -+Virgule -+&Pause -+Parcourir... -+Mode de saisie Google du japonais (pour clavier Dvorak américain) -+Police à largeur fixe -+Stockage de session -+Page en arrière-plan : -+Le serveur a renvoyé un certificat client incorrect. Erreur  () -+Signature de document Microsoft -+Bloqué -+Gérer les paramètres d'impression... -+Cette page Web a désactivé la saisie automatique dans ce formulaire. -+Clavier hongrois -+Les versions en développement permettent de tester de nouvelles idées, mais elles peuvent s'avérer très instables. Nous vous prions d'agir avec précaution. -+Ajouter un dossier... -+Mode de saisie du japonais (pour clavier Dvorak américain) -+Signaler un bug -+&Toujours ouvrir les fichiers de ce type -+Disque optique -+Nom commun -+Très grande -+Modification terminée -+Objet -+Opérateur : -+Algorithme de signature du certificat -+Cette fonctionnalité permet d'afficher un onglet d'aperçu avant de lancer une impression. -+Autre nom de l'objet du certificat -+Activer la saisie automatique pour remplir les formulaires Web d'un simple clic -+Le site Web à l'adresse a été signalé comme étant un site de phishing. Ces sites tentent d'amener les internautes à divulguer leurs informations personnelles en se faisant passer pour des institutions de confiance, telles que des banques. -+Rechercher directement sur -+Connectez-vous à pour exporter le certificat client. -+Créer un compte Google maintenant -+État Sandbox -+Retirer de la liste -+rapide -+&Effacer les données de navigation… -+Vérification des mises à jour... -+Télécharger les mises à jour de sécurité essentielles -+Package incorrect. Détails : "". -+Continuer à bloquer les cookies -+Ligne de commande -+Coller l'URL et y a&ccéder -+Désactiver -+Build officiel -+Se connecter à un réseau Wi-Fi -+Périphérique inconnu -+Supprimer les cookies et autres données de site -+URL saisies -+Utiliser les touches , et . pour paginer une liste d'entrées -+Vider la mémoire -+Supprimer les éléments sélectionnés -+Toujours -+de moins d'une heure -+Aucun réseau n'est disponible. -+Supprimer les cookies et autres données de site et de plug-in -+Intervertir les touches Rechercher et Ctrl gauche -+Faites glisser trois doigts sur la surface de votre trackpad pour afficher un aperçu de tous vos onglets. Cliquez sur une vignette pour la sélectionner. Idéal en mode plein écran. -+Nouveau ! Configurer la synchronisation des mots de passe -+Échec de la tentative de connexion au serveur -+Désactiver les notifications de -+Les fichiers suivants ont été créés : -+ -+Extension : -+Fichier de clé : -+ -+Conservez votre fichier de clé en lieu sûr. Vous en aurez besoin lors de la création de nouvelles versions de l'extension. -+&Oui -+Ouvrir les fichiers -+Clavier suédois -+Mémoire JavaScript -+Quitter le mode plein écran -+Hiérarchie des certificats -+Afficher l'onglet existant si l'URL associée est demandée dans un autre -+&Afficher -+Vos données personnelles sur , et sur  autres sites Web -+SMS de -+Afficher la s&ource -+Zoom arrière -+C&opier l'URL du fichier audio -+Importer et associer au périphérique... -+() () -+Plug-ins (par ex. Adobe Flash Player, QuickTime, etc.) -+Empaqueter l'extension... -+Vérifier l'orthographe lors de la frappe -+Échec de la traduction en raison d'un problème de connexion réseau -+Code PIN incorrect. Veuillez réessayer. Nombre de tentatives restantes : -+Vous pouvez effectuer une recherche directement à partir du champ ci-dessus. -+Ajouter les expressions au premier plan -+Lorem ipsum dolor sit amet, consectetur adipiscing elit. -+Opérateur -+Confirmer l'installation -+(Mot clé : ) -+Sensibilité : -+ -diff --git a/tools/grit/grit/testdata/generated_resources_iw.xtb b/tools/grit/grit/testdata/generated_resources_iw.xtb -new file mode 100644 -index 0000000000..86b55334c0 ---- /dev/null -+++ b/tools/grit/grit/testdata/generated_resources_iw.xtb -@@ -0,0 +1,4 @@ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/generated_resources_no.xtb b/tools/grit/grit/testdata/generated_resources_no.xtb -new file mode 100644 -index 0000000000..913638ba4e ---- /dev/null -+++ b/tools/grit/grit/testdata/generated_resources_no.xtb -@@ -0,0 +1,4 @@ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/grit_part.grdp b/tools/grit/grit/testdata/grit_part.grdp -new file mode 100644 -index 0000000000..c8e9d92692 ---- /dev/null -+++ b/tools/grit/grit/testdata/grit_part.grdp -@@ -0,0 +1,5 @@ -+ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/header.html b/tools/grit/grit/testdata/header.html -new file mode 100644 -index 0000000000..8e9d10ec50 ---- /dev/null -+++ b/tools/grit/grit/testdata/header.html -@@ -0,0 +1,39 @@ -+ -+[$~TITLE~$] -+ -+ -+ -+ -+[EXTRA_META] -+ -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/homepage.html b/tools/grit/grit/testdata/homepage.html -new file mode 100644 -index 0000000000..cce4f2cf35 ---- /dev/null -+++ b/tools/grit/grit/testdata/homepage.html -@@ -0,0 +1,37 @@ -+ -+Google Desktop Search -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+
    Google Desktop Search

    -+
    -+ -+ -+ -+
    -+[$~LINKS~$] -+
    -+ -+ -+ -+ -+ -+
     
      Desktop Preferences
    -+

    Search your own computer.

    -+[$~MESSAGE~$]
    -+
    [$~SETHOMEPAGE~$][$~BOTTOMLINE~$]

    -+

    ©2005 Google - Searching [NUM_ITEMS] items

    -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/hover.html b/tools/grit/grit/testdata/hover.html -new file mode 100644 -index 0000000000..b8f9ce0200 ---- /dev/null -+++ b/tools/grit/grit/testdata/hover.html -@@ -0,0 +1,177 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+Sidebar -+Minibar -+Close -+
    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+
    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
      
    -+
    -+ -+ -+
    -+ -+
    -+
    -+ -+ -+ -diff --git a/tools/grit/grit/testdata/include_test.html b/tools/grit/grit/testdata/include_test.html -new file mode 100644 -index 0000000000..e08f2e2e8a ---- /dev/null -+++ b/tools/grit/grit/testdata/include_test.html -@@ -0,0 +1,31 @@ -+ -+ -+should be kept -+ -+in the middle... -+ -+should be removed -+ -+ -+ -+should be removed -+ -+ should be removed because outer expr is False -+ -+should be removed -+ -+ -+ -+ -+ -+ nested true should be kept -+ -+ -+ should be removed -+ -+ -+ -+ silbing true should be kept -+ -+ -+at the end... -diff --git a/tools/grit/grit/testdata/included_sample.html b/tools/grit/grit/testdata/included_sample.html -new file mode 100644 -index 0000000000..7150ffcbea ---- /dev/null -+++ b/tools/grit/grit/testdata/included_sample.html -@@ -0,0 +1 @@ -+Hello Include! -diff --git a/tools/grit/grit/testdata/indexing_speed.html b/tools/grit/grit/testdata/indexing_speed.html -new file mode 100644 -index 0000000000..db1787b0e2 ---- /dev/null -+++ b/tools/grit/grit/testdata/indexing_speed.html -@@ -0,0 +1,58 @@ -+ -+Google Desktop Search Index Speed -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ Go to Google Desktop Search  -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+
     Index SpeedIndex Speed -+ Help | About Google Desktop Search
    -+ -+

    -+To make your emails, files, and previously viewed web pages searchable, Google Desktop Search -+needs to index them. This indexing process is currently occuring in the background -+and your computer performance is minimally impacted. -+

    -+You have the option of speeding up this process. -+

    Warning: Speeding up indexing will cause your computer -+to become unusable for many minutes, depending on how many items need to be indexed. FAST INDEXING IS NOT -+RECOMMENDED. -+
     
    -+

    -+ -+
    -+

    -+ -+
    -+
    -+ -+

     
    -+ -+ -+ -+
    -+ -+ -+ -+ -+
    Google Desktop Search Home - Status - About Google Desktop Search - [$~BUILDNUMBER~$] - ©2005 Google

    -+ -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/install_prefs.html b/tools/grit/grit/testdata/install_prefs.html -new file mode 100644 -index 0000000000..eca0b56de5 ---- /dev/null -+++ b/tools/grit/grit/testdata/install_prefs.html -@@ -0,0 +1,92 @@ -+ -+Google Desktop Search: Initial Preferences -+ -+ -+ -+ -+ -+ -+ -+

    -+ -+
    -+
    To continue, please set these initial preferences:

    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
     
     
      -+
    -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+
    Deskbar
    -+ -+ -+
    -+
      -+
    You can change these and other preferences at any time.
    -+


    -+

    -+
    -+[SCRIPT] -+ -+ -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/install_prefs2.html b/tools/grit/grit/testdata/install_prefs2.html -new file mode 100644 -index 0000000000..18380397c2 ---- /dev/null -+++ b/tools/grit/grit/testdata/install_prefs2.html -@@ -0,0 +1,52 @@ -+ -+Indexing has Started -+ -+ -+ -+ -+ -+ -+ -+
    -+

    -+
    -+
    -+One-time indexing has started.

    -+An index is being prepared on your computer to allow you -+to search your information as fast as you can search the web.

    -+
  • This is a one-time process that may take several hours. -+
  • You may continue to use your computer as usual and it is safe to shut down your computer. -+
  • Indexing will be performed only when your computer is idle. -+ -+ -+


    -+ -+

  • -+ -+
    -+ -+[SCRIPT] -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/klonk-alternate-skeleton.rc b/tools/grit/grit/testdata/klonk-alternate-skeleton.rc -new file mode 100644 -index 0000000000000000000000000000000000000000..5f2c82a55469ddaab246c095826ad9e6743c0015 -GIT binary patch -literal 1088 -zcmbW0Pfr3t48`AhKZV)z#sGrI5!gjnU?DC>IT2z!82=r_L=!)}zjnmk5b$6oGo9&7 -z+t=4lu9UG-Ujxl_t%b{59ih$9PSBn!lW7`iGrKMm&Q10vTRK5!yRJHlRN`fcWril@ -zv|?uHM))d_NBa7`nW9TQ&PZ3tsax6ojav@U&9TYdHduz6k{G4GFTfpX_hk&`!z0F` -z!gJ>6WBh&UO&i_oS+VOvUfcD9JR=y&;3OxP2%KT$#JB9W=UtgQpDT@>(E^#^A;oG% -z4omjIK7rLXcRgmyS+%u_Gl2`MhOxMB{GGM&5o6cXFE~=G -z`!#F5=z%_bq95y7+aIx?IdcSN`A)xX^vZjCS7lnS#=iZ)E7W%eX8!kr-#RDO36^!o -Qqn&wY8qX0d7T}2V4SbP+*8l(j - -literal 0 -HcmV?d00001 - -diff --git a/tools/grit/grit/testdata/klonk.ico b/tools/grit/grit/testdata/klonk.ico -new file mode 100644 -index 0000000000000000000000000000000000000000..d371b214dc366249870efccc5da278d023aa91f1 -GIT binary patch -literal 766 -zcmeH_F%H5o5CqSFL>Ve71Sxq1;TtsMEB*!Fv6LbmDQFSUL1mXjO7OC0gpl|G?B1ML -zXS=a1V(2`di0U>FnQ~o{oUDnF5j(}bxAgSuhE8lMu~rkI8Ju%mb%Im^Xd<+ZwEgwd -zFTg+WQOj5lfvO*4mbEA^bCj9KHh65vjx^zvsKW{eA8|Ah`w&r;%!`QgmEiG3hXCcC -L+@V2V6oA7MJIRBx - -literal 0 -HcmV?d00001 - -diff --git a/tools/grit/grit/testdata/klonk.rc b/tools/grit/grit/testdata/klonk.rc -new file mode 100644 -index 0000000000000000000000000000000000000000..35652c4e6dd7cf7b7f62f637e191acf66f487235 -GIT binary patch -literal 9824 -zcmeI2+j1L48poSUd1!LS!j6*Z-q>7MTIeClrf{=b{yW=KLKoQA`29(tkA -z?@<`g*P*W;F2X@LqqP?P!IgxQa2&e)&gmcUJfiQMr{-PocF21|OVCckGsY~31#sNt -zeuJJaU(OhLWaHAYxy#{kNExfq8uQ5J2xc`jLo2kyURV$HuoL#fZm7|_&ii)Q3SZFE -z;@$|W^lb4S@e23#yIdxsED4)%Ix5vi$fg&b@^yerB!M>k-sfJ2-!(XtBx>~E;y0>; -zywqpO@eUBz4c2yv49m3k+_Z88eb3Rg>+A-4?GCk8rmyLEuD7;k@iyBQuQz|u4r}P| -z1pk!hKgO!w#>STMq~-8ViH-G#etL?RCgF{OzaBBS8aA-k=%+1wau1JP!(#WbwJk2e -z{FW=3II|6mUA$wTS=-Ei$KrzUMVn6ea?kwXHeRp*%qrtH8Cm5n-|(IYVUuHA@wRN;~7h6y+xyz_&R~;+XxM^eZ-_q~|%%b86_{3Asa-8FBk+Z7c-kJgN>UjHR -zv*J6C_vNv`hUxGkXMvL0T0vKhVQf$p6QjfeUR}fgl_wW2W!gk%O?IOa`tbcYLDwE{AY?>BR88vkIj3pcp9ftwy~b;A8i-;T|_p=$nY5yWU!`jTE^ib -ze*F+mE-Vf$>e;=5g*fg0^w_NUeElxZA2EAWiGRui^1Zl<=<)P1 -zF&Y;=yo$%KVIA>VGwa=@)kgQbrt31jq~WuvvL2VO`$zNqGSmHCaU;Y2q0yQ$JF7mTwL~ub{sOMb^Vh8GFZ(K1F-x>#wroJR -z&tF1@??TN-{BD^HbgJ;mLeTx&a -ztSZO1p-!t5NvMLINn_JEi1N%h$mrKfeZ%Sxtv*(Sq%E`|5` -zMQa!2rJ*fu!l%|$%^a7pE^XVFE$AM-((pNcct~BK8YqR1Sd~Aqmi*&@D)rQ&bN`YW -zMPvC%+;<0?G_uSf2bldXz_x`Rp$tXUa07m0#5g^O>n*TJE4PW#|}5_jztxOjO*+fAM}< -zk=Lii5sD#879SKTSIp++>5AlgXumxIv246U-XKqCe;}^ATDIP+P{%8`Yynw2Uilpc -z$xha}X;{ahB+#YVajq(xJ|2|kCBqoURxZc-PCWGR&NeH+c%h>-Yw>z7_{+>=5WWql;yg~F}V-&+XR>jna$uG|ylUKW)Rw*m^ -z_oOjp@vHny>%lMrW)jt@&DG$}J`tOC!twxncz`|R{U9wplS^%1SD7h)zLPS$9KxSJ -z^(luqF00#DmestFZxDq%2fL5@KE>#HI|)#R(g69An@YFD|(_t^K?Y(=LYvGR$s)LKbvaYc(JPp$Xb2G?a>eC9KE-cEhZ -zHSZ3+_C$Rze-w`BSsn7ZgI%TJO=9FfdDBy)V;pqaYpnOHjNdZ)cZhIWOV;71NPE_b -z5ZwYd@EV=tI))^?mN>3>KBO~=3-s|NvQu_bO!m`Xy&s`1RS8A9bec9lO`@(ym$)sX -zMVVq?wjta)kvTJp%Bk>bSh}4@HcmwuW}T<$ta~!gT03ja*d|hI1w9*Uk>}TwPvL12 -z=Q{J$UgQ8RXmu+(2GDd)J#{>6mrEh;W{57|8=6JgB)U>?#`vQXEaBEZgsP}6H0c~I -zlTn_wQLB~3>U1IQ2y}Rh=cM|##66Rnd!p7F(K=LbM6B`LtO3?OS3Ko>03~gD6g5tu -zOSRooa>4*SqvO;gSO;d)IuFc4e&rSY3#4arR~e}tmqXie5w!0rzg2#y{KWm2%CD85 -zD?e8LTlv1?UR>st9pKlDtGM^mfuA&df=7MIT`QQ#k8mnxoriygx5#|&^UZ&6F?Nx! -z2jMH^+zTJm>H?vU#6L!6XLz9~{RHheL_xo4SVUcx*(c|e8ZfVRzJC37^PM7DoUXW9 -zRu0v_b;|ztF`73W!u5N4HWX!l^ZH1;i+3m{&0Ya4gg*c` -C>9bG( - -literal 0 -HcmV?d00001 - -diff --git a/tools/grit/grit/testdata/ko_oem_enable_bug.html b/tools/grit/grit/testdata/ko_oem_enable_bug.html -new file mode 100644 -index 0000000000..f2c199cc15 ---- /dev/null -+++ b/tools/grit/grit/testdata/ko_oem_enable_bug.html -@@ -0,0 +1 @@ -+아웃룩 -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/ko_oem_non_admin_bug.html b/tools/grit/grit/testdata/ko_oem_non_admin_bug.html -new file mode 100644 -index 0000000000..b9e8a1f288 ---- /dev/null -+++ b/tools/grit/grit/testdata/ko_oem_non_admin_bug.html -@@ -0,0 +1 @@ -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/mini.html b/tools/grit/grit/testdata/mini.html -new file mode 100644 -index 0000000000..8ac0a231a0 ---- /dev/null -+++ b/tools/grit/grit/testdata/mini.html -@@ -0,0 +1,36 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+ -+ -+ -+ -+
      
    -+
    -+
    -diff --git a/tools/grit/grit/testdata/oem_enable.html b/tools/grit/grit/testdata/oem_enable.html -new file mode 100644 -index 0000000000..db6b85eca6 ---- /dev/null -+++ b/tools/grit/grit/testdata/oem_enable.html -@@ -0,0 +1,106 @@ -+ -+Google Desktop Search Download -+ -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+ -+
    -+
    Google Desktop Search
                Search your own -+computer.

    -+ -+ -+ -+ -+ -+
    -+
  • Find your email, files, web history and chats instantly -+
  • View web pages you've seen, even when you're not online -+
  • Search as easily as you do on Google -+

    Google Desktop Search finds:

    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    Outlook  Email from Outlook, Outlook Express, & -+ Thunderbird
    Internet Explorer  Web history -+ from IE/Firefox/Mozilla/Netscape
    Text  Files in Word, -+ Excel, Powerpoint, PDF, & media formats
    AOL IM  Chats from AOL -+ Instant Messenger
     
     About Desktop -+ Search   Screenshots   -+ Help   Contact -+ Us
  •     -+ -+ -+ -+

    -+
    By using, you agree to our
    Terms & -+ Conditions
    and Privacy -+ Policy
    -+

    -+
    -+

    -+

    * Automatically starts when you turn on -+ your computer
    -+

    -+

    -+
    ©2005 Google -+

    -diff --git a/tools/grit/grit/testdata/oem_non_admin.html b/tools/grit/grit/testdata/oem_non_admin.html -new file mode 100644 -index 0000000000..8b7ca13e21 ---- /dev/null -+++ b/tools/grit/grit/testdata/oem_non_admin.html -@@ -0,0 +1,39 @@ -+ -+Google Desktop Search Preferences -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+
    -+


    We're sorry, but you need administrator access to -+enable Desktop Search.

    -+

    To install or run Google Desktop Search you need administrator access on this -+computer. Please try installing again once you have administrator -+access.

    -+


    -+
    -diff --git a/tools/grit/grit/testdata/onebox.html b/tools/grit/grit/testdata/onebox.html -new file mode 100644 -index 0000000000..c24ff043a5 ---- /dev/null -+++ b/tools/grit/grit/testdata/onebox.html -@@ -0,0 +1,21 @@ -+Google Desktop Search Results -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/oneclick.html b/tools/grit/grit/testdata/oneclick.html -new file mode 100644 -index 0000000000..32dc6459dd ---- /dev/null -+++ b/tools/grit/grit/testdata/oneclick.html -@@ -0,0 +1,34 @@ -+[HEADER] -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ [EMAIL_TOP_CHROME] -+ -+

    -+ -+ [EMAIL] -+
    -+

    -+ [FREQ_TOP_CHROME] -+

    -+ -+ [$~FREQ~$] -+
    -+

    -+ [RECENT_TOP_CHROME] -+ -+ [$~RECENT~$] -+
    -+

    -+

    -+ -+ -+[FOOTER] -diff --git a/tools/grit/grit/testdata/password.html b/tools/grit/grit/testdata/password.html -new file mode 100644 -index 0000000000..16007a1ac0 ---- /dev/null -+++ b/tools/grit/grit/testdata/password.html -@@ -0,0 +1,37 @@ -+ -+Password Required -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+
    Google Desktop Search

    -+
    -+ -+ -+
    -+ -+ -+ -+
    Password required:   -+ -+   -+
    -+ -+
    -+
    [$~BOTTOMLINE~$]

    -+

    ©2005 Google

    -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/preferences.html b/tools/grit/grit/testdata/preferences.html -new file mode 100644 -index 0000000000..b37412436b ---- /dev/null -+++ b/tools/grit/grit/testdata/preferences.html -@@ -0,0 +1,234 @@ -+ -+Google Desktop Search Preferences -+ -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+
    -+Go to Google Desktop Search  -+ -+ -+ -+ -+
    Preferences -+Preferences Help -+
    -+ -+
    -+ -+ -+ -+ -+
    -+Save your preferences when finished.
    -+ -+[STATUS-MESSAGE] -+ -+ -+
    Preferences (changes apply to Google Desktop Search application)
    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    Search types
    Index the following items so that you can -+search for them:
     
    -+
    -+ -+ -+ -+ -+ -+
    -+
    -+
    -+ -+ -+
    -+ -+ -+
    -+ -+
    -+ -+
    -+
    -+ -+
    -+ -+
    -+

    -+ -+
    -+
    -+
    Plug-ins
    Index these additional items:

    -+[ADDIN-DO] -+[ADDIN-OPTIONS]

    -+To install plug-ins to index other items, visit the -+Plug-ins Download page.
    -+
    Don't search these items
    -+
    -+c:\Documents and Settings\username\Private Stuff
    -+http://www.domain.com/
    -+
     
    -+
    -+
    Search Box Display -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+
    Deskbar
    -+ -+ -+
    -+ -+ -+ -+
    -+ -+
    Number of Results -+
    Google integration -+ -+ -+ -+
    -+ Your personal results are private from Google. -+
    -+
    Help us improve -+ -+
    -+ -+ -+ -+ -+
    Save your preferences -+when finished.
    -+ -+

    [$~BOTTOMLINE~$]
    -+
    ©2005 Google
    -+
    -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/preprocess_test.html b/tools/grit/grit/testdata/preprocess_test.html -new file mode 100644 -index 0000000000..13ece9a9f6 ---- /dev/null -+++ b/tools/grit/grit/testdata/preprocess_test.html -@@ -0,0 +1,7 @@ -+ -+should be kept -+ -+in the middle... -+ -+should be removed -+ -diff --git a/tools/grit/grit/testdata/privacy.html b/tools/grit/grit/testdata/privacy.html -new file mode 100644 -index 0000000000..1d45f4a539 ---- /dev/null -+++ b/tools/grit/grit/testdata/privacy.html -@@ -0,0 +1,35 @@ -+[!] -+title Privacy and Google Desktop Search -+template -+privacy_bottomline -+hp_image -+ -+ -+ -+
    -+

    Privacy and Google Desktop Search

    -+ -+

    Google is committed to making search on your desktop as easy -+as searching the web. We recognize that privacy is an important issue, -+so we designed and built Google Desktop Search with respect for your privacy. -+

    -+So that you can easily search your computer, the Google Desktop Search application indexes -+and stores versions of your files and other computer activity, -+such as email, chats, and web history. These versions may also be mixed -+with your Web search results to produce -+results pages for you that integrate relevant content from your computer and -+information from the Web. -+

    -+Your computer's content is not made accessible to Google or anyone else without your explicit permission. -+ -+

    You can read the -+Privacy Policy -+and Privacy FAQ online. -+ -+

    -+ -+

    -+ -+
    -+[$~PRIVACY_BOTTOMLINE~$] - ©2005 Google -+
    -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/quit_apps.html b/tools/grit/grit/testdata/quit_apps.html -new file mode 100644 -index 0000000000..a501b0e2bf ---- /dev/null -+++ b/tools/grit/grit/testdata/quit_apps.html -@@ -0,0 +1,49 @@ -+ -+Google Desktop Search Preferences -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+
    -+


    To start using Google Desktop Search, we may need to close the following programs if they are running:

    -+

    You can start these programs once Google Desktop Search is running.

    -+ -+
  • AOL Instant Messenger -+
  • Firefox -+
  • Internet Explorer -+
  • Microsoft Excel -+
  • Microsoft Outlook -+
  • Microsoft Word -+
  • Mozilla -+
  • Mozilla Thunderbird -+
  • Netscape -+
  • Opera -+
  • Other web browsers -+ -+

    This will take only a few seconds to complete.

  • -+

    -+

    -+
    -diff --git a/tools/grit/grit/testdata/recrawl.html b/tools/grit/grit/testdata/recrawl.html -new file mode 100644 -index 0000000000..0401e7c2b0 ---- /dev/null -+++ b/tools/grit/grit/testdata/recrawl.html -@@ -0,0 +1,30 @@ -+ -+Refresh index -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+
    Google Desktop Search -+
    -+
    -+
    Google Desktop Search is now recrawling your drive to index new files.
    -+
    Note that new files are indexed automatically, and this step is generally not needed.
    -+
    Click here to continue.
    -+ -+
    -+[$~BOTTOMLINE~$] -+

    ©2005 Google

    -+
    -+ -+ -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/resource_ids b/tools/grit/grit/testdata/resource_ids -new file mode 100644 -index 0000000000..d5d440d57f ---- /dev/null -+++ b/tools/grit/grit/testdata/resource_ids -@@ -0,0 +1,13 @@ -+{ -+ "SRCDIR": ".", -+ "test.grd": { -+ "messages": [100, 10000], -+ }, -+ "substitute_no_ids.grd": { -+ "messages": [10000, 20000], -+ }, -+ "<(FOO)/file.grd": { -+ }, -+ "<(SHARED_INTERMEDIATE_DIR)/devtools/devtools.grd": { -+ }, -+} -diff --git a/tools/grit/grit/testdata/script.html b/tools/grit/grit/testdata/script.html -new file mode 100644 -index 0000000000..f177d9c30e ---- /dev/null -+++ b/tools/grit/grit/testdata/script.html -@@ -0,0 +1,38 @@ -+ -diff --git a/tools/grit/grit/testdata/searchbox.html b/tools/grit/grit/testdata/searchbox.html -new file mode 100644 -index 0000000000..9eccba99a5 ---- /dev/null -+++ b/tools/grit/grit/testdata/searchbox.html -@@ -0,0 +1,22 @@ -+ -+ -+ -+ -+ -+
    Go to Google Desktop Search   -+ -+ -+ -+ -+
    -+ -+ -+
    -+[$~LINKS~$] -+
    -+
    -+[$~FLAGS~$]
      Desktop Preferences
      [DELETE_NAME]
    -+ -+ -+
     
    -+
    -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/sidebar_h.html b/tools/grit/grit/testdata/sidebar_h.html -new file mode 100644 -index 0000000000..e103e8f8db ---- /dev/null -+++ b/tools/grit/grit/testdata/sidebar_h.html -@@ -0,0 +1,82 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+
    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
     Google Desktop Search
    -+
    -+ -+
    -+ -+[HEADER_SECTION1] -+[CONTENT_INBOX] -+ -+ -+ -+[HEADER_SECTION2] -+[CONTENT_HIST] -+ -+ -+ -+[CONTENT_NEWS] -+[CONTENT_OTHER] -+ -+ -+ -+ -+ -+
    -+ -+ -+ -+[SCRIPT] -+ -diff --git a/tools/grit/grit/testdata/sidebar_v.html b/tools/grit/grit/testdata/sidebar_v.html -new file mode 100644 -index 0000000000..e040d8ec59 ---- /dev/null -+++ b/tools/grit/grit/testdata/sidebar_v.html -@@ -0,0 +1,267 @@ -+ -+Google Desktop Search Sidebar -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+
    -+ -+ -+ -+ -+ -+ -+
    Google Desktop Search  Web 
    -+
    -+ -+

    -+
    -+
     News
    -+
    -+ -+ -+[CONTENT_NEWS] -+

    -+ -+ -+
    -+
     Email
    -+
    -+ -+ -+[CONTENT_INBOX] -+

    -+ -+ -+
    -+
     Related History
    -+
    -+ -+ -+[CONTENT_HIST] -+

    -+ -+ -+ -+
    -+
     Recent
    -+
    -+ -+ -+[CONTENT_RECENT] -+

    -+ -+ -+ -+
    -+
     Frequently Visited
    -+
    -+ -+ -+[CONTENT_POPULAR] -+

    -+ -+ -+ -+
    -+
     Implicit Query Debug
    -+
    -+ -+ -+[CONTENT_QUIB_DEBUG] -+ -+ -+ -+ -+[CONTENT_OTHER] -+ -+[SCRIPT] -+ -+ -diff --git a/tools/grit/grit/testdata/simple-input.xml b/tools/grit/grit/testdata/simple-input.xml -new file mode 100644 -index 0000000000..92827fa4b5 ---- /dev/null -+++ b/tools/grit/grit/testdata/simple-input.xml -@@ -0,0 +1,52 @@ -+ -+ -+ -+ -+ Hello earthlings! -+ -+ -+ -+ -+ -+ -+ -+ -+ Go! -+ -+ Hello %sJoi, how are you doing today? -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/simple.html b/tools/grit/grit/testdata/simple.html -new file mode 100644 -index 0000000000..4392d23e98 ---- /dev/null -+++ b/tools/grit/grit/testdata/simple.html -@@ -0,0 +1,3 @@ -+

    -+ Hello! -+

    -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/source.rc b/tools/grit/grit/testdata/source.rc -new file mode 100644 -index 0000000000..fbc72284e9 ---- /dev/null -+++ b/tools/grit/grit/testdata/source.rc -@@ -0,0 +1,57 @@ -+IDC_KLONKMENU MENU -+BEGIN -+ POPUP "&File" -+ BEGIN -+ MENUITEM "E&xit", IDM_EXIT -+ MENUITEM "This be ""Klonk"" me like", ID_FILE_THISBE -+ POPUP "gonk" -+ BEGIN -+ MENUITEM "Klonk && is [good]", ID_GONK_KLONKIS -+ END -+ END -+ POPUP "&Help" -+ BEGIN -+ MENUITEM "&About ...", IDM_ABOUT -+ END -+END -+ -+IDD_ABOUTBOX DIALOGEX 22, 17, 230, 75 -+STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -+CAPTION "About" -+FONT 8, "System", 0, 0, 0x0 -+BEGIN -+ ICON IDI_KLONK,IDC_MYICON,14,9,20,20 -+ LTEXT "klonk Version ""yibbee"" 1.0",IDC_STATIC,49,10,119,8, -+ SS_NOPREFIX -+ LTEXT "Copyright (C) 2005",IDC_STATIC,49,20,119,8 -+ DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP -+ CONTROL "Jack ""Black"" Daniels",IDC_RADIO1,"Button", -+ BS_AUTORADIOBUTTON,46,51,84,10 -+END -+ -+IDD_DIFFERENT_LENGTH_IN_TRANSL DIALOGEX 22, 17, 230, 75 -+STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -+CAPTION "Bingobobbi" -+FONT 8, "System", 0, 0, 0x0 -+BEGIN -+ LTEXT "Howdie dodie!",IDC_STATIC,49,10,119,8,SS_NOPREFIX -+ LTEXT "Yo froodie!",IDC_STATIC,49,20,119,8 -+END -+ -+STRINGTABLE -+BEGIN -+ IDS_SIMPLE "One" -+ IDS_PLACEHOLDER "%s birds" -+ IDS_PLACEHOLDERS "%d of %d" -+ IDS_REORDERED_PLACEHOLDERS "$1 of $2" -+ // Won't be in translations list because it has changed -+ IDS_CHANGED "This was the old version" -+ IDS_TWIN_1 "Hello" -+ IDS_TWIN_2 "Hello" -+ IDS_NOT_TRANSLATEABLE ":" -+ IDS_LONGER_TRANSLATED "Removed document $1" -+ // Won't appear in the list of translations because it's not in the .grd file -+ IDS_NO_LONGER_USED "Not used" -+ IDS_DIFFERENT_TWIN_1 "Howdie" -+ IDS_DIFFERENT_TWIN_2 "Howdie" -+END -diff --git a/tools/grit/grit/testdata/special_100_percent/a.png b/tools/grit/grit/testdata/special_100_percent/a.png -new file mode 100644 -index 0000000000000000000000000000000000000000..5d5089038ca71172e95db9e7aae1e1fa5cebd505 -GIT binary patch -literal 159 -zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>0wld=oSO}#(mY)pLnNjq|2Y3)zGGzYPN&L+ -zMSC}CcCfp=Dtxv4%6W%G#Q=|R|L;6pCCLUWO)Z<5eoL%TkDTw=s4X!^d(Qa<2khAN -zZPy!XToBAic1Ss}vcWiD27B3&`Zj^H6CO>7R1{ToQ;=ggdEYbV=IISvfHpFCy85}S -Ib4q9e0O9jEh5!Hn - -literal 0 -HcmV?d00001 - -diff --git a/tools/grit/grit/testdata/status.html b/tools/grit/grit/testdata/status.html -new file mode 100644 -index 0000000000..6b997b9369 ---- /dev/null -+++ b/tools/grit/grit/testdata/status.html -@@ -0,0 +1,44 @@ -+[HEADER] -+ -+ -+
    -+ -+ -+
     Desktop Search Status
    -+
    -+
    -+[$~MESSAGE~$] -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
     Number of itemsTime of newest item
      Total searchable items[TOTAL_COUNT][TOTAL_TIME]
           Emails[EMAIL_COUNT][EMAIL_TIME]
           Chats[IM_COUNT][IM_TIME]
           Web history[WEB_COUNT][WEB_TIME]
           Files[FILE_COUNT][FILE_TIME]
    -+
    -+[FOOTER] -\ No newline at end of file -diff --git a/tools/grit/grit/testdata/structure_variables.html b/tools/grit/grit/testdata/structure_variables.html -new file mode 100644 -index 0000000000..2a15de8072 ---- /dev/null -+++ b/tools/grit/grit/testdata/structure_variables.html -@@ -0,0 +1,4 @@ -+

    [GREETING]!

    -+Some cool things are [THINGS]. -+Did you know that [EQUATION]? -+ -diff --git a/tools/grit/grit/testdata/substitute.grd b/tools/grit/grit/testdata/substitute.grd -new file mode 100644 -index 0000000000..95dcc56e1d ---- /dev/null -+++ b/tools/grit/grit/testdata/substitute.grd -@@ -0,0 +1,31 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Copyright 2008 Google Inc. All Rights Reserved. -+ -+ -+ Google Desktop News gadget -+[IDS_COPYRIGHT_GOOGLE_LONG] -+View news that is personalized based on the articles you read. -+ -+For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles. -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/substitute.xmb b/tools/grit/grit/testdata/substitute.xmb -new file mode 100644 -index 0000000000..e592069c8b ---- /dev/null -+++ b/tools/grit/grit/testdata/substitute.xmb -@@ -0,0 +1,10 @@ -+ -+ -+ -+© 2008 Google Inc. Med ensamrätt. -+Google Desktop News gadget -+ -+Se nyheter som är anpassade till dig, baserat på de artiklar du läser. -+ -+Om du t.ex. läser massor av sportnyheter kommer du att se fler sportartiklar. Om du inte läser tekniknyheter lika ofta ser du färre av dessa artiklar. -+ -diff --git a/tools/grit/grit/testdata/substitute_no_ids.grd b/tools/grit/grit/testdata/substitute_no_ids.grd -new file mode 100644 -index 0000000000..d569d1cacd ---- /dev/null -+++ b/tools/grit/grit/testdata/substitute_no_ids.grd -@@ -0,0 +1,31 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Copyright 2008 Google Inc. All Rights Reserved. -+ -+ -+ Google Desktop News gadget -+[IDS_COPYRIGHT_GOOGLE_LONG] -+View news that is personalized based on the articles you read. -+ -+For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles. -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/substitute_tmpl.grd b/tools/grit/grit/testdata/substitute_tmpl.grd -new file mode 100644 -index 0000000000..be7b601707 ---- /dev/null -+++ b/tools/grit/grit/testdata/substitute_tmpl.grd -@@ -0,0 +1,31 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Copyright 2008 Google Inc. All Rights Reserved. -+ -+ -+ Google Desktop News gadget -+[IDS_COPYRIGHT_GOOGLE_LONG] -+View news that is personalized based on the articles you read. -+ -+For example, if you read lots of sports news, you'll see more sports articles. If you read technology news less often, you'll see fewer of those articles. -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/test_css.css b/tools/grit/grit/testdata/test_css.css -new file mode 100644 -index 0000000000..55d5dd1770 ---- /dev/null -+++ b/tools/grit/grit/testdata/test_css.css -@@ -0,0 +1 @@ -+This is a test! -diff --git a/tools/grit/grit/testdata/test_html.html b/tools/grit/grit/testdata/test_html.html -new file mode 100644 -index 0000000000..55d5dd1770 ---- /dev/null -+++ b/tools/grit/grit/testdata/test_html.html -@@ -0,0 +1 @@ -+This is a test! -diff --git a/tools/grit/grit/testdata/test_js.js b/tools/grit/grit/testdata/test_js.js -new file mode 100644 -index 0000000000..55d5dd1770 ---- /dev/null -+++ b/tools/grit/grit/testdata/test_js.js -@@ -0,0 +1 @@ -+This is a test! -diff --git a/tools/grit/grit/testdata/test_svg.svg b/tools/grit/grit/testdata/test_svg.svg -new file mode 100644 -index 0000000000..55d5dd1770 ---- /dev/null -+++ b/tools/grit/grit/testdata/test_svg.svg -@@ -0,0 +1 @@ -+This is a test! -diff --git a/tools/grit/grit/testdata/test_text.txt b/tools/grit/grit/testdata/test_text.txt -new file mode 100644 -index 0000000000..55d5dd1770 ---- /dev/null -+++ b/tools/grit/grit/testdata/test_text.txt -@@ -0,0 +1 @@ -+This is a test! -diff --git a/tools/grit/grit/testdata/time_related.html b/tools/grit/grit/testdata/time_related.html -new file mode 100644 -index 0000000000..ee64b1665e ---- /dev/null -+++ b/tools/grit/grit/testdata/time_related.html -@@ -0,0 +1,11 @@ -+[HEADER] -+[CHROME] -+[NAV_PRE_POST] -+[$~MESSAGE~$]
    -+ -+[CONTENTS] -+

    -+ -+[NAV_PRE_POST] -+[FOOTER] -+ -diff --git a/tools/grit/grit/testdata/toolbar_about.html b/tools/grit/grit/testdata/toolbar_about.html -new file mode 100644 -index 0000000000..bb4b0eb355 ---- /dev/null -+++ b/tools/grit/grit/testdata/toolbar_about.html -@@ -0,0 +1,138 @@ -+ -+ -+ -+About Google Toolbar -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    -+ -+ -+ -+ -+ -+ -+
    -+
    Google Toolbar
    -+
    -+
    -+ -+ -+
    -+
    -+ -+
    -+
    -+
    -+ -+ -+ De parvis grandis acervus erit -+ -+ -+
    -+ -+ © 2006 Google -+ -+ -+
    -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/tools/grit/resource_ids b/tools/grit/grit/testdata/tools/grit/resource_ids -new file mode 100644 -index 0000000000..8a2b608df1 ---- /dev/null -+++ b/tools/grit/grit/testdata/tools/grit/resource_ids -@@ -0,0 +1,176 @@ -+# Copyright (c) 2011 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+# -+# This file is used to assign starting resource ids for resources and strings -+# used by Chromium. This is done to ensure that resource ids are unique -+# across all the grd files. If you are adding a new grd file, please add -+# a new entry to this file. -+# -+# The first entry in the file, SRCDIR, is special: It is a relative path from -+# this file to the base of your checkout. -+# -+# http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx says that the -+# range for IDR_ is 1 to 28,671 and the range for IDS_ is 1 to 32,767 and -+# common convention starts practical use of IDs at 100 or 101. -+{ -+ "SRCDIR": "../..", -+ -+ "chrome/browser/browser_resources.grd": { -+ "includes": [500], -+ }, -+ "chrome/browser/resources/component_extension_resources.grd": { -+ "includes": [1000], -+ }, -+ "chrome/browser/resources/net_internals_resources.grd": { -+ "includes": [1500], -+ }, -+ "chrome/browser/resources/shared_resources.grd": { -+ "includes": [2000], -+ }, -+ "chrome/common/common_resources.grd": { -+ "includes": [2500], -+ }, -+ "chrome/default_plugin/default_plugin_resources.grd": { -+ "includes": [3000], -+ }, -+ "chrome/renderer/renderer_resources.grd": { -+ "includes": [3500], -+ }, -+ "net/base/net_resources.grd": { -+ "includes": [4000], -+ }, -+ "webkit/glue/webkit_resources.grd": { -+ "includes": [4500], -+ }, -+ "webkit/tools/test_shell/test_shell_resources.grd": { -+ "includes": [5000], -+ }, -+ "ui/resources/ui_resources.grd": { -+ "includes": [5500], -+ }, -+ "chrome/app/theme/theme_resources.grd": { -+ "includes": [6000], -+ }, -+ "chrome_frame/resources/chrome_frame_resources.grd": { -+ "includes": [6500], -+ }, -+ # WebKit.grd can be in two different places depending on whether we are -+ # in a chromium checkout or a webkit-only checkout. -+ "third_party/WebKit/Source/WebKit/chromium/WebKit.grd": { -+ "includes": [7000], -+ }, -+ "WebKit.grd": { -+ "includes": [7000], -+ }, -+ -+ "ui/base/strings/app_locale_settings.grd": { -+ "META": {"join": 2}, -+ "messages": [7500], -+ }, -+ "chrome/app/resources/locale_settings.grd": { -+ "includes": [8000], -+ "messages": [8500], -+ }, -+ # These each start with the same resource id because we only use one -+ # file for each build (cros, linux, mac, or win). -+ "chrome/app/resources/locale_settings_cros.grd": { -+ "messages": [9000], -+ }, -+ "chrome/app/resources/locale_settings_linux.grd": { -+ "messages": [9000], -+ }, -+ "chrome/app/resources/locale_settings_mac.grd": { -+ "messages": [9000], -+ }, -+ "chrome/app/resources/locale_settings_win.grd": { -+ "messages": [9000], -+ }, -+ -+ "ui/base/strings/ui_strings.grd": { -+ "META": {"join": 4}, -+ "messages": [9500], -+ }, -+ # Chromium strings and Google Chrome strings must start at the same id. -+ # We only use one file depending on whether we're building Chromium or -+ # Google Chrome. -+ "chrome/app/chromium_strings.grd": { -+ "messages": [10000], -+ }, -+ "chrome/app/google_chrome_strings.grd": { -+ "messages": [10000], -+ }, -+ # Leave lots of space for generated_resources since it has most of our -+ # strings. -+ "chrome/app/generated_resources.grd": { -+ "META": {"join": 2}, -+ "structures": [10500], -+ "messages": [11000], -+ }, -+ # The chrome frame dialogs are also in generated_resources.grd so they -+ # get included by the translation console. We make sure that the ids -+ # for structures here are the same as for generated_resources.grd. -+ "chrome_frame/resources/chrome_frame_dialogs.grd": { -+ "structures": [10500], -+ "includes": [10750], -+ }, -+ "webkit/glue/inspector_strings.grd": { -+ "messages": [16000], -+ }, -+ "webkit/glue/webkit_strings.grd": { -+ "messages": [16500], -+ }, -+ -+ "chrome_frame/resources/chrome_frame_resources.grd": { -+ "includes": [17500], -+ "structures": [18000], -+ }, -+ -+ "ui/gfx/gfx_resources.grd": { -+ "includes": [18500], -+ }, -+ -+ "chrome/app/policy/policy_templates.grd": { -+ "structures": [19000], -+ "messages": [19010], -+ }, -+ -+ "chrome/browser/autofill/autofill_resources.grd": { -+ "messages": [19500], -+ }, -+ "chrome/browser/resources/sync_internals_resources.grd": { -+ "includes": [20000], -+ }, -+ # This file is generated during the build. -+ "<(SHARED_INTERMEDIATE_DIR)/devtools/devtools_resources.grd": { -+ "includes": [20500], -+ }, -+ # All standard and large theme resources should have the same IDs. -+ "chrome/app/theme/theme_resources_standard.grd": { -+ "includes": [21000], -+ }, -+ "chrome/app/theme/theme_resources_large.grd": { -+ "includes": [21000], -+ }, -+ # This file is generated during the build. -+ "chrome/browser/debugger/frontend/devtools_frontend_resources.grd": { -+ "META": {"join": 2}, -+ "includes": [21500], -+ }, -+ "cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd": { -+ "messages": [22500], -+ }, -+ "chrome/browser/resources/quota_internals_resources.grd": { -+ "includes": [23000], -+ }, -+ "chrome/browser/resources/workers_resources.grd": { -+ "includes": [23500], -+ }, -+ # All standard and large theme resources should have the same IDs. -+ "ui/resources/ui_resources_standard.grd": { -+ "includes": [24000], -+ }, -+ "ui/resources/ui_resources_large.grd": { -+ "includes": [24000], -+ }, -+} -diff --git a/tools/grit/grit/testdata/transl.rc b/tools/grit/grit/testdata/transl.rc -new file mode 100644 -index 0000000000..2f2595db3f ---- /dev/null -+++ b/tools/grit/grit/testdata/transl.rc -@@ -0,0 +1,56 @@ -+IDC_KLONKMENU MENU -+BEGIN -+ POPUP "&Skra" -+ BEGIN -+ MENUITEM "&Haetta", IDM_EXIT -+ MENUITEM "Thetta er ""Klonk"" sem eg fyla", ID_FILE_THISBE -+ POPUP "gonkurinn" -+ BEGIN -+ MENUITEM "Klonk && er [good]", ID_GONK_KLONKIS -+ END -+ END -+ POPUP "&Hjalp" -+ BEGIN -+ MENUITEM "&Um...", IDM_ABOUT -+ END -+END -+ -+IDD_ABOUTBOX DIALOGEX 22, 17, 230, 75 -+STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -+CAPTION "Um Klonk" -+FONT 8, "System", 0, 0, 0x0 -+BEGIN -+ ICON IDI_KLONK,IDC_MYICON,14,9,20,20 -+ LTEXT "klonk utgafa ""jibbi"" 1.0",IDC_STATIC,49,10,119,8, -+ SS_NOPREFIX -+ LTEXT "Hofundarrettur (C) 2005",IDC_STATIC,49,20,119,8 -+ DEFPUSHBUTTON "I lagi",IDOK,195,6,30,11,WS_GROUP -+ CONTROL "Jack ""Black"" Daniels",IDC_RADIO1,"Button", -+ BS_AUTORADIOBUTTON,46,51,84,10 -+END -+ -+IDD_DIFFERENT_LENGTH_IN_TRANSL DIALOGEX 22, 17, 230, 75 -+STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -+CAPTION "Bingobobbi" -+FONT 8, "System", 0, 0, 0x0 -+BEGIN -+ LTEXT "Howdie dodie!",IDC_STATIC,49,10,119,8,SS_NOPREFIX -+END -+ -+STRINGTABLE -+BEGIN -+ IDS_SIMPLE "Ein" -+ IDS_PLACEHOLDER "%s Vogeln" -+ IDS_PLACEHOLDERS "%d von %d" -+ // Shouldn't be part of translations list because the translation is -+ // reordered so placeholder fixup fails -+ IDS_REORDERED_PLACEHOLDERS "$2 auf $1" -+ IDS_CHANGED "Dass war die alte Version" -+ IDS_TWIN_1 "Hallo" -+ IDS_TWIN_2 "Hallo" -+ IDS_NOT_TRANSLATEABLE ":" -+ IDS_LONGER_TRANSLATED "Dokument $1 ist entfernt worden" -+ IDS_NO_LONGER_USED "Nicht verwendet" -+ IDS_DIFFERENT_TWIN_1 "Howdie" -+ IDS_DIFFERENT_TWIN_2 "Hallo sagt man" -+END -diff --git a/tools/grit/grit/testdata/versions.html b/tools/grit/grit/testdata/versions.html -new file mode 100644 -index 0000000000..d1f40d8d72 ---- /dev/null -+++ b/tools/grit/grit/testdata/versions.html -@@ -0,0 +1,7 @@ -+[HEADER] -+ -+[TOP_CHROME] -+[CONTENTS] -+ -+[NEXT_PREV] -+[FOOTER] -diff --git a/tools/grit/grit/testdata/whitelist.txt b/tools/grit/grit/testdata/whitelist.txt -new file mode 100644 -index 0000000000..5b3aca40b5 ---- /dev/null -+++ b/tools/grit/grit/testdata/whitelist.txt -@@ -0,0 +1,4 @@ -+IDS_MESSAGE_WHITELISTED -+IDR_STRUCTURE_WHITELISTED -+IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED -+IDR_INCLUDE_WHITELISTED -diff --git a/tools/grit/grit/testdata/whitelist_resources.grd b/tools/grit/grit/testdata/whitelist_resources.grd -new file mode 100644 -index 0000000000..9925688ff5 ---- /dev/null -+++ b/tools/grit/grit/testdata/whitelist_resources.grd -@@ -0,0 +1,54 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/tools/grit/grit/testdata/whitelist_strings.grd b/tools/grit/grit/testdata/whitelist_strings.grd -new file mode 100644 -index 0000000000..df80f5fd32 ---- /dev/null -+++ b/tools/grit/grit/testdata/whitelist_strings.grd -@@ -0,0 +1,23 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Whitelisted. -+ -+ -+ Not whitelisted. -+ -+ -+ -+ -diff --git a/tools/grit/grit/tool/__init__.py b/tools/grit/grit/tool/__init__.py -new file mode 100644 -index 0000000000..cc455b36e7 ---- /dev/null -+++ b/tools/grit/grit/tool/__init__.py -@@ -0,0 +1,8 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Package grit.tool -+''' -+ -+pass -diff --git a/tools/grit/grit/tool/android2grd.py b/tools/grit/grit/tool/android2grd.py -new file mode 100644 -index 0000000000..005297bafe ---- /dev/null -+++ b/tools/grit/grit/tool/android2grd.py -@@ -0,0 +1,484 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""The 'grit android2grd' tool.""" -+ -+from __future__ import print_function -+ -+import getopt -+import os.path -+import sys -+from xml.dom import Node -+import xml.dom.minidom -+ -+import six -+from six import StringIO -+ -+import grit.node.empty -+from grit.node import node_io -+from grit.node import message -+ -+from grit.tool import interface -+ -+from grit import grd_reader -+from grit import lazy_re -+from grit import tclib -+ -+ -+# The name of a string in strings.xml -+_STRING_NAME = lazy_re.compile(r'[a-z0-9_]+\Z') -+ -+# A string's character limit in strings.xml -+_CHAR_LIMIT = lazy_re.compile(r'\[CHAR-LIMIT=(\d+)\]') -+ -+# Finds String.Format() style format specifiers such as "%-5.2f". -+_FORMAT_SPECIFIER = lazy_re.compile( -+ r'%' -+ r'([1-9][0-9]*\$|<)?' # argument_index -+ r'([-#+ 0,(]*)' # flags -+ r'([0-9]+)?' # width -+ r'(\.[0-9]+)?' # precision -+ r'([bBhHsScCdoxXeEfgGaAtT%n])') # conversion -+ -+ -+class Android2Grd(interface.Tool): -+ """Tool for converting Android string.xml files into chrome Grd files. -+ -+Usage: grit [global options] android2grd [OPTIONS] STRINGS_XML -+ -+The Android2Grd tool will convert an Android strings.xml file (whose path is -+specified by STRINGS_XML) and create a chrome style grd file containing the -+relevant information. -+ -+Because grd documents are much richer than strings.xml documents we supplement -+the information required by grds using OPTIONS with sensible defaults. -+ -+OPTIONS may be any of the following: -+ -+ --name FILENAME Specify the base FILENAME. This should be without -+ any file type suffix. By default -+ "chrome_android_strings" will be used. -+ -+ --languages LANGUAGES Comma separated list of ISO language codes (e.g. -+ en-US, en-GB, ru, zh-CN). These codes will be used -+ to determine the names of resource and translations -+ files that will be declared by the output grd file. -+ -+ --grd-dir GRD_DIR Specify where the resultant grd file -+ (FILENAME.grd) should be output. By default this -+ will be the present working directory. -+ -+ --header-dir HEADER_DIR Specify the location of the directory where grit -+ generated C++ headers (whose name will be -+ FILENAME.h) will be placed. Use an empty string to -+ disable rc generation. Default: empty. -+ -+ --rc-dir RC_DIR Specify the directory where resource files will -+ be located relative to grit build's output -+ directory. Use an empty string to disable rc -+ generation. Default: empty. -+ -+ --xml-dir XML_DIR Specify where to place localized strings.xml files -+ relative to grit build's output directory. For each -+ language xx a values-xx/strings.xml file will be -+ generated. Use an empty string to disable -+ strings.xml generation. Default: '.'. -+ -+ --xtb-dir XTB_DIR Specify where the xtb files containing translations -+ will be located relative to the grd file. Default: -+ '.'. -+""" -+ -+ _NAME_FLAG = 'name' -+ _LANGUAGES_FLAG = 'languages' -+ _GRD_DIR_FLAG = 'grd-dir' -+ _RC_DIR_FLAG = 'rc-dir' -+ _HEADER_DIR_FLAG = 'header-dir' -+ _XTB_DIR_FLAG = 'xtb-dir' -+ _XML_DIR_FLAG = 'xml-dir' -+ -+ def __init__(self): -+ self.name = 'chrome_android_strings' -+ self.languages = [] -+ self.grd_dir = '.' -+ self.rc_dir = None -+ self.xtb_dir = '.' -+ self.xml_res_dir = '.' -+ self.header_dir = None -+ -+ def ShortDescription(self): -+ """Returns a short description of the Android2Grd tool. -+ -+ Overridden from grit.interface.Tool -+ -+ Returns: -+ A string containing a short description of the android2grd tool. -+ """ -+ return 'Converts Android string.xml files into Chrome grd files.' -+ -+ def ParseOptions(self, args): -+ """Set this objects and return all non-option arguments.""" -+ flags = [ -+ Android2Grd._NAME_FLAG, -+ Android2Grd._LANGUAGES_FLAG, -+ Android2Grd._GRD_DIR_FLAG, -+ Android2Grd._RC_DIR_FLAG, -+ Android2Grd._HEADER_DIR_FLAG, -+ Android2Grd._XTB_DIR_FLAG, -+ Android2Grd._XML_DIR_FLAG, ] -+ (opts, args) = getopt.getopt( -+ args, None, ['%s=' % o for o in flags] + ['help']) -+ -+ for key, val in opts: -+ # Get rid of the preceding hypens. -+ k = key[2:] -+ if k == Android2Grd._NAME_FLAG: -+ self.name = val -+ elif k == Android2Grd._LANGUAGES_FLAG: -+ self.languages = val.split(',') -+ elif k == Android2Grd._GRD_DIR_FLAG: -+ self.grd_dir = val -+ elif k == Android2Grd._RC_DIR_FLAG: -+ self.rc_dir = val -+ elif k == Android2Grd._HEADER_DIR_FLAG: -+ self.header_dir = val -+ elif k == Android2Grd._XTB_DIR_FLAG: -+ self.xtb_dir = val -+ elif k == Android2Grd._XML_DIR_FLAG: -+ self.xml_res_dir = val -+ elif k == 'help': -+ self.ShowUsage() -+ sys.exit(0) -+ return args -+ -+ def Run(self, opts, args): -+ """Runs the Android2Grd tool. -+ -+ Inherited from grit.interface.Tool. -+ -+ Args: -+ opts: List of string arguments that should be parsed. -+ args: String containing the path of the strings.xml file to be converted. -+ """ -+ args = self.ParseOptions(args) -+ if len(args) != 1: -+ print('Tool requires one argument, the path to the Android ' -+ 'strings.xml resource file to be converted.') -+ return 2 -+ self.SetOptions(opts) -+ -+ android_path = args[0] -+ -+ # Read and parse the Android strings.xml file. -+ with open(android_path) as android_file: -+ android_dom = xml.dom.minidom.parse(android_file) -+ -+ # Do the hard work -- convert the Android dom to grd file contents. -+ grd_dom = self.AndroidDomToGrdDom(android_dom) -+ grd_string = six.text_type(grd_dom) -+ -+ # Write the grd string to a file in grd_dir. -+ grd_filename = self.name + '.grd' -+ grd_path = os.path.join(self.grd_dir, grd_filename) -+ with open(grd_path, 'w') as grd_file: -+ grd_file.write(grd_string) -+ -+ def AndroidDomToGrdDom(self, android_dom): -+ """Converts a strings.xml DOM into a DOM representing the contents of -+ a grd file. -+ -+ Args: -+ android_dom: A xml.dom.Document containing the contents of the Android -+ string.xml document. -+ Returns: -+ The DOM for the grd xml document produced by converting the Android DOM. -+ """ -+ -+ # Start with a basic skeleton for the .grd file. -+ root = grd_reader.Parse(StringIO( -+ ''' -+ -+ -+ -+ -+ -+ -+ '''), dir='.') -+ outputs = root.children[0] -+ translations = root.children[1] -+ messages = root.children[2].children[0] -+ assert (isinstance(messages, grit.node.empty.MessagesNode) and -+ isinstance(translations, grit.node.empty.TranslationsNode) and -+ isinstance(outputs, grit.node.empty.OutputsNode)) -+ -+ if self.header_dir: -+ cpp_header = self.__CreateCppHeaderOutputNode(outputs, self.header_dir) -+ for lang in self.languages: -+ # Create an output element for each language. -+ if self.rc_dir: -+ self.__CreateRcOutputNode(outputs, lang, self.rc_dir) -+ if self.xml_res_dir: -+ self.__CreateAndroidXmlOutputNode(outputs, lang, self.xml_res_dir) -+ if lang != 'en': -+ self.__CreateFileNode(translations, lang) -+ # Convert all the strings.xml strings into grd messages. -+ self.__CreateMessageNodes(messages, android_dom.documentElement) -+ -+ return root -+ -+ def __CreateMessageNodes(self, messages, resources): -+ """Creates the elements and adds them as children of . -+ -+ Args: -+ messages: the element in the strings.xml dom. -+ resources: the element in the grd dom. -+ """ -+ # elements contain the definition of the resource. -+ # The description of a element is contained within the comment -+ # node element immediately preceeding the string element in question. -+ description = '' -+ for child in resources.childNodes: -+ if child.nodeType == Node.COMMENT_NODE: -+ # Remove leading/trailing whitespace; collapse consecutive whitespaces. -+ description = ' '.join(child.data.split()) -+ elif child.nodeType == Node.ELEMENT_NODE: -+ if child.tagName != 'string': -+ print('Warning: ignoring unknown tag <%s>' % child.tagName) -+ else: -+ translatable = self.IsTranslatable(child) -+ raw_name = child.getAttribute('name') -+ if not _STRING_NAME.match(raw_name): -+ print('Error: illegal string name: %s' % raw_name) -+ grd_name = 'IDS_' + raw_name.upper() -+ # Transform the node contents into a tclib.Message, taking -+ # care to handle whitespace transformations and escaped characters, -+ # and coverting placeholders into placeholders. -+ msg = self.CreateTclibMessage(child) -+ msg_node = self.__CreateMessageNode(messages, grd_name, description, -+ msg, translatable) -+ messages.AddChild(msg_node) -+ # Reset the description once a message has been parsed. -+ description = '' -+ -+ def CreateTclibMessage(self, android_string): -+ """Transforms a element from strings.xml into a tclib.Message. -+ -+ Interprets whitespace, quotes, and escaped characters in the android_string -+ according to Android's formatting and styling rules for strings. Also -+ converts placeholders into placeholders, e.g.: -+ -+ %s -+ becomes -+ google.com%s -+ -+ Returns: -+ The tclib.Message. -+ """ -+ msg = tclib.Message() -+ current_text = '' # Accumulated text that hasn't yet been added to msg. -+ nodes = android_string.childNodes -+ -+ for i, node in enumerate(nodes): -+ # Handle text nodes. -+ if node.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): -+ current_text += node.data -+ -+ # Handle and other tags. -+ elif node.nodeType == Node.ELEMENT_NODE: -+ if node.tagName == 'xliff:g': -+ assert node.hasAttribute('id'), 'missing id: ' + node.data() -+ placeholder_id = node.getAttribute('id') -+ placeholder_text = self.__FormatPlaceholderText(node) -+ placeholder_example = node.getAttribute('example') -+ if not placeholder_example: -+ print('Info: placeholder does not contain an example: %s' % -+ node.toxml()) -+ placeholder_example = placeholder_id.upper() -+ msg.AppendPlaceholder(tclib.Placeholder(placeholder_id, -+ placeholder_text, placeholder_example)) -+ else: -+ print('Warning: removing tag <%s> which must be inside a ' -+ 'placeholder: %s' % (node.tagName, node.toxml())) -+ msg.AppendText(self.__FormatPlaceholderText(node)) -+ -+ # Handle other nodes. -+ elif node.nodeType != Node.COMMENT_NODE: -+ assert False, 'Unknown node type: %s' % node.nodeType -+ -+ is_last_node = (i == len(nodes) - 1) -+ if (current_text and -+ (is_last_node or nodes[i + 1].nodeType == Node.ELEMENT_NODE)): -+ # For messages containing just text and comments (no xml tags) Android -+ # strips leading and trailing whitespace. We mimic that behavior. -+ if not msg.GetContent() and is_last_node: -+ current_text = current_text.strip() -+ msg.AppendText(self.__FormatAndroidString(current_text)) -+ current_text = '' -+ -+ return msg -+ -+ def __FormatAndroidString(self, android_string, inside_placeholder=False): -+ r"""Returns android_string formatted for a .grd file. -+ -+ * Collapses consecutive whitespaces, except when inside double-quotes. -+ * Replaces \\, \n, \t, \", \' with \, newline, tab, ", '. -+ """ -+ backslash_map = {'\\' : '\\', 'n' : '\n', 't' : '\t', '"' : '"', "'" : "'"} -+ is_quoted_section = False # True when we're inside double quotes. -+ is_backslash_sequence = False # True after seeing an unescaped backslash. -+ prev_char = '' -+ output = [] -+ for c in android_string: -+ if is_backslash_sequence: -+ # Unescape \\, \n, \t, \", and \'. -+ assert c in backslash_map, 'Illegal escape sequence: \\%s' % c -+ output.append(backslash_map[c]) -+ is_backslash_sequence = False -+ elif c == '\\': -+ is_backslash_sequence = True -+ elif c.isspace() and not is_quoted_section: -+ # Turn whitespace into ' ' and collapse consecutive whitespaces. -+ if not prev_char.isspace(): -+ output.append(' ') -+ elif c == '"': -+ is_quoted_section = not is_quoted_section -+ else: -+ output.append(c) -+ prev_char = c -+ output = ''.join(output) -+ -+ if is_quoted_section: -+ print('Warning: unbalanced quotes in string: %s' % android_string) -+ -+ if is_backslash_sequence: -+ print('Warning: trailing backslash in string: %s' % android_string) -+ -+ # Check for format specifiers outside of placeholder tags. -+ if not inside_placeholder: -+ format_specifier = _FORMAT_SPECIFIER.search(output) -+ if format_specifier: -+ print('Warning: format specifiers are not inside a placeholder ' -+ ' tag: %s' % output) -+ -+ return output -+ -+ def __FormatPlaceholderText(self, placeholder_node): -+ """Returns the text inside of an placeholder node.""" -+ text = [] -+ for childNode in placeholder_node.childNodes: -+ if childNode.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): -+ text.append(childNode.data) -+ elif childNode.nodeType != Node.COMMENT_NODE: -+ assert False, 'Unknown node type in ' + placeholder_node.toxml() -+ return self.__FormatAndroidString(''.join(text), inside_placeholder=True) -+ -+ def __CreateMessageNode(self, messages_node, grd_name, description, msg, -+ translatable): -+ """Creates and initializes a element. -+ -+ Message elements correspond to Android elements in that they -+ declare a string resource along with a programmatic id. -+ """ -+ if not description: -+ print('Warning: no description for %s' % grd_name) -+ # Check that we actually fit within the character limit we've specified. -+ match = _CHAR_LIMIT.search(description) -+ if match: -+ char_limit = int(match.group(1)) -+ msg_content = msg.GetRealContent() -+ if len(msg_content) > char_limit: -+ print('Warning: char-limit for %s is %d, but length is %d: %s' % -+ (grd_name, char_limit, len(msg_content), msg_content)) -+ return message.MessageNode.Construct(parent=messages_node, -+ name=grd_name, -+ message=msg, -+ desc=description, -+ translateable=translatable) -+ -+ def __CreateFileNode(self, translations_node, lang): -+ """Creates and initializes the elements. -+ -+ File elements provide information on the location of translation files -+ (xtbs) -+ """ -+ xtb_file = os.path.normpath(os.path.join( -+ self.xtb_dir, '%s_%s.xtb' % (self.name, lang))) -+ fnode = node_io.FileNode() -+ fnode.StartParsing(u'file', translations_node) -+ fnode.HandleAttribute('path', xtb_file) -+ fnode.HandleAttribute('lang', lang) -+ fnode.EndParsing() -+ translations_node.AddChild(fnode) -+ return fnode -+ -+ def __CreateCppHeaderOutputNode(self, outputs_node, header_dir): -+ """Creates the element corresponding to the generated c header.""" -+ header_file_name = os.path.join(header_dir, self.name + '.h') -+ header_node = node_io.OutputNode() -+ header_node.StartParsing(u'output', outputs_node) -+ header_node.HandleAttribute('filename', header_file_name) -+ header_node.HandleAttribute('type', 'rc_header') -+ emit_node = node_io.EmitNode() -+ emit_node.StartParsing(u'emit', header_node) -+ emit_node.HandleAttribute('emit_type', 'prepend') -+ emit_node.EndParsing() -+ header_node.AddChild(emit_node) -+ header_node.EndParsing() -+ outputs_node.AddChild(header_node) -+ return header_node -+ -+ def __CreateRcOutputNode(self, outputs_node, lang, rc_dir): -+ """Creates the element corresponding to various rc file output.""" -+ rc_file_name = self.name + '_' + lang + ".rc" -+ rc_path = os.path.join(rc_dir, rc_file_name) -+ node = node_io.OutputNode() -+ node.StartParsing(u'output', outputs_node) -+ node.HandleAttribute('filename', rc_path) -+ node.HandleAttribute('lang', lang) -+ node.HandleAttribute('type', 'rc_all') -+ node.EndParsing() -+ outputs_node.AddChild(node) -+ return node -+ -+ def __CreateAndroidXmlOutputNode(self, outputs_node, locale, xml_res_dir): -+ """Creates the element corresponding to various rc file output.""" -+ # Need to check to see if the locale has a region, e.g. the GB in en-GB. -+ # When a locale has a region Android expects the region to be prefixed -+ # with an 'r'. For example for en-GB Android expects a values-en-rGB -+ # directory. Also, Android expects nb, tl, in, iw, ji as the language -+ # codes for Norwegian, Tagalog/Filipino, Indonesian, Hebrew, and Yiddish: -+ # http://developer.android.com/reference/java/util/Locale.html -+ if locale == 'es-419': -+ android_locale = 'es-rUS' -+ else: -+ android_lang, dash, region = locale.partition('-') -+ lang_map = {'no': 'nb', 'fil': 'tl', 'id': 'in', 'he': 'iw', 'yi': 'ji'} -+ android_lang = lang_map.get(android_lang, android_lang) -+ android_locale = android_lang + ('-r' + region if region else '') -+ values = 'values-' + android_locale if android_locale != 'en' else 'values' -+ xml_path = os.path.normpath(os.path.join( -+ xml_res_dir, values, 'strings.xml')) -+ -+ node = node_io.OutputNode() -+ node.StartParsing(u'output', outputs_node) -+ node.HandleAttribute('filename', xml_path) -+ node.HandleAttribute('lang', locale) -+ node.HandleAttribute('type', 'android') -+ node.EndParsing() -+ outputs_node.AddChild(node) -+ return node -+ -+ def IsTranslatable(self, android_string): -+ """Determines if a element is a candidate for translation. -+ -+ A element is by default translatable unless otherwise marked. -+ """ -+ if android_string.hasAttribute('translatable'): -+ value = android_string.getAttribute('translatable').lower() -+ if value not in ('true', 'false'): -+ print('Warning: translatable attribute has invalid value: %s' % value) -+ return value == 'true' -+ else: -+ return True -diff --git a/tools/grit/grit/tool/android2grd_unittest.py b/tools/grit/grit/tool/android2grd_unittest.py -new file mode 100644 -index 0000000000..a6934a707c ---- /dev/null -+++ b/tools/grit/grit/tool/android2grd_unittest.py -@@ -0,0 +1,181 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grit.tool.android2grd''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+import unittest -+import xml.dom.minidom -+ -+from grit import util -+from grit.node import empty -+from grit.node import message -+from grit.node import misc -+from grit.node import node_io -+from grit.tool import android2grd -+ -+ -+class Android2GrdUnittest(unittest.TestCase): -+ -+ def __Parse(self, xml_string): -+ return xml.dom.minidom.parseString(xml_string).childNodes[0] -+ -+ def testCreateTclibMessage(self): -+ tool = android2grd.Android2Grd() -+ msg = tool.CreateTclibMessage(self.__Parse(r''' -+ A simple string''')) -+ self.assertEqual(msg.GetRealContent(), 'A simple string') -+ msg = tool.CreateTclibMessage(self.__Parse(r''' -+ -+ Strip leading/trailing whitespace -+ ''')) -+ self.assertEqual(msg.GetRealContent(), 'Strip leading/trailing whitespace') -+ msg = tool.CreateTclibMessage(self.__Parse(r''' -+ Fold multiple spaces''')) -+ self.assertEqual(msg.GetRealContent(), 'Fold multiple spaces') -+ msg = tool.CreateTclibMessage(self.__Parse(r''' -+ Retain \n escaped\t spaces''')) -+ self.assertEqual(msg.GetRealContent(), 'Retain \n escaped\t spaces') -+ msg = tool.CreateTclibMessage(self.__Parse(r''' -+ " Quotes preserve -+ whitespace" but only for "enclosed elements " -+ ''')) -+ self.assertEqual(msg.GetRealContent(), ''' Quotes preserve -+ whitespace but only for enclosed elements ''') -+ msg = tool.CreateTclibMessage(self.__Parse( -+ r'''Escaped characters: \"\'\\\t\n''' -+ '')) -+ self.assertEqual(msg.GetRealContent(), '''Escaped characters: "'\\\t\n''') -+ msg = tool.CreateTclibMessage(self.__Parse( -+ '' -+ 'Open %s?' -+ '')) -+ self.assertEqual(msg.GetRealContent(), 'Open %s?') -+ self.assertEqual(len(msg.GetPlaceholders()), 1) -+ self.assertEqual(msg.GetPlaceholders()[0].presentation, 'FILENAME') -+ self.assertEqual(msg.GetPlaceholders()[0].original, '%s') -+ self.assertEqual(msg.GetPlaceholders()[0].example, 'internet.html') -+ msg = tool.CreateTclibMessage(self.__Parse(r''' -+ Contains a comment -+ ''')) -+ self.assertEqual(msg.GetRealContent(), 'Contains a comment') -+ -+ def testIsTranslatable(self): -+ tool = android2grd.Android2Grd() -+ string_el = self.__Parse('Hi') -+ self.assertTrue(tool.IsTranslatable(string_el)) -+ string_el = self.__Parse( -+ 'Hi') -+ self.assertTrue(tool.IsTranslatable(string_el)) -+ string_el = self.__Parse( -+ 'Hi') -+ self.assertFalse(tool.IsTranslatable(string_el)) -+ -+ def __ParseAndroidXml(self, options = []): -+ tool = android2grd.Android2Grd() -+ -+ tool.ParseOptions(options) -+ -+ android_path = util.PathFromRoot('grit/testdata/android.xml') -+ with open(android_path) as android_file: -+ android_dom = xml.dom.minidom.parse(android_file) -+ -+ grd = tool.AndroidDomToGrdDom(android_dom) -+ self.assertTrue(isinstance(grd, misc.GritNode)) -+ -+ return grd -+ -+ def testAndroidDomToGrdDom(self): -+ grd = self.__ParseAndroidXml(['--languages', 'en-US,en-GB,ru']) -+ -+ # Check that the structure of the GritNode is as expected. -+ messages = grd.GetChildrenOfType(message.MessageNode) -+ translations = grd.GetChildrenOfType(empty.TranslationsNode) -+ files = grd.GetChildrenOfType(node_io.FileNode) -+ -+ self.assertEqual(len(translations), 1) -+ self.assertEqual(len(files), 3) -+ self.assertEqual(len(messages), 5) -+ -+ # Check that a message node is constructed correctly. -+ msg = [x for x in messages if x.GetTextualIds()[0] == 'IDS_PLACEHOLDERS'] -+ self.assertTrue(msg) -+ msg = msg[0] -+ -+ self.assertTrue(msg.IsTranslateable()) -+ self.assertEqual(msg.attrs["desc"], "A string with placeholder.") -+ -+ def testTranslatableAttribute(self): -+ grd = self.__ParseAndroidXml([]) -+ messages = grd.GetChildrenOfType(message.MessageNode) -+ msgs = [x for x in messages if x.GetTextualIds()[0] == 'IDS_CONSTANT'] -+ self.assertTrue(msgs) -+ self.assertFalse(msgs[0].IsTranslateable()) -+ -+ def testTranslations(self): -+ grd = self.__ParseAndroidXml(['--languages', 'en-US,en-GB,ru,id']) -+ -+ files = grd.GetChildrenOfType(node_io.FileNode) -+ us_file = [x for x in files if x.attrs['lang'] == 'en-US'] -+ self.assertTrue(us_file) -+ self.assertEqual(us_file[0].GetInputPath(), -+ 'chrome_android_strings_en-US.xtb') -+ -+ id_file = [x for x in files if x.attrs['lang'] == 'id'] -+ self.assertTrue(id_file) -+ self.assertEqual(id_file[0].GetInputPath(), -+ 'chrome_android_strings_id.xtb') -+ -+ def testOutputs(self): -+ grd = self.__ParseAndroidXml(['--languages', 'en-US,ru,id', -+ '--rc-dir', 'rc/dir', -+ '--header-dir', 'header/dir', -+ '--xtb-dir', 'xtb/dir', -+ '--xml-dir', 'xml/dir']) -+ -+ outputs = grd.GetChildrenOfType(node_io.OutputNode) -+ self.assertEqual(len(outputs), 7) -+ -+ header_outputs = [x for x in outputs if x.GetType() == 'rc_header'] -+ rc_outputs = [x for x in outputs if x.GetType() == 'rc_all'] -+ xml_outputs = [x for x in outputs if x.GetType() == 'android'] -+ -+ self.assertEqual(len(header_outputs), 1) -+ self.assertEqual(len(rc_outputs), 3) -+ self.assertEqual(len(xml_outputs), 3) -+ -+ # The header node should have an "" child and the proper filename. -+ self.assertTrue(header_outputs[0].GetChildrenOfType(node_io.EmitNode)) -+ self.assertEqual(util.normpath(header_outputs[0].GetFilename()), -+ util.normpath('header/dir/chrome_android_strings.h')) -+ -+ id_rc = [x for x in rc_outputs if x.GetLanguage() == 'id'] -+ id_xml = [x for x in xml_outputs if x.GetLanguage() == 'id'] -+ self.assertTrue(id_rc) -+ self.assertTrue(id_xml) -+ self.assertEqual(util.normpath(id_rc[0].GetFilename()), -+ util.normpath('rc/dir/chrome_android_strings_id.rc')) -+ self.assertEqual(util.normpath(id_xml[0].GetFilename()), -+ util.normpath('xml/dir/values-in/strings.xml')) -+ -+ us_rc = [x for x in rc_outputs if x.GetLanguage() == 'en-US'] -+ us_xml = [x for x in xml_outputs if x.GetLanguage() == 'en-US'] -+ self.assertTrue(us_rc) -+ self.assertTrue(us_xml) -+ self.assertEqual(util.normpath(us_rc[0].GetFilename()), -+ util.normpath('rc/dir/chrome_android_strings_en-US.rc')) -+ self.assertEqual(util.normpath(us_xml[0].GetFilename()), -+ util.normpath('xml/dir/values-en-rUS/strings.xml')) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py -new file mode 100644 -index 0000000000..204592bf0d ---- /dev/null -+++ b/tools/grit/grit/tool/build.py -@@ -0,0 +1,556 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''The 'grit build' tool. -+''' -+ -+from __future__ import print_function -+ -+import codecs -+import filecmp -+import getopt -+import gzip -+import os -+import shutil -+import sys -+ -+import six -+ -+from grit import grd_reader -+from grit import shortcuts -+from grit import util -+from grit.format import minifier -+from grit.node import brotli_util -+from grit.node import include -+from grit.node import message -+from grit.node import structure -+from grit.tool import interface -+ -+ -+# It would be cleaner to have each module register itself, but that would -+# require importing all of them on every run of GRIT. -+'''Map from node types to modules under grit.format.''' -+_format_modules = { -+ 'android': 'android_xml', -+ 'c_format': 'c_format', -+ 'chrome_messages_json': 'chrome_messages_json', -+ 'chrome_messages_json_gzip': 'chrome_messages_json', -+ 'data_package': 'data_pack', -+ 'policy_templates': 'policy_templates_json', -+ 'rc_all': 'rc', -+ 'rc_header': 'rc_header', -+ 'rc_nontranslateable': 'rc', -+ 'rc_translateable': 'rc', -+ 'resource_file_map_source': 'resource_map', -+ 'resource_map_header': 'resource_map', -+ 'resource_map_source': 'resource_map', -+} -+ -+def GetFormatter(type): -+ modulename = 'grit.format.' + _format_modules[type] -+ __import__(modulename) -+ module = sys.modules[modulename] -+ try: -+ return module.Format -+ except AttributeError: -+ return module.GetFormatter(type) -+ -+ -+class RcBuilder(interface.Tool): -+ '''A tool that builds RC files and resource header files for compilation. -+ -+Usage: grit build [-o OUTPUTDIR] [-D NAME[=VAL]]* -+ -+All output options for this tool are specified in the input file (see -+'grit help' for details on how to specify the input file - it is a global -+option). -+ -+Options: -+ -+ -a FILE Assert that the given file is an output. There can be -+ multiple "-a" flags listed for multiple outputs. If a "-a" -+ or "--assert-file-list" argument is present, then the list -+ of asserted files must match the output files or the tool -+ will fail. The use-case is for the build system to maintain -+ separate lists of output files and to catch errors if the -+ build system's list and the grit list are out-of-sync. -+ -+ --assert-file-list Provide a file listing multiple asserted output files. -+ There is one file name per line. This acts like specifying -+ each file with "-a" on the command line, but without the -+ possibility of running into OS line-length limits for very -+ long lists. -+ -+ -o OUTPUTDIR Specify what directory output paths are relative to. -+ Defaults to the current directory. -+ -+ -p FILE Specify a file containing a pre-determined mapping from -+ resource names to resource ids which will be used to assign -+ resource ids to those resources. Resources not found in this -+ file will be assigned ids normally. The motivation is to run -+ your app's startup and have it dump the resources it loads, -+ and then pass these via this flag. This will pack startup -+ resources together, thus reducing paging while all other -+ resources are unperturbed. The file should have the format: -+ RESOURCE_ONE_NAME 123 -+ RESOURCE_TWO_NAME 124 -+ -+ -D NAME[=VAL] Specify a C-preprocessor-like define NAME with optional -+ value VAL (defaults to 1) which will be used to control -+ conditional inclusion of resources. -+ -+ -E NAME=VALUE Set environment variable NAME to VALUE (within grit). -+ -+ -f FIRSTIDSFILE Path to a python file that specifies the first id of -+ value to use for resources. A non-empty value here will -+ override the value specified in the node's -+ first_ids_file. -+ -+ -w WHITELISTFILE Path to a file containing the string names of the -+ resources to include. Anything not listed is dropped. -+ -+ -t PLATFORM Specifies the platform the build is targeting; defaults -+ to the value of sys.platform. The value provided via this -+ flag should match what sys.platform would report for your -+ target platform; see grit.node.base.EvaluateCondition. -+ -+ --whitelist-support -+ Generate code to support extracting a resource whitelist -+ from executables. -+ -+ --write-only-new flag -+ If flag is non-0, write output files to a temporary file -+ first, and copy it to the real output only if the new file -+ is different from the old file. This allows some build -+ systems to realize that dependent build steps might be -+ unnecessary, at the cost of comparing the output data at -+ grit time. -+ -+ --depend-on-stamp -+ If specified along with --depfile and --depdir, the depfile -+ generated will depend on a stampfile instead of the first -+ output in the input .grd file. -+ -+ --js-minifier A command to run the Javascript minifier. If not set then -+ Javascript won't be minified. The command should read the -+ original Javascript from standard input, and output the -+ minified Javascript to standard output. A non-zero exit -+ status will be taken as indicating failure. -+ -+ --css-minifier A command to run the CSS minifier. If not set then CSS won't -+ be minified. The command should read the original CSS from -+ standard input, and output the minified CSS to standard -+ output. A non-zero exit status will be taken as indicating -+ failure. -+ -+ --brotli The full path to the brotli executable generated by -+ third_party/brotli/BUILD.gn, required if any entries use -+ compress="brotli". -+ -+Conditional inclusion of resources only affects the output of files which -+control which resources get linked into a binary, e.g. it affects .rc files -+meant for compilation but it does not affect resource header files (that define -+IDs). This helps ensure that values of IDs stay the same, that all messages -+are exported to translation interchange files (e.g. XMB files), etc. -+''' -+ -+ def ShortDescription(self): -+ return 'A tool that builds RC files for compilation.' -+ -+ def Run(self, opts, args): -+ brotli_util.SetBrotliCommand(None) -+ os.environ['cwd'] = os.getcwd() -+ self.output_directory = '.' -+ first_ids_file = None -+ predetermined_ids_file = None -+ whitelist_filenames = [] -+ assert_output_files = [] -+ target_platform = None -+ depfile = None -+ depdir = None -+ whitelist_support = False -+ write_only_new = False -+ depend_on_stamp = False -+ js_minifier = None -+ css_minifier = None -+ replace_ellipsis = True -+ (own_opts, args) = getopt.getopt( -+ args, 'a:p:o:D:E:f:w:t:', -+ ('depdir=', 'depfile=', 'assert-file-list=', 'help', -+ 'output-all-resource-defines', 'no-output-all-resource-defines', -+ 'no-replace-ellipsis', 'depend-on-stamp', 'js-minifier=', -+ 'css-minifier=', 'write-only-new=', 'whitelist-support', 'brotli=')) -+ for (key, val) in own_opts: -+ if key == '-a': -+ assert_output_files.append(val) -+ elif key == '--assert-file-list': -+ with open(val) as f: -+ assert_output_files += f.read().splitlines() -+ elif key == '-o': -+ self.output_directory = val -+ elif key == '-D': -+ name, val = util.ParseDefine(val) -+ self.defines[name] = val -+ elif key == '-E': -+ (env_name, env_value) = val.split('=', 1) -+ os.environ[env_name] = env_value -+ elif key == '-f': -+ # TODO(joi@chromium.org): Remove this override once change -+ # lands in WebKit.grd to specify the first_ids_file in the -+ # .grd itself. -+ first_ids_file = val -+ elif key == '-w': -+ whitelist_filenames.append(val) -+ elif key == '--no-replace-ellipsis': -+ replace_ellipsis = False -+ elif key == '-p': -+ predetermined_ids_file = val -+ elif key == '-t': -+ target_platform = val -+ elif key == '--depdir': -+ depdir = val -+ elif key == '--depfile': -+ depfile = val -+ elif key == '--write-only-new': -+ write_only_new = val != '0' -+ elif key == '--depend-on-stamp': -+ depend_on_stamp = True -+ elif key == '--js-minifier': -+ js_minifier = val -+ elif key == '--css-minifier': -+ css_minifier = val -+ elif key == '--whitelist-support': -+ whitelist_support = True -+ elif key == '--brotli': -+ brotli_util.SetBrotliCommand([os.path.abspath(val)]) -+ elif key == '--help': -+ self.ShowUsage() -+ sys.exit(0) -+ -+ if len(args): -+ print('This tool takes no tool-specific arguments.') -+ return 2 -+ self.SetOptions(opts) -+ self.VerboseOut('Output directory: %s (absolute path: %s)\n' % -+ (self.output_directory, -+ os.path.abspath(self.output_directory))) -+ -+ if whitelist_filenames: -+ self.whitelist_names = set() -+ for whitelist_filename in whitelist_filenames: -+ self.VerboseOut('Using whitelist: %s\n' % whitelist_filename); -+ whitelist_contents = util.ReadFile(whitelist_filename, 'utf-8') -+ self.whitelist_names.update(whitelist_contents.strip().split('\n')) -+ -+ if js_minifier: -+ minifier.SetJsMinifier(js_minifier) -+ -+ if css_minifier: -+ minifier.SetCssMinifier(css_minifier) -+ -+ self.write_only_new = write_only_new -+ -+ self.res = grd_reader.Parse(opts.input, -+ debug=opts.extra_verbose, -+ first_ids_file=first_ids_file, -+ predetermined_ids_file=predetermined_ids_file, -+ defines=self.defines, -+ target_platform=target_platform) -+ -+ # Set an output context so that conditionals can use defines during the -+ # gathering stage; we use a dummy language here since we are not outputting -+ # a specific language. -+ self.res.SetOutputLanguage('en') -+ self.res.SetWhitelistSupportEnabled(whitelist_support) -+ self.res.RunGatherers() -+ -+ # Replace ... with the single-character version. http://crbug.com/621772 -+ if replace_ellipsis: -+ for node in self.res: -+ if isinstance(node, message.MessageNode): -+ node.SetReplaceEllipsis(True) -+ -+ self.Process() -+ -+ if assert_output_files: -+ if not self.CheckAssertedOutputFiles(assert_output_files): -+ return 2 -+ -+ if depfile and depdir: -+ self.GenerateDepfile(depfile, depdir, first_ids_file, depend_on_stamp) -+ -+ return 0 -+ -+ def __init__(self, defines=None): -+ # Default file-creation function is codecs.open(). Only done to allow -+ # overriding by unit test. -+ self.fo_create = codecs.open -+ -+ # key/value pairs of C-preprocessor like defines that are used for -+ # conditional output of resources -+ self.defines = defines or {} -+ -+ # self.res is a fully-populated resource tree if Run() -+ # has been called, otherwise None. -+ self.res = None -+ -+ # The set of names that are whitelisted to actually be included in the -+ # output. -+ self.whitelist_names = None -+ -+ # Whether to compare outputs to their old contents before writing. -+ self.write_only_new = False -+ -+ @staticmethod -+ def AddWhitelistTags(start_node, whitelist_names): -+ # Walk the tree of nodes added attributes for the nodes that shouldn't -+ # be written into the target files (skip markers). -+ for node in start_node: -+ # Same trick data_pack.py uses to see what nodes actually result in -+ # real items. -+ if (isinstance(node, include.IncludeNode) or -+ isinstance(node, message.MessageNode) or -+ isinstance(node, structure.StructureNode)): -+ text_ids = node.GetTextualIds() -+ # Mark the item to be skipped if it wasn't in the whitelist. -+ if text_ids and text_ids[0] not in whitelist_names: -+ node.SetWhitelistMarkedAsSkip(True) -+ -+ @staticmethod -+ def ProcessNode(node, output_node, outfile): -+ '''Processes a node in-order, calling its formatter before and after -+ recursing to its children. -+ -+ Args: -+ node: grit.node.base.Node subclass -+ output_node: grit.node.io.OutputNode -+ outfile: open filehandle -+ ''' -+ base_dir = util.dirname(output_node.GetOutputFilename()) -+ -+ formatter = GetFormatter(output_node.GetType()) -+ formatted = formatter(node, output_node.GetLanguage(), output_dir=base_dir) -+ # NB: Formatters may be generators or return lists. The writelines API -+ # accepts iterables as a shortcut to calling write directly. That means -+ # you can pass strings (iteration yields characters), but not bytes (as -+ # iteration yields integers). Python 2 worked due to its quirks with -+ # bytes/string implementation, but Python 3 fails. It's also a bit more -+ # inefficient to call write once per character/byte. Handle all of this -+ # ourselves by calling write directly on strings/bytes before falling back -+ # to writelines. -+ if isinstance(formatted, (six.string_types, six.binary_type)): -+ outfile.write(formatted) -+ else: -+ outfile.writelines(formatted) -+ if output_node.GetType() == 'data_package': -+ with open(output_node.GetOutputFilename() + '.info', 'w') as infofile: -+ if node.info: -+ # We terminate with a newline so that when these files are -+ # concatenated later we consistently terminate with a newline so -+ # consumers can account for terminating newlines. -+ infofile.writelines(['\n'.join(node.info), '\n']) -+ -+ @staticmethod -+ def _EncodingForOutputType(output_type): -+ # Microsoft's RC compiler can only deal with single-byte or double-byte -+ # files (no UTF-8), so we make all RC files UTF-16 to support all -+ # character sets. -+ if output_type in ('rc_header', 'resource_file_map_source', -+ 'resource_map_header', 'resource_map_source'): -+ return 'cp1252' -+ if output_type in ('android', 'c_format', 'plist', 'plist_strings', 'doc', -+ 'json', 'android_policy', 'chrome_messages_json', -+ 'chrome_messages_json_gzip', 'policy_templates'): -+ return 'utf_8' -+ # TODO(gfeher) modify here to set utf-8 encoding for admx/adml -+ return 'utf_16' -+ -+ def Process(self): -+ for output in self.res.GetOutputFiles(): -+ output.output_filename = os.path.abspath(os.path.join( -+ self.output_directory, output.GetOutputFilename())) -+ -+ # If there are whitelisted names, tag the tree once up front, this way -+ # while looping through the actual output, it is just an attribute check. -+ if self.whitelist_names: -+ self.AddWhitelistTags(self.res, self.whitelist_names) -+ -+ for output in self.res.GetOutputFiles(): -+ self.VerboseOut('Creating %s...' % output.GetOutputFilename()) -+ -+ # Set the context, for conditional inclusion of resources -+ self.res.SetOutputLanguage(output.GetLanguage()) -+ self.res.SetOutputContext(output.GetContext()) -+ self.res.SetFallbackToDefaultLayout(output.GetFallbackToDefaultLayout()) -+ self.res.SetDefines(self.defines) -+ -+ # Assign IDs only once to ensure that all outputs use the same IDs. -+ if self.res.GetIdMap() is None: -+ self.res.InitializeIds() -+ -+ # Make the output directory if it doesn't exist. -+ self.MakeDirectoriesTo(output.GetOutputFilename()) -+ -+ # Write the results to a temporary file and only overwrite the original -+ # if the file changed. This avoids unnecessary rebuilds. -+ out_filename = output.GetOutputFilename() -+ tmp_filename = out_filename + '.tmp' -+ tmpfile = self.fo_create(tmp_filename, 'wb') -+ -+ output_type = output.GetType() -+ if output_type != 'data_package': -+ encoding = self._EncodingForOutputType(output_type) -+ tmpfile = util.WrapOutputStream(tmpfile, encoding) -+ -+ # Iterate in-order through entire resource tree, calling formatters on -+ # the entry into a node and on exit out of it. -+ with tmpfile: -+ self.ProcessNode(self.res, output, tmpfile) -+ -+ if output_type == 'chrome_messages_json_gzip': -+ gz_filename = tmp_filename + '.gz' -+ with open(tmp_filename, 'rb') as tmpfile, open(gz_filename, 'wb') as f: -+ with gzip.GzipFile(filename='', mode='wb', fileobj=f, mtime=0) as fgz: -+ shutil.copyfileobj(tmpfile, fgz) -+ os.remove(tmp_filename) -+ tmp_filename = gz_filename -+ -+ # Now copy from the temp file back to the real output, but on Windows, -+ # only if the real output doesn't exist or the contents of the file -+ # changed. This prevents identical headers from being written and .cc -+ # files from recompiling (which is painful on Windows). -+ if not os.path.exists(out_filename): -+ os.rename(tmp_filename, out_filename) -+ else: -+ # CHROMIUM SPECIFIC CHANGE. -+ # This clashes with gyp + vstudio, which expect the output timestamp -+ # to change on a rebuild, even if nothing has changed, so only do -+ # it when opted in. -+ if not self.write_only_new: -+ write_file = True -+ else: -+ files_match = filecmp.cmp(out_filename, tmp_filename) -+ write_file = not files_match -+ if write_file: -+ shutil.copy2(tmp_filename, out_filename) -+ os.remove(tmp_filename) -+ -+ self.VerboseOut(' done.\n') -+ -+ # Print warnings if there are any duplicate shortcuts. -+ warnings = shortcuts.GenerateDuplicateShortcutsWarnings( -+ self.res.UberClique(), self.res.GetTcProject()) -+ if warnings: -+ print('\n'.join(warnings)) -+ -+ # Print out any fallback warnings, and missing translation errors, and -+ # exit with an error code if there are missing translations in a non-pseudo -+ # and non-official build. -+ warnings = (self.res.UberClique().MissingTranslationsReport(). -+ encode('ascii', 'replace')) -+ if warnings: -+ self.VerboseOut(warnings) -+ if self.res.UberClique().HasMissingTranslations(): -+ print(self.res.UberClique().missing_translations_) -+ sys.exit(-1) -+ -+ -+ def CheckAssertedOutputFiles(self, assert_output_files): -+ '''Checks that the asserted output files are specified in the given list. -+ -+ Returns true if the asserted files are present. If they are not, returns -+ False and prints the failure. -+ ''' -+ # Compare the absolute path names, sorted. -+ asserted = sorted([os.path.abspath(i) for i in assert_output_files]) -+ actual = sorted([ -+ os.path.abspath(os.path.join(self.output_directory, -+ i.GetOutputFilename())) -+ for i in self.res.GetOutputFiles()]) -+ -+ if asserted != actual: -+ missing = list(set(asserted) - set(actual)) -+ extra = list(set(actual) - set(asserted)) -+ error = '''Asserted file list does not match. -+ -+Expected output files: -+%s -+Actual output files: -+%s -+Missing output files: -+%s -+Extra output files: -+%s -+''' -+ print(error % ('\n'.join(asserted), '\n'.join(actual), '\n'.join(missing), -+ ' \n'.join(extra))) -+ return False -+ return True -+ -+ -+ def GenerateDepfile(self, depfile, depdir, first_ids_file, depend_on_stamp): -+ '''Generate a depfile that contains the imlicit dependencies of the input -+ grd. The depfile will be in the same format as a makefile, and will contain -+ references to files relative to |depdir|. It will be put in |depfile|. -+ -+ For example, supposing we have three files in a directory src/ -+ -+ src/ -+ blah.grd <- depends on input{1,2}.xtb -+ input1.xtb -+ input2.xtb -+ -+ and we run -+ -+ grit -i blah.grd -o ../out/gen \ -+ --depdir ../out \ -+ --depfile ../out/gen/blah.rd.d -+ -+ from the directory src/ we will generate a depfile ../out/gen/blah.grd.d -+ that has the contents -+ -+ gen/blah.h: ../src/input1.xtb ../src/input2.xtb -+ -+ Where "gen/blah.h" is the first output (Ninja expects the .d file to list -+ the first output in cases where there is more than one). If the flag -+ --depend-on-stamp is specified, "gen/blah.rd.d.stamp" will be used that is -+ 'touched' whenever a new depfile is generated. -+ -+ Note that all paths in the depfile are relative to ../out, the depdir. -+ ''' -+ depfile = os.path.abspath(depfile) -+ depdir = os.path.abspath(depdir) -+ infiles = self.res.GetInputFiles() -+ -+ # We want to trigger a rebuild if the first ids change. -+ if first_ids_file is not None: -+ infiles.append(first_ids_file) -+ -+ if (depend_on_stamp): -+ output_file = depfile + ".stamp" -+ # Touch the stamp file before generating the depfile. -+ with open(output_file, 'a'): -+ os.utime(output_file, None) -+ else: -+ # Get the first output file relative to the depdir. -+ outputs = self.res.GetOutputFiles() -+ output_file = os.path.join(self.output_directory, -+ outputs[0].GetOutputFilename()) -+ -+ output_file = os.path.relpath(output_file, depdir) -+ # The path prefix to prepend to dependencies in the depfile. -+ prefix = os.path.relpath(os.getcwd(), depdir) -+ deps_text = ' '.join([os.path.join(prefix, i) for i in infiles]) -+ -+ depfile_contents = output_file + ': ' + deps_text -+ self.MakeDirectoriesTo(depfile) -+ outfile = self.fo_create(depfile, 'w', encoding='utf-8') -+ outfile.write(depfile_contents) -+ -+ @staticmethod -+ def MakeDirectoriesTo(file): -+ '''Creates directories necessary to contain |file|.''' -+ dir = os.path.split(file)[0] -+ if not os.path.exists(dir): -+ os.makedirs(dir) -diff --git a/tools/grit/grit/tool/build_unittest.py b/tools/grit/grit/tool/build_unittest.py -new file mode 100644 -index 0000000000..c4a2f2752b ---- /dev/null -+++ b/tools/grit/grit/tool/build_unittest.py -@@ -0,0 +1,341 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for the 'grit build' tool. -+''' -+ -+from __future__ import print_function -+ -+import codecs -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+import unittest -+ -+from grit import util -+from grit.tool import build -+ -+ -+class BuildUnittest(unittest.TestCase): -+ -+ # IDs should not change based on whitelisting. -+ # Android WebView currently relies on this. -+ EXPECTED_ID_MAP = { -+ 'IDS_MESSAGE_WHITELISTED': 6889, -+ 'IDR_STRUCTURE_WHITELISTED': 11546, -+ 'IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED': 11548, -+ 'IDR_INCLUDE_WHITELISTED': 15601, -+ } -+ -+ def testFindTranslationsWithSubstitutions(self): -+ # This is a regression test; we had a bug where GRIT would fail to find -+ # messages with substitutions e.g. "Hello [IDS_USER]" where IDS_USER is -+ # another . -+ output_dir = util.TempDir({}) -+ builder = build.RcBuilder() -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/substitute.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ builder.Run(DummyOpts(), ['-o', output_dir.GetPath()]) -+ output_dir.CleanUp() -+ -+ def testGenerateDepFile(self): -+ output_dir = util.TempDir({}) -+ builder = build.RcBuilder() -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/depfile.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ expected_dep_file = output_dir.GetPath('substitute.grd.d') -+ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), -+ '--depdir', output_dir.GetPath(), -+ '--depfile', expected_dep_file]) -+ -+ self.failUnless(os.path.isfile(expected_dep_file)) -+ with open(expected_dep_file) as f: -+ line = f.readline() -+ (dep_output_file, deps_string) = line.split(': ') -+ deps = deps_string.split(' ') -+ -+ self.failUnlessEqual("default_100_percent.pak", dep_output_file) -+ self.failUnlessEqual(deps, [ -+ util.PathFromRoot('grit/testdata/default_100_percent/a.png'), -+ util.PathFromRoot('grit/testdata/grit_part.grdp'), -+ util.PathFromRoot('grit/testdata/special_100_percent/a.png'), -+ ]) -+ output_dir.CleanUp() -+ -+ def testGenerateDepFileWithResourceIds(self): -+ output_dir = util.TempDir({}) -+ builder = build.RcBuilder() -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/substitute_no_ids.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ expected_dep_file = output_dir.GetPath('substitute_no_ids.grd.d') -+ builder.Run(DummyOpts(), -+ ['-f', util.PathFromRoot('grit/testdata/resource_ids'), -+ '-o', output_dir.GetPath(), -+ '--depdir', output_dir.GetPath(), -+ '--depfile', expected_dep_file]) -+ -+ self.failUnless(os.path.isfile(expected_dep_file)) -+ with open(expected_dep_file) as f: -+ line = f.readline() -+ (dep_output_file, deps_string) = line.split(': ') -+ deps = deps_string.split(' ') -+ -+ self.failUnlessEqual("resource.h", dep_output_file) -+ self.failUnlessEqual(2, len(deps)) -+ self.failUnlessEqual(deps[0], -+ util.PathFromRoot('grit/testdata/substitute.xmb')) -+ self.failUnlessEqual(deps[1], -+ util.PathFromRoot('grit/testdata/resource_ids')) -+ output_dir.CleanUp() -+ -+ def testAssertOutputs(self): -+ output_dir = util.TempDir({}) -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/substitute.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ -+ # Incomplete output file list should fail. -+ builder_fail = build.RcBuilder() -+ self.failUnlessEqual(2, -+ builder_fail.Run(DummyOpts(), [ -+ '-o', output_dir.GetPath(), -+ '-a', os.path.abspath( -+ output_dir.GetPath('en_generated_resources.rc'))])) -+ -+ # Complete output file list should succeed. -+ builder_ok = build.RcBuilder() -+ self.failUnlessEqual(0, -+ builder_ok.Run(DummyOpts(), [ -+ '-o', output_dir.GetPath(), -+ '-a', os.path.abspath( -+ output_dir.GetPath('en_generated_resources.rc')), -+ '-a', os.path.abspath( -+ output_dir.GetPath('sv_generated_resources.rc')), -+ '-a', os.path.abspath(output_dir.GetPath('resource.h'))])) -+ output_dir.CleanUp() -+ -+ def testAssertTemplateOutputs(self): -+ output_dir = util.TempDir({}) -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/substitute_tmpl.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ -+ # Incomplete output file list should fail. -+ builder_fail = build.RcBuilder() -+ self.failUnlessEqual(2, -+ builder_fail.Run(DummyOpts(), [ -+ '-o', output_dir.GetPath(), -+ '-E', 'name=foo', -+ '-a', os.path.abspath(output_dir.GetPath('en_foo_resources.rc'))])) -+ -+ # Complete output file list should succeed. -+ builder_ok = build.RcBuilder() -+ self.failUnlessEqual(0, -+ builder_ok.Run(DummyOpts(), [ -+ '-o', output_dir.GetPath(), -+ '-E', 'name=foo', -+ '-a', os.path.abspath(output_dir.GetPath('en_foo_resources.rc')), -+ '-a', os.path.abspath(output_dir.GetPath('sv_foo_resources.rc')), -+ '-a', os.path.abspath(output_dir.GetPath('resource.h'))])) -+ output_dir.CleanUp() -+ -+ def _verifyWhitelistedOutput(self, -+ filename, -+ whitelisted_ids, -+ non_whitelisted_ids, -+ encoding='utf8'): -+ self.failUnless(os.path.exists(filename)) -+ whitelisted_ids_found = [] -+ non_whitelisted_ids_found = [] -+ with codecs.open(filename, encoding=encoding) as f: -+ for line in f.readlines(): -+ for whitelisted_id in whitelisted_ids: -+ if whitelisted_id in line: -+ whitelisted_ids_found.append(whitelisted_id) -+ if filename.endswith('.h'): -+ numeric_id = int(line.split()[2]) -+ expected_numeric_id = self.EXPECTED_ID_MAP.get(whitelisted_id) -+ self.assertEqual( -+ expected_numeric_id, numeric_id, -+ 'Numeric ID for {} was {} should be {}'.format( -+ whitelisted_id, numeric_id, expected_numeric_id)) -+ for non_whitelisted_id in non_whitelisted_ids: -+ if non_whitelisted_id in line: -+ non_whitelisted_ids_found.append(non_whitelisted_id) -+ self.longMessage = True -+ self.assertEqual(whitelisted_ids, -+ whitelisted_ids_found, -+ '\nin file {}'.format(os.path.basename(filename))) -+ non_whitelisted_msg = ('Non-Whitelisted IDs {} found in {}' -+ .format(non_whitelisted_ids_found, os.path.basename(filename))) -+ self.assertFalse(non_whitelisted_ids_found, non_whitelisted_msg) -+ -+ def testWhitelistStrings(self): -+ output_dir = util.TempDir({}) -+ builder = build.RcBuilder() -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/whitelist_strings.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ whitelist_file = util.PathFromRoot('grit/testdata/whitelist.txt') -+ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), -+ '-w', whitelist_file]) -+ header = output_dir.GetPath('whitelist_test_resources.h') -+ rc = output_dir.GetPath('en_whitelist_test_strings.rc') -+ -+ whitelisted_ids = ['IDS_MESSAGE_WHITELISTED'] -+ non_whitelisted_ids = ['IDS_MESSAGE_NOT_WHITELISTED'] -+ self._verifyWhitelistedOutput( -+ header, -+ whitelisted_ids, -+ non_whitelisted_ids, -+ ) -+ self._verifyWhitelistedOutput( -+ rc, -+ whitelisted_ids, -+ non_whitelisted_ids, -+ encoding='utf16' -+ ) -+ output_dir.CleanUp() -+ -+ def testWhitelistResources(self): -+ output_dir = util.TempDir({}) -+ builder = build.RcBuilder() -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/whitelist_resources.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ whitelist_file = util.PathFromRoot('grit/testdata/whitelist.txt') -+ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), -+ '-w', whitelist_file]) -+ header = output_dir.GetPath('whitelist_test_resources.h') -+ map_cc = output_dir.GetPath('whitelist_test_resources_map.cc') -+ map_h = output_dir.GetPath('whitelist_test_resources_map.h') -+ pak = output_dir.GetPath('whitelist_test_resources.pak') -+ -+ # Ensure the resource map header and .pak files exist, but don't verify -+ # their content. -+ self.failUnless(os.path.exists(map_h)) -+ self.failUnless(os.path.exists(pak)) -+ -+ whitelisted_ids = [ -+ 'IDR_STRUCTURE_WHITELISTED', -+ 'IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED', -+ 'IDR_INCLUDE_WHITELISTED', -+ ] -+ non_whitelisted_ids = [ -+ 'IDR_STRUCTURE_NOT_WHITELISTED', -+ 'IDR_STRUCTURE_IN_TRUE_IF_NOT_WHITELISTED', -+ 'IDR_STRUCTURE_IN_FALSE_IF_WHITELISTED', -+ 'IDR_STRUCTURE_IN_FALSE_IF_NOT_WHITELISTED', -+ 'IDR_INCLUDE_NOT_WHITELISTED', -+ ] -+ for output_file in (header, map_cc): -+ self._verifyWhitelistedOutput( -+ output_file, -+ whitelisted_ids, -+ non_whitelisted_ids, -+ ) -+ output_dir.CleanUp() -+ -+ def testWriteOnlyNew(self): -+ output_dir = util.TempDir({}) -+ builder = build.RcBuilder() -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/substitute.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ UNCHANGED = 10 -+ header = output_dir.GetPath('resource.h') -+ -+ builder.Run(DummyOpts(), ['-o', output_dir.GetPath()]) -+ self.failUnless(os.path.exists(header)) -+ first_mtime = os.stat(header).st_mtime -+ -+ os.utime(header, (UNCHANGED, UNCHANGED)) -+ builder.Run(DummyOpts(), -+ ['-o', output_dir.GetPath(), '--write-only-new', '0']) -+ self.failUnless(os.path.exists(header)) -+ second_mtime = os.stat(header).st_mtime -+ -+ os.utime(header, (UNCHANGED, UNCHANGED)) -+ builder.Run(DummyOpts(), -+ ['-o', output_dir.GetPath(), '--write-only-new', '1']) -+ self.failUnless(os.path.exists(header)) -+ third_mtime = os.stat(header).st_mtime -+ -+ self.assertTrue(abs(second_mtime - UNCHANGED) > 5) -+ self.assertTrue(abs(third_mtime - UNCHANGED) < 5) -+ output_dir.CleanUp() -+ -+ def testGenerateDepFileWithDependOnStamp(self): -+ output_dir = util.TempDir({}) -+ builder = build.RcBuilder() -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = util.PathFromRoot('grit/testdata/substitute.grd') -+ self.verbose = False -+ self.extra_verbose = False -+ expected_dep_file_name = 'substitute.grd.d' -+ expected_stamp_file_name = expected_dep_file_name + '.stamp' -+ expected_dep_file = output_dir.GetPath(expected_dep_file_name) -+ expected_stamp_file = output_dir.GetPath(expected_stamp_file_name) -+ if os.path.isfile(expected_stamp_file): -+ os.remove(expected_stamp_file) -+ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), -+ '--depdir', output_dir.GetPath(), -+ '--depfile', expected_dep_file, -+ '--depend-on-stamp']) -+ self.failUnless(os.path.isfile(expected_stamp_file)) -+ first_mtime = os.stat(expected_stamp_file).st_mtime -+ -+ # Reset mtime to very old. -+ OLDTIME = 10 -+ os.utime(expected_stamp_file, (OLDTIME, OLDTIME)) -+ -+ builder.Run(DummyOpts(), ['-o', output_dir.GetPath(), -+ '--depdir', output_dir.GetPath(), -+ '--depfile', expected_dep_file, -+ '--depend-on-stamp']) -+ self.failUnless(os.path.isfile(expected_stamp_file)) -+ second_mtime = os.stat(expected_stamp_file).st_mtime -+ -+ # Some OS have a 2s stat resolution window, so can't do a direct comparison. -+ self.assertTrue((second_mtime - OLDTIME) > 5) -+ self.assertTrue(abs(second_mtime - first_mtime) < 5) -+ -+ self.failUnless(os.path.isfile(expected_dep_file)) -+ with open(expected_dep_file) as f: -+ line = f.readline() -+ (dep_output_file, deps_string) = line.split(': ') -+ deps = deps_string.split(' ') -+ -+ self.failUnlessEqual(expected_stamp_file_name, dep_output_file) -+ self.failUnlessEqual(deps, [ -+ util.PathFromRoot('grit/testdata/substitute.xmb'), -+ ]) -+ output_dir.CleanUp() -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/tool/buildinfo.py b/tools/grit/grit/tool/buildinfo.py -new file mode 100644 -index 0000000000..7f8d1a3b04 ---- /dev/null -+++ b/tools/grit/grit/tool/buildinfo.py -@@ -0,0 +1,78 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Output the list of files to be generated by GRIT from an input. -+""" -+ -+from __future__ import print_function -+ -+import getopt -+import os -+import sys -+ -+from grit import grd_reader -+from grit.node import structure -+from grit.tool import interface -+ -+class DetermineBuildInfo(interface.Tool): -+ """Determine what files will be read and output by GRIT. -+Outputs the list of generated files and inputs used to stdout. -+ -+Usage: grit buildinfo [-o DIR] -+ -+The output directory is used for display only. -+""" -+ -+ def __init__(self): -+ pass -+ -+ def ShortDescription(self): -+ """Describes this tool for the usage message.""" -+ return ('Determine what files will be needed and\n' -+ 'output by GRIT with a given input.') -+ -+ def Run(self, opts, args): -+ """Main method for the buildinfo tool.""" -+ self.output_directory = '.' -+ (own_opts, args) = getopt.getopt(args, 'o:', ('help',)) -+ for (key, val) in own_opts: -+ if key == '-o': -+ self.output_directory = val -+ elif key == '--help': -+ self.ShowUsage() -+ sys.exit(0) -+ if len(args) > 0: -+ print('This tool takes exactly one argument: the output directory via -o') -+ return 2 -+ self.SetOptions(opts) -+ -+ res_tree = grd_reader.Parse(opts.input, debug=opts.extra_verbose) -+ -+ langs = {} -+ for output in res_tree.GetOutputFiles(): -+ if output.attrs['lang']: -+ langs[output.attrs['lang']] = os.path.dirname(output.GetFilename()) -+ -+ for lang, dirname in langs.items(): -+ old_output_language = res_tree.output_language -+ res_tree.SetOutputLanguage(lang) -+ for node in res_tree.ActiveDescendants(): -+ with node: -+ if (isinstance(node, structure.StructureNode) and -+ node.HasFileForLanguage()): -+ path = node.FileForLanguage(lang, dirname, create_file=False, -+ return_if_not_generated=False) -+ if path: -+ path = os.path.join(self.output_directory, path) -+ path = os.path.normpath(path) -+ print('%s|%s' % ('rc_all', path)) -+ res_tree.SetOutputLanguage(old_output_language) -+ -+ for output in res_tree.GetOutputFiles(): -+ path = os.path.join(self.output_directory, output.GetFilename()) -+ path = os.path.normpath(path) -+ print('%s|%s' % (output.GetType(), path)) -+ -+ for infile in res_tree.GetInputFiles(): -+ print('input|%s' % os.path.normpath(infile)) -diff --git a/tools/grit/grit/tool/buildinfo_unittest.py b/tools/grit/grit/tool/buildinfo_unittest.py -new file mode 100644 -index 0000000000..24e9ddf8d8 ---- /dev/null -+++ b/tools/grit/grit/tool/buildinfo_unittest.py -@@ -0,0 +1,90 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Unit tests for the 'grit buildinfo' tool. -+""" -+ -+from __future__ import print_function -+ -+import os -+import sys -+import unittest -+ -+# This is needed to find some of the imports below. -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+from six import StringIO -+ -+# pylint: disable-msg=C6204 -+from grit.tool import buildinfo -+ -+ -+class BuildInfoUnittest(unittest.TestCase): -+ def setUp(self): -+ self.old_cwd = os.getcwd() -+ # Change CWD to make tests work independently of callers CWD. -+ os.chdir(os.path.dirname(__file__)) -+ os.chdir('..') -+ self.buf = StringIO() -+ self.old_stdout = sys.stdout -+ sys.stdout = self.buf -+ -+ def tearDown(self): -+ sys.stdout = self.old_stdout -+ os.chdir(self.old_cwd) -+ -+ def testBuildOutput(self): -+ """Find all of the inputs and outputs for a GRD file.""" -+ info_object = buildinfo.DetermineBuildInfo() -+ -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = '../grit/testdata/buildinfo.grd' -+ self.print_header = False -+ self.verbose = False -+ self.extra_verbose = False -+ info_object.Run(DummyOpts(), []) -+ output = self.buf.getvalue().replace('\\', '/') -+ self.failUnless(output.count(r'rc_all|sv_sidebar_loading.html')) -+ self.failUnless(output.count(r'rc_header|resource.h')) -+ self.failUnless(output.count(r'rc_all|en_generated_resources.rc')) -+ self.failUnless(output.count(r'rc_all|sv_generated_resources.rc')) -+ self.failUnless(output.count(r'input|../grit/testdata/substitute.xmb')) -+ self.failUnless(output.count(r'input|../grit/testdata/pr.bmp')) -+ self.failUnless(output.count(r'input|../grit/testdata/pr2.bmp')) -+ self.failUnless( -+ output.count(r'input|../grit/testdata/sidebar_loading.html')) -+ self.failUnless(output.count(r'input|../grit/testdata/transl.rc')) -+ self.failUnless(output.count(r'input|../grit/testdata/transl1.rc')) -+ -+ def testBuildOutputWithDir(self): -+ """Find all the inputs and outputs for a GRD file with an output dir.""" -+ info_object = buildinfo.DetermineBuildInfo() -+ -+ class DummyOpts(object): -+ def __init__(self): -+ self.input = '../grit/testdata/buildinfo.grd' -+ self.print_header = False -+ self.verbose = False -+ self.extra_verbose = False -+ info_object.Run(DummyOpts(), ['-o', '../grit/testdata']) -+ output = self.buf.getvalue().replace('\\', '/') -+ self.failUnless( -+ output.count(r'rc_all|../grit/testdata/sv_sidebar_loading.html')) -+ self.failUnless(output.count(r'rc_header|../grit/testdata/resource.h')) -+ self.failUnless( -+ output.count(r'rc_all|../grit/testdata/en_generated_resources.rc')) -+ self.failUnless( -+ output.count(r'rc_all|../grit/testdata/sv_generated_resources.rc')) -+ self.failUnless(output.count(r'input|../grit/testdata/substitute.xmb')) -+ self.failUnlessEqual(0, -+ output.count(r'rc_all|../grit/testdata/sv_welcome_toast.html')) -+ self.failUnless( -+ output.count(r'rc_all|../grit/testdata/en_welcome_toast.html')) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/tool/count.py b/tools/grit/grit/tool/count.py -new file mode 100644 -index 0000000000..ab37f2ddb3 ---- /dev/null -+++ b/tools/grit/grit/tool/count.py -@@ -0,0 +1,52 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Count number of occurrences of a given message ID.''' -+ -+from __future__ import print_function -+ -+import getopt -+import sys -+ -+from grit import grd_reader -+from grit.tool import interface -+ -+ -+class CountMessage(interface.Tool): -+ '''Count the number of times a given message ID is used.''' -+ -+ def __init__(self): -+ pass -+ -+ def ShortDescription(self): -+ return 'Count the number of times a given message ID is used.' -+ -+ def ParseOptions(self, args): -+ """Set this objects and return all non-option arguments.""" -+ own_opts, args = getopt.getopt(args, '', ('help',)) -+ for key, val in own_opts: -+ if key == '--help': -+ self.ShowUsage() -+ sys.exit(0) -+ return args -+ -+ def Run(self, opts, args): -+ args = self.ParseOptions(args) -+ if len(args) != 1: -+ print('This tool takes a single tool-specific argument, the message ' -+ 'ID to count.') -+ return 2 -+ self.SetOptions(opts) -+ -+ id = args[0] -+ res_tree = grd_reader.Parse(opts.input, debug=opts.extra_verbose) -+ res_tree.OnlyTheseTranslations([]) -+ res_tree.RunGatherers() -+ -+ count = 0 -+ for c in res_tree.UberClique().AllCliques(): -+ if c.GetId() == id: -+ count += 1 -+ -+ print("There are %d occurrences of message %s." % (count, id)) -diff --git a/tools/grit/grit/tool/diff_structures.py b/tools/grit/grit/tool/diff_structures.py -new file mode 100644 -index 0000000000..d69e009b58 ---- /dev/null -+++ b/tools/grit/grit/tool/diff_structures.py -@@ -0,0 +1,119 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''The 'grit sdiff' tool. -+''' -+ -+from __future__ import print_function -+ -+import os -+import getopt -+import sys -+import tempfile -+ -+from grit.node import structure -+from grit.tool import interface -+ -+from grit import constants -+from grit import util -+ -+# Builds the description for the tool (used as the __doc__ -+# for the DiffStructures class). -+_class_doc = """\ -+Allows you to view the differences in the structure of two files, -+disregarding their translateable content. Translateable portions of -+each file are changed to the string "TTTTTT" before invoking the diff program -+specified by the P4DIFF environment variable. -+ -+Usage: grit sdiff [-t TYPE] [-s SECTION] [-e ENCODING] LEFT RIGHT -+ -+LEFT and RIGHT are the files you want to diff. SECTION is required -+for structure types like 'dialog' to identify the part of the file to look at. -+ENCODING indicates the encoding of the left and right files (default 'cp1252'). -+TYPE can be one of the following, defaults to 'tr_html': -+""" -+for gatherer in structure._GATHERERS: -+ _class_doc += " - %s\n" % gatherer -+ -+ -+class DiffStructures(interface.Tool): -+ __doc__ = _class_doc -+ -+ def __init__(self): -+ self.section = None -+ self.left_encoding = 'cp1252' -+ self.right_encoding = 'cp1252' -+ self.structure_type = 'tr_html' -+ -+ def ShortDescription(self): -+ return 'View differences without regard for translateable portions.' -+ -+ def Run(self, global_opts, args): -+ (opts, args) = getopt.getopt(args, 's:e:t:', -+ ('help', 'left_encoding=', 'right_encoding=')) -+ for key, val in opts: -+ if key == '-s': -+ self.section = val -+ elif key == '-e': -+ self.left_encoding = val -+ self.right_encoding = val -+ elif key == '-t': -+ self.structure_type = val -+ elif key == '--left_encoding': -+ self.left_encoding = val -+ elif key == '--right_encoding': -+ self.right_encoding == val -+ elif key == '--help': -+ self.ShowUsage() -+ sys.exit(0) -+ -+ if len(args) != 2: -+ print("Incorrect usage - 'grit help sdiff' for usage details.") -+ return 2 -+ -+ if 'P4DIFF' not in os.environ: -+ print("Environment variable P4DIFF not set; defaulting to 'windiff'.") -+ diff_program = 'windiff' -+ else: -+ diff_program = os.environ['P4DIFF'] -+ -+ left_trans = self.MakeStaticTranslation(args[0], self.left_encoding) -+ try: -+ try: -+ right_trans = self.MakeStaticTranslation(args[1], self.right_encoding) -+ -+ os.system('%s %s %s' % (diff_program, left_trans, right_trans)) -+ finally: -+ os.unlink(right_trans) -+ finally: -+ os.unlink(left_trans) -+ -+ def MakeStaticTranslation(self, original_filename, encoding): -+ """Given the name of the structure type (self.structure_type), the filename -+ of the file holding the original structure, and optionally the "section" key -+ identifying the part of the file to look at (self.section), creates a -+ temporary file holding a "static" translation of the original structure -+ (i.e. one where all translateable parts have been replaced with "TTTTTT") -+ and returns the temporary file name. It is the caller's responsibility to -+ delete the file when finished. -+ -+ Args: -+ original_filename: 'c:\\bingo\\bla.rc' -+ -+ Return: -+ 'c:\\temp\\werlkjsdf334.tmp' -+ """ -+ original = structure._GATHERERS[self.structure_type](original_filename, -+ extkey=self.section, -+ encoding=encoding) -+ original.Parse() -+ translated = original.Translate(constants.CONSTANT_LANGUAGE, False) -+ -+ fname = tempfile.mktemp() -+ with util.WrapOutputStream(open(fname, 'wb')) as writer: -+ writer.write("Original filename: %s\n=============\n\n" -+ % original_filename) -+ writer.write(translated) # write in UTF-8 -+ -+ return fname -diff --git a/tools/grit/grit/tool/diff_structures_unittest.py b/tools/grit/grit/tool/diff_structures_unittest.py -new file mode 100644 -index 0000000000..a6d7585761 ---- /dev/null -+++ b/tools/grit/grit/tool/diff_structures_unittest.py -@@ -0,0 +1,46 @@ -+#!/usr/bin/env python -+# Copyright 2020 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for the 'grit newgrd' tool.''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+import unittest -+ -+from grit.tool import diff_structures -+ -+ -+class DummyOpts(object): -+ """Options needed by NewGrd.""" -+ -+ -+class DiffStructuresUnittest(unittest.TestCase): -+ -+ def testMissingFiles(self): -+ """Verify failure w/out file inputs.""" -+ tool = diff_structures.DiffStructures() -+ ret = tool.Run(DummyOpts(), []) -+ self.assertIsNotNone(ret) -+ self.assertGreater(ret, 0) -+ -+ ret = tool.Run(DummyOpts(), ['left']) -+ self.assertIsNotNone(ret) -+ self.assertGreater(ret, 0) -+ -+ def testTooManyArgs(self): -+ """Verify failure w/too many inputs.""" -+ tool = diff_structures.DiffStructures() -+ ret = tool.Run(DummyOpts(), ['a', 'b', 'c']) -+ self.assertIsNotNone(ret) -+ self.assertGreater(ret, 0) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/tool/interface.py b/tools/grit/grit/tool/interface.py -new file mode 100644 -index 0000000000..e923205223 ---- /dev/null -+++ b/tools/grit/grit/tool/interface.py -@@ -0,0 +1,62 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Base class and interface for tools. -+''' -+ -+from __future__ import print_function -+ -+class Tool(object): -+ '''Base class for all tools. Tools should use their docstring (i.e. the -+ class-level docstring) for the help they want to have printed when they -+ are invoked.''' -+ -+ # -+ # Interface (abstract methods) -+ # -+ -+ def ShortDescription(self): -+ '''Returns a short description of the functionality of the tool.''' -+ raise NotImplementedError() -+ -+ def Run(self, global_options, my_arguments): -+ '''Runs the tool. -+ -+ Args: -+ global_options: object grit_runner.Options -+ my_arguments: [arg1 arg2 ...] -+ -+ Return: -+ 0 for success, non-0 for error -+ ''' -+ raise NotImplementedError() -+ -+ # -+ # Base class implementation -+ # -+ -+ def __init__(self): -+ self.o = None -+ -+ def ShowUsage(self): -+ '''Show usage text for this tool.''' -+ print(self.__doc__) -+ -+ def SetOptions(self, opts): -+ self.o = opts -+ -+ def Out(self, text): -+ '''Always writes out 'text'.''' -+ self.o.output_stream.write(text) -+ -+ def VerboseOut(self, text): -+ '''Writes out 'text' if the verbose option is on.''' -+ if self.o.verbose: -+ self.o.output_stream.write(text) -+ -+ def ExtraVerboseOut(self, text): -+ '''Writes out 'text' if the extra-verbose option is on. -+ ''' -+ if self.o.extra_verbose: -+ self.o.output_stream.write(text) -diff --git a/tools/grit/grit/tool/menu_from_parts.py b/tools/grit/grit/tool/menu_from_parts.py -new file mode 100644 -index 0000000000..fcec26c5b1 ---- /dev/null -+++ b/tools/grit/grit/tool/menu_from_parts.py -@@ -0,0 +1,79 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''The 'grit menufromparts' tool.''' -+ -+from __future__ import print_function -+ -+import six -+ -+from grit import grd_reader -+from grit import util -+from grit import xtb_reader -+from grit.tool import interface -+from grit.tool import transl2tc -+ -+import grit.extern.tclib -+ -+ -+class MenuTranslationsFromParts(interface.Tool): -+ '''One-off tool to generate translated menu messages (where each menu is kept -+in a single message) based on existing translations of the individual menu -+items. Was needed when changing menus from being one message per menu item -+to being one message for the whole menu.''' -+ -+ def ShortDescription(self): -+ return ('Create translations of whole menus from existing translations of ' -+ 'menu items.') -+ -+ def Run(self, globopt, args): -+ self.SetOptions(globopt) -+ assert len(args) == 2, "Need exactly two arguments, the XTB file and the output file" -+ -+ xtb_file = args[0] -+ output_file = args[1] -+ -+ grd = grd_reader.Parse(self.o.input, debug=self.o.extra_verbose) -+ grd.OnlyTheseTranslations([]) # don't load translations -+ grd.RunGatherers() -+ -+ xtb = {} -+ def Callback(msg_id, parts): -+ msg = [] -+ for part in parts: -+ if part[0]: -+ msg = [] -+ break # it had a placeholder so ignore it -+ else: -+ msg.append(part[1]) -+ if len(msg): -+ xtb[msg_id] = ''.join(msg) -+ with open(xtb_file, 'rb') as f: -+ xtb_reader.Parse(f, Callback) -+ -+ translations = [] # list of translations as per transl2tc.WriteTranslations -+ for node in grd: -+ if node.name == 'structure' and node.attrs['type'] == 'menu': -+ assert len(node.GetCliques()) == 1 -+ message = node.GetCliques()[0].GetMessage() -+ translation = [] -+ -+ contents = message.GetContent() -+ for part in contents: -+ if isinstance(part, six.string_types): -+ id = grit.extern.tclib.GenerateMessageId(part) -+ if id not in xtb: -+ print("WARNING didn't find all translations for menu %s" % -+ (node.attrs['name'],)) -+ translation = [] -+ break -+ translation.append(xtb[id]) -+ else: -+ translation.append(part.GetPresentation()) -+ -+ if len(translation): -+ translations.append([message.GetId(), ''.join(translation)]) -+ -+ with util.WrapOutputStream(open(output_file, 'wb')) as f: -+ transl2tc.TranslationToTc.WriteTranslations(f, translations) -diff --git a/tools/grit/grit/tool/newgrd.py b/tools/grit/grit/tool/newgrd.py -new file mode 100644 -index 0000000000..66a18e9c04 ---- /dev/null -+++ b/tools/grit/grit/tool/newgrd.py -@@ -0,0 +1,85 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Tool to create a new, empty .grd file with all the basic sections. -+''' -+ -+from __future__ import print_function -+ -+import getopt -+import sys -+ -+from grit.tool import interface -+from grit import constants -+from grit import util -+ -+# The contents of the new .grd file -+_FILE_CONTENTS = '''\ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+''' % constants.ENCODING_CHECK -+ -+ -+class NewGrd(interface.Tool): -+ '''Usage: grit newgrd OUTPUT_FILE -+ -+Creates a new, empty .grd file OUTPUT_FILE with comments about what to put -+where in the file.''' -+ -+ def ShortDescription(self): -+ return 'Create a new empty .grd file.' -+ -+ def ParseOptions(self, args): -+ """Set this objects and return all non-option arguments.""" -+ own_opts, args = getopt.getopt(args, '', ('help',)) -+ for key, val in own_opts: -+ if key == '--help': -+ self.ShowUsage() -+ sys.exit(0) -+ return args -+ -+ def Run(self, opts, args): -+ args = self.ParseOptions(args) -+ if len(args) != 1: -+ print('This tool requires exactly one argument, the name of the output ' -+ 'file.') -+ return 2 -+ filename = args[0] -+ with util.WrapOutputStream(open(filename, 'wb'), 'utf-8') as out: -+ out.write(_FILE_CONTENTS) -+ print("Wrote file %s" % filename) -diff --git a/tools/grit/grit/tool/newgrd_unittest.py b/tools/grit/grit/tool/newgrd_unittest.py -new file mode 100644 -index 0000000000..f7c8831df5 ---- /dev/null -+++ b/tools/grit/grit/tool/newgrd_unittest.py -@@ -0,0 +1,51 @@ -+#!/usr/bin/env python -+# Copyright 2020 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for the 'grit newgrd' tool.''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+import unittest -+ -+from grit import util -+from grit.tool import newgrd -+ -+ -+class DummyOpts(object): -+ """Options needed by NewGrd.""" -+ -+ -+class NewgrdUnittest(unittest.TestCase): -+ -+ def testNewFile(self): -+ """Create a new file.""" -+ tool = newgrd.NewGrd() -+ with util.TempDir({}) as output_dir: -+ output_file = os.path.join(output_dir.GetPath(), 'new.grd') -+ self.assertIsNone(tool.Run(DummyOpts(), [output_file])) -+ self.assertTrue(os.path.exists(output_file)) -+ -+ def testMissingFile(self): -+ """Verify failure w/out file output.""" -+ tool = newgrd.NewGrd() -+ ret = tool.Run(DummyOpts(), []) -+ self.assertIsNotNone(ret) -+ self.assertGreater(ret, 0) -+ -+ def testTooManyArgs(self): -+ """Verify failure w/too many outputs.""" -+ tool = newgrd.NewGrd() -+ ret = tool.Run(DummyOpts(), ['a', 'b']) -+ self.assertIsNotNone(ret) -+ self.assertGreater(ret, 0) -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/tool/postprocess_interface.py b/tools/grit/grit/tool/postprocess_interface.py -new file mode 100644 -index 0000000000..4bb8c5871f ---- /dev/null -+++ b/tools/grit/grit/tool/postprocess_interface.py -@@ -0,0 +1,29 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+''' Base class for postprocessing of RC files. -+''' -+ -+from __future__ import print_function -+ -+class PostProcessor(object): -+ ''' Base class for postprocessing of the RC file data before being -+ output through the RC2GRD tool. You should implement this class if -+ you want GRIT to do specific things to the RC files after it has -+ converted the data into GRD format, i.e. change the content of the -+ RC file, and put it into a P4 changelist, etc.''' -+ -+ -+ def Process(self, rctext, rcpath, grdnode): -+ ''' Processes the data in rctext and grdnode. -+ Args: -+ rctext: string containing the contents of the RC file being processed. -+ rcpath: the path used to access the file. -+ grdtext: the root node of the grd xml data generated by -+ the rc2grd tool. -+ -+ Return: -+ The root node of the processed GRD tree. -+ ''' -+ raise NotImplementedError() -diff --git a/tools/grit/grit/tool/postprocess_unittest.py b/tools/grit/grit/tool/postprocess_unittest.py -new file mode 100644 -index 0000000000..77fe228bbe ---- /dev/null -+++ b/tools/grit/grit/tool/postprocess_unittest.py -@@ -0,0 +1,64 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit test that checks postprocessing of files. -+ Tests postprocessing by having the postprocessor -+ modify the grd data tree, changing the message name attributes. -+''' -+ -+from __future__ import print_function -+ -+import os -+import re -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+import unittest -+ -+import grit.tool.postprocess_interface -+from grit.tool import rc2grd -+ -+ -+class PostProcessingUnittest(unittest.TestCase): -+ -+ def testPostProcessing(self): -+ rctext = '''STRINGTABLE -+BEGIN -+ DUMMY_STRING_1 "String 1" -+ // Some random description -+ DUMMY_STRING_2 "This text was added during preprocessing" -+END -+ ''' -+ tool = rc2grd.Rc2Grd() -+ class DummyOpts(object): -+ verbose = False -+ extra_verbose = False -+ tool.o = DummyOpts() -+ tool.post_process = 'grit.tool.postprocess_unittest.DummyPostProcessor' -+ result = tool.Process(rctext, '.\resource.rc') -+ -+ self.failUnless( -+ result.children[2].children[2].children[0].attrs['name'] == 'SMART_STRING_1') -+ self.failUnless( -+ result.children[2].children[2].children[1].attrs['name'] == 'SMART_STRING_2') -+ -+class DummyPostProcessor(grit.tool.postprocess_interface.PostProcessor): -+ ''' -+ Post processing replaces all message name attributes containing "DUMMY" to -+ "SMART". -+ ''' -+ def Process(self, rctext, rcpath, grdnode): -+ smarter = re.compile(r'(DUMMY)(.*)') -+ messages = grdnode.children[2].children[2] -+ for node in messages.children: -+ name_attr = node.attrs['name'] -+ m = smarter.search(name_attr) -+ if m: -+ node.attrs['name'] = 'SMART' + m.group(2) -+ return grdnode -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/tool/preprocess_interface.py b/tools/grit/grit/tool/preprocess_interface.py -new file mode 100644 -index 0000000000..67974e704e ---- /dev/null -+++ b/tools/grit/grit/tool/preprocess_interface.py -@@ -0,0 +1,25 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+''' Base class for preprocessing of RC files. -+''' -+ -+from __future__ import print_function -+ -+class PreProcessor(object): -+ ''' Base class for preprocessing of the RC file data before being -+ output through the RC2GRD tool. You should implement this class if -+ you have specific constructs in your RC files that GRIT cannot handle.''' -+ -+ -+ def Process(self, rctext, rcpath): -+ ''' Processes the data in rctext. -+ Args: -+ rctext: string containing the contents of the RC file being processed -+ rcpath: the path used to access the file. -+ -+ Return: -+ The processed text. -+ ''' -+ raise NotImplementedError() -diff --git a/tools/grit/grit/tool/preprocess_unittest.py b/tools/grit/grit/tool/preprocess_unittest.py -new file mode 100644 -index 0000000000..40b95cd6f8 ---- /dev/null -+++ b/tools/grit/grit/tool/preprocess_unittest.py -@@ -0,0 +1,50 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit test that checks preprocessing of files. -+ Tests preprocessing by adding having the preprocessor -+ provide the actual rctext data. -+''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+import unittest -+ -+import grit.tool.preprocess_interface -+from grit.tool import rc2grd -+ -+ -+class PreProcessingUnittest(unittest.TestCase): -+ -+ def testPreProcessing(self): -+ tool = rc2grd.Rc2Grd() -+ class DummyOpts(object): -+ verbose = False -+ extra_verbose = False -+ tool.o = DummyOpts() -+ tool.pre_process = 'grit.tool.preprocess_unittest.DummyPreProcessor' -+ result = tool.Process('', '.\resource.rc') -+ -+ self.failUnless( -+ result.children[2].children[2].children[0].attrs['name'] == 'DUMMY_STRING_1') -+ -+class DummyPreProcessor(grit.tool.preprocess_interface.PreProcessor): -+ def Process(self, rctext, rcpath): -+ rctext = '''STRINGTABLE -+BEGIN -+ DUMMY_STRING_1 "String 1" -+ // Some random description -+ DUMMY_STRING_2 "This text was added during preprocessing" -+END -+ ''' -+ return rctext -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/tools/grit/grit/tool/rc2grd.py b/tools/grit/grit/tool/rc2grd.py -new file mode 100644 -index 0000000000..3195b39000 ---- /dev/null -+++ b/tools/grit/grit/tool/rc2grd.py -@@ -0,0 +1,418 @@ -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''The 'grit rc2grd' tool.''' -+ -+from __future__ import print_function -+ -+import os.path -+import getopt -+import re -+import sys -+ -+import six -+from six import StringIO -+ -+import grit.node.empty -+from grit.node import include -+from grit.node import structure -+from grit.node import message -+ -+from grit.gather import rc -+from grit.gather import tr_html -+ -+from grit.tool import interface -+from grit.tool import postprocess_interface -+from grit.tool import preprocess_interface -+ -+from grit import grd_reader -+from grit import lazy_re -+from grit import tclib -+from grit import util -+ -+ -+# Matches files referenced from an .rc file -+_FILE_REF = lazy_re.compile(r''' -+ ^(?P[A-Z_0-9.]+)[ \t]+ -+ (?P[A-Z_0-9]+)[ \t]+ -+ "(?P.*?([^"]|""))"[ \t]*$''', re.VERBOSE | re.MULTILINE) -+ -+ -+# Matches a dialog section -+_DIALOG = lazy_re.compile( -+ r'^(?P[A-Z0-9_]+)\s+DIALOG(EX)?\s.+?^BEGIN\s*$.+?^END\s*$', -+ re.MULTILINE | re.DOTALL) -+ -+ -+# Matches a menu section -+_MENU = lazy_re.compile(r'^(?P[A-Z0-9_]+)\s+MENU.+?^BEGIN\s*$.+?^END\s*$', -+ re.MULTILINE | re.DOTALL) -+ -+ -+# Matches a versioninfo section -+_VERSIONINFO = lazy_re.compile( -+ r'^(?P[A-Z0-9_]+)\s+VERSIONINFO\s.+?^BEGIN\s*$.+?^END\s*$', -+ re.MULTILINE | re.DOTALL) -+ -+ -+# Matches a stringtable -+_STRING_TABLE = lazy_re.compile( -+ (r'^STRINGTABLE(\s+(PRELOAD|DISCARDABLE|CHARACTERISTICS.+|LANGUAGE.+|' -+ r'VERSION.+))*\s*\nBEGIN\s*$(?P.+?)^END\s*$'), -+ re.MULTILINE | re.DOTALL) -+ -+ -+# Matches each message inside a stringtable, breaking it up into comments, -+# the ID of the message, and the (RC-escaped) message text. -+_MESSAGE = lazy_re.compile(r''' -+ (?P(^\s+//.+?)*) # 0 or more lines of comments preceding the message -+ ^\s* -+ (?P[A-Za-z0-9_]+) # id -+ \s+ -+ "(?P.*?([^"]|""))"([^"]|$) # The message itself -+ ''', re.MULTILINE | re.DOTALL | re.VERBOSE) -+ -+ -+# Matches each line of comment text in a multi-line comment. -+_COMMENT_TEXT = lazy_re.compile(r'^\s*//\s*(?P.+?)$', re.MULTILINE) -+ -+ -+# Matches a string that is empty or all whitespace -+_WHITESPACE_ONLY = lazy_re.compile(r'\A\s*\Z', re.MULTILINE) -+ -+ -+# Finds printf and FormatMessage style format specifiers -+# Uses non-capturing groups except for the outermost group, so the output of -+# re.split() should include both the normal text and what we intend to -+# replace with placeholders. -+# TODO(joi) Check documentation for printf (and Windows variants) and FormatMessage -+_FORMAT_SPECIFIER = lazy_re.compile( -+ r'(%[-# +]?(?:[0-9]*|\*)(?:\.(?:[0-9]+|\*))?(?:h|l|L)?' # printf up to last char -+ r'(?:d|i|o|u|x|X|e|E|f|F|g|G|c|r|s|ls|ws)' # printf last char -+ r'|\$[1-9][0-9]*)') # FormatMessage -+ -+ -+class Rc2Grd(interface.Tool): -+ '''A tool for converting .rc files to .grd files. This tool is only for -+converting the source (nontranslated) .rc file to a .grd file. For importing -+existing translations, use the rc2xtb tool. -+ -+Usage: grit [global options] rc2grd [OPTIONS] RCFILE -+ -+The tool takes a single argument, which is the path to the .rc file to convert. -+It outputs a .grd file with the same name in the same directory as the .rc file. -+The .grd file may have one or more TODO comments for things that have to be -+cleaned up manually. -+ -+OPTIONS may be any of the following: -+ -+ -e ENCODING Specify the ENCODING of the .rc file. Default is 'cp1252'. -+ -+ -h TYPE Specify the TYPE attribute for HTML structures. -+ Default is 'tr_html'. -+ -+ -u ENCODING Specify the ENCODING of HTML files. Default is 'utf-8'. -+ -+ -n MATCH Specify the regular expression to match in comments that will -+ indicate that the resource the comment belongs to is not -+ translateable. Default is 'Not locali(s|z)able'. -+ -+ -r GRDFILE Specify that GRDFILE should be used as a "role model" for -+ any placeholders that otherwise would have had TODO names. -+ This attempts to find an identical message in the GRDFILE -+ and uses that instead of the automatically placeholderized -+ message. -+ -+ --pre CLASS Specify an optional, fully qualified classname, which -+ has to be a subclass of grit.tool.PreProcessor, to -+ run on the text of the RC file before conversion occurs. -+ This can be used to support constructs in the RC files -+ that GRIT cannot handle on its own. -+ -+ --post CLASS Specify an optional, fully qualified classname, which -+ has to be a subclass of grit.tool.PostProcessor, to -+ run on the text of the converted RC file. -+ This can be used to alter the content of the RC file -+ based on the conversion that occured. -+ -+For menus, dialogs and version info, the .grd file will refer to the original -+.rc file. Once conversion is complete, you can strip the original .rc file -+of its string table and all comments as these will be available in the .grd -+file. -+ -+Note that this tool WILL NOT obey C preprocessor rules, so even if something -+is #if 0-ed out it will still be included in the output of this tool -+Therefore, if your .rc file contains sections like this, you should run the -+C preprocessor on the .rc file or manually edit it before using this tool. -+''' -+ -+ def ShortDescription(self): -+ return 'A tool for converting .rc source files to .grd files.' -+ -+ def __init__(self): -+ self.input_encoding = 'cp1252' -+ self.html_type = 'tr_html' -+ self.html_encoding = 'utf-8' -+ self.not_localizable_re = re.compile('Not locali(s|z)able') -+ self.role_model = None -+ self.pre_process = None -+ self.post_process = None -+ -+ def ParseOptions(self, args, help_func=None): -+ '''Given a list of arguments, set this object's options and return -+ all non-option arguments. -+ ''' -+ (own_opts, args) = getopt.getopt(args, 'e:h:u:n:r', -+ ('help', 'pre=', 'post=')) -+ for (key, val) in own_opts: -+ if key == '-e': -+ self.input_encoding = val -+ elif key == '-h': -+ self.html_type = val -+ elif key == '-u': -+ self.html_encoding = val -+ elif key == '-n': -+ self.not_localizable_re = re.compile(val) -+ elif key == '-r': -+ self.role_model = grd_reader.Parse(val) -+ elif key == '--pre': -+ self.pre_process = val -+ elif key == '--post': -+ self.post_process = val -+ elif key == '--help': -+ if help_func is None: -+ self.ShowUsage() -+ else: -+ help_func() -+ sys.exit(0) -+ return args -+ -+ def Run(self, opts, args): -+ args = self.ParseOptions(args) -+ if len(args) != 1: -+ print('This tool takes a single tool-specific argument, the path to the\n' -+ '.rc file to process.') -+ return 2 -+ self.SetOptions(opts) -+ -+ path = args[0] -+ out_path = os.path.join(util.dirname(path), -+ os.path.splitext(os.path.basename(path))[0] + '.grd') -+ -+ rctext = util.ReadFile(path, self.input_encoding) -+ grd_text = six.text_type(self.Process(rctext, path)) -+ with util.WrapOutputStream(open(out_path, 'wb'), 'utf-8') as outfile: -+ outfile.write(grd_text) -+ -+ print('Wrote output file %s.\nPlease check for TODO items in the file.' % -+ (out_path,)) -+ -+ -+ def Process(self, rctext, rc_path): -+ '''Processes 'rctext' and returns a resource tree corresponding to it. -+ -+ Args: -+ rctext: complete text of the rc file -+ rc_path: 'resource\resource.rc' -+ -+ Return: -+ grit.node.base.Node subclass -+ ''' -+ -+ if self.pre_process: -+ preprocess_class = util.NewClassInstance(self.pre_process, -+ preprocess_interface.PreProcessor) -+ if preprocess_class: -+ rctext = preprocess_class.Process(rctext, rc_path) -+ else: -+ self.Out( -+ 'PreProcessing class could not be found. Skipping preprocessing.\n') -+ -+ # Start with a basic skeleton for the .grd file -+ root = grd_reader.Parse(StringIO( -+ ''' -+ -+ -+ -+ -+ -+ -+ -+ -+ '''), util.dirname(rc_path)) -+ includes = root.children[2].children[0] -+ structures = root.children[2].children[1] -+ messages = root.children[2].children[2] -+ assert (isinstance(includes, grit.node.empty.IncludesNode) and -+ isinstance(structures, grit.node.empty.StructuresNode) and -+ isinstance(messages, grit.node.empty.MessagesNode)) -+ -+ self.AddIncludes(rctext, includes) -+ self.AddStructures(rctext, structures, os.path.basename(rc_path)) -+ self.AddMessages(rctext, messages) -+ -+ self.VerboseOut('Validating that all IDs are unique...\n') -+ root.ValidateUniqueIds() -+ self.ExtraVerboseOut('Done validating that all IDs are unique.\n') -+ -+ if self.post_process: -+ postprocess_class = util.NewClassInstance(self.post_process, -+ postprocess_interface.PostProcessor) -+ if postprocess_class: -+ root = postprocess_class.Process(rctext, rc_path, root) -+ else: -+ self.Out( -+ 'PostProcessing class could not be found. Skipping postprocessing.\n') -+ -+ return root -+ -+ -+ def IsHtml(self, res_type, fname): -+ '''Check whether both the type and file extension indicate HTML''' -+ fext = fname.split('.')[-1].lower() -+ return res_type == 'HTML' and fext in ('htm', 'html') -+ -+ -+ def AddIncludes(self, rctext, node): -+ '''Scans 'rctext' for included resources (e.g. BITMAP, ICON) and -+ adds each included resource as an child node of 'node'.''' -+ for m in _FILE_REF.finditer(rctext): -+ id = m.group('id') -+ res_type = m.group('type').upper() -+ fname = rc.Section.UnEscape(m.group('file')) -+ assert fname.find('\n') == -1 -+ if not self.IsHtml(res_type, fname): -+ self.VerboseOut('Processing %s with ID %s (filename: %s)\n' % -+ (res_type, id, fname)) -+ node.AddChild(include.IncludeNode.Construct(node, id, res_type, fname)) -+ -+ -+ def AddStructures(self, rctext, node, rc_filename): -+ '''Scans 'rctext' for structured resources (e.g. menus, dialogs, version -+ information resources and HTML templates) and adds each as a -+ child of 'node'.''' -+ # First add HTML includes -+ for m in _FILE_REF.finditer(rctext): -+ id = m.group('id') -+ res_type = m.group('type').upper() -+ fname = rc.Section.UnEscape(m.group('file')) -+ if self.IsHtml(type, fname): -+ node.AddChild(structure.StructureNode.Construct( -+ node, id, self.html_type, fname, self.html_encoding)) -+ -+ # Then add all RC includes -+ def AddStructure(res_type, id): -+ self.VerboseOut('Processing %s with ID %s\n' % (res_type, id)) -+ node.AddChild(structure.StructureNode.Construct(node, id, res_type, -+ rc_filename, -+ encoding=self.input_encoding)) -+ for m in _MENU.finditer(rctext): -+ AddStructure('menu', m.group('id')) -+ for m in _DIALOG.finditer(rctext): -+ AddStructure('dialog', m.group('id')) -+ for m in _VERSIONINFO.finditer(rctext): -+ AddStructure('version', m.group('id')) -+ -+ -+ def AddMessages(self, rctext, node): -+ '''Scans 'rctext' for all messages in string tables, preprocesses them as -+ much as possible for placeholders (e.g. messages containing $1, $2 or %s, %d -+ type format specifiers get those specifiers replaced with placeholders, and -+ HTML-formatted messages get run through the HTML-placeholderizer). Adds -+ each message as a node child of 'node'.''' -+ for tm in _STRING_TABLE.finditer(rctext): -+ table = tm.group('body') -+ for mm in _MESSAGE.finditer(table): -+ comment_block = mm.group('comment') -+ comment_text = [] -+ for cm in _COMMENT_TEXT.finditer(comment_block): -+ comment_text.append(cm.group('text')) -+ comment_text = ' '.join(comment_text) -+ -+ id = mm.group('id') -+ text = rc.Section.UnEscape(mm.group('text')) -+ -+ self.VerboseOut('Processing message %s (text: "%s")\n' % (id, text)) -+ -+ msg_obj = self.Placeholderize(text) -+ -+ # Messages that contain only placeholders do not need translation. -+ is_translateable = False -+ for item in msg_obj.GetContent(): -+ if isinstance(item, six.string_types): -+ if not _WHITESPACE_ONLY.match(item): -+ is_translateable = True -+ -+ if self.not_localizable_re.search(comment_text): -+ is_translateable = False -+ -+ message_meaning = '' -+ internal_comment = '' -+ -+ # If we have a "role model" (existing GRD file) and this node exists -+ # in the role model, use the description, meaning and translateable -+ # attributes from the role model. -+ if self.role_model: -+ role_node = self.role_model.GetNodeById(id) -+ if role_node: -+ is_translateable = role_node.IsTranslateable() -+ message_meaning = role_node.attrs['meaning'] -+ comment_text = role_node.attrs['desc'] -+ internal_comment = role_node.attrs['internal_comment'] -+ -+ # For nontranslateable messages, we don't want the complexity of -+ # placeholderizing everything. -+ if not is_translateable: -+ msg_obj = tclib.Message(text=text) -+ -+ msg_node = message.MessageNode.Construct(node, msg_obj, id, -+ desc=comment_text, -+ translateable=is_translateable, -+ meaning=message_meaning) -+ msg_node.attrs['internal_comment'] = internal_comment -+ -+ node.AddChild(msg_node) -+ self.ExtraVerboseOut('Done processing message %s\n' % id) -+ -+ -+ def Placeholderize(self, text): -+ '''Creates a tclib.Message object from 'text', attempting to recognize -+ a few different formats of text that can be automatically placeholderized -+ (HTML code, printf-style format strings, and FormatMessage-style format -+ strings). -+ ''' -+ -+ try: -+ # First try HTML placeholderizing. -+ # TODO(joi) Allow use of non-TotalRecall flavors of HTML placeholderizing -+ msg = tr_html.HtmlToMessage(text, True) -+ for item in msg.GetContent(): -+ if not isinstance(item, six.string_types): -+ return msg # Contained at least one placeholder, so we're done -+ -+ # HTML placeholderization didn't do anything, so try to find printf or -+ # FormatMessage format specifiers and change them into placeholders. -+ msg = tclib.Message() -+ parts = _FORMAT_SPECIFIER.split(text) -+ todo_counter = 1 # We make placeholder IDs 'TODO_0001' etc. -+ for part in parts: -+ if _FORMAT_SPECIFIER.match(part): -+ msg.AppendPlaceholder(tclib.Placeholder( -+ 'TODO_%04d' % todo_counter, part, 'TODO')) -+ todo_counter += 1 -+ elif part != '': -+ msg.AppendText(part) -+ -+ if self.role_model and len(parts) > 1: # there are TODO placeholders -+ role_model_msg = self.role_model.UberClique().BestCliqueByOriginalText( -+ msg.GetRealContent(), '') -+ if role_model_msg: -+ # replace wholesale to get placeholder names and examples -+ msg = role_model_msg -+ -+ return msg -+ except: -+ print('Exception processing message with text "%s"' % text) -+ raise -diff --git a/tools/grit/grit/tool/rc2grd_unittest.py b/tools/grit/grit/tool/rc2grd_unittest.py -new file mode 100644 -index 0000000000..6d53794c27 ---- /dev/null -+++ b/tools/grit/grit/tool/rc2grd_unittest.py -@@ -0,0 +1,163 @@ -+#!/usr/bin/env python -+# Copyright (c) 2012 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+'''Unit tests for grit.tool.rc2grd''' -+ -+from __future__ import print_function -+ -+import os -+import sys -+if __name__ == '__main__': -+ sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -+ -+import re -+import unittest -+ -+from six import StringIO -+ -+from grit import grd_reader -+from grit import util -+from grit.node import base -+from grit.tool import rc2grd -+ -+ -+class Rc2GrdUnittest(unittest.TestCase): -+ def testPlaceholderize(self): -+ tool = rc2grd.Rc2Grd() -+ original = "Hello %s, how are you? I'm $1 years old!" -+ msg = tool.Placeholderize(original) -+ self.failUnless(msg.GetPresentableContent() == "Hello TODO_0001, how are you? I'm TODO_0002 years old!") -+ self.failUnless(msg.GetRealContent() == original) -+ -+ def testHtmlPlaceholderize(self): -+ tool = rc2grd.Rc2Grd() -+ original = "Hello [USERNAME], how are you? I'm [AGE] years old!" -+ msg = tool.Placeholderize(original) -+ self.failUnless(msg.GetPresentableContent() == -+ "Hello BEGIN_BOLDX_USERNAME_XEND_BOLD, how are you? I'm X_AGE_X years old!") -+ self.failUnless(msg.GetRealContent() == original) -+ -+ def testMenuWithoutWhitespaceRegression(self): -+ # There was a problem in the original regular expression for parsing out -+ # menu sections, that would parse the following block of text as a single -+ # menu instead of two. -+ two_menus = ''' -+// Hyper context menus -+IDR_HYPERMENU_FOLDER MENU -+BEGIN -+ POPUP "HyperFolder" -+ BEGIN -+ MENUITEM "Open Containing Folder", IDM_OPENFOLDER -+ END -+END -+ -+IDR_HYPERMENU_FILE MENU -+BEGIN -+ POPUP "HyperFile" -+ BEGIN -+ MENUITEM "Open Folder", IDM_OPENFOLDER -+ END -+END -+ -+''' -+ self.failUnless(len(rc2grd._MENU.findall(two_menus)) == 2) -+ -+ def testRegressionScriptWithTranslateable(self): -+ tool = rc2grd.Rc2Grd() -+ -+ # test rig -+ class DummyNode(base.Node): -+ def AddChild(self, item): -+ self.node = item -+ verbose = False -+ extra_verbose = False -+ tool.not_localizable_re = re.compile('') -+ tool.o = DummyNode() -+ -+ rc_text = '''STRINGTABLE\nBEGIN\nID_BINGO ""\nEND\n''' -+ tool.AddMessages(rc_text, tool.o) -+ self.failUnless(tool.o.node.GetCdata().find('Set As Homepage') != -1) -+ -+ # TODO(joi) Improve the HTML parser to support translateables inside -+ #