diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index e417cbf..f9cc3d7 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -182,7 +182,6 @@ // Blending refers to modifications to the backdrop. bool use_shaders_for_blending = false; - const Program* program = nullptr; bool use_aa = false; @@ -603,8 +602,7 @@ void GLRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad) { SetBlendEnabled(quad->ShouldDrawWithBlending()); - const Program* program = GetProgram(ProgramKey::DebugBorder()); - SetUseProgram(program); + SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB()); // Use the full quad_rect for debug quads to not move the edges based on // partial swaps. @@ -1307,16 +1305,14 @@ SamplerTypeFromTextureTarget(params->mask_resource_lock->target()); } - params->program = GetProgram(ProgramKey::RenderPass( - tex_coord_precision, sampler_type, shader_blend_mode, - params->use_aa ? USE_AA : NO_AA, mask_mode, mask_for_background, - params->use_color_matrix)); - SetUseProgram(params->program); + SetUseProgram(ProgramKey::RenderPass( + tex_coord_precision, sampler_type, shader_blend_mode, + params->use_aa ? USE_AA : NO_AA, mask_mode, + mask_for_background, params->use_color_matrix), + current_frame()->device_color_space); } void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) { - const Program* program = params->program; - gfx::RectF tex_rect(params->src_offset.x(), params->src_offset.y(), params->dst_rect.width(), params->dst_rect.height()); gfx::Size texture_size; @@ -1328,26 +1324,29 @@ } tex_rect.Scale(1.0f / texture_size.width(), 1.0f / texture_size.height()); - DCHECK(program->vertex_tex_transform_location() != -1 || IsContextLost()); + DCHECK(current_program_->vertex_tex_transform_location() != -1 || + IsContextLost()); if (params->source_needs_flip) { // Flip the content vertically in the shader, as the RenderPass input // texture is already oriented the same way as the framebuffer, but the // projection transform does a flip. - gl_->Uniform4f(program->vertex_tex_transform_location(), tex_rect.x(), - 1.0f - tex_rect.y(), tex_rect.width(), -tex_rect.height()); + gl_->Uniform4f(current_program_->vertex_tex_transform_location(), + tex_rect.x(), 1.0f - tex_rect.y(), tex_rect.width(), + -tex_rect.height()); } else { // Tile textures are oriented opposite the framebuffer, so can use // the projection transform to do the flip. - gl_->Uniform4f(program->vertex_tex_transform_location(), tex_rect.x(), - tex_rect.y(), tex_rect.width(), tex_rect.height()); + gl_->Uniform4f(current_program_->vertex_tex_transform_location(), + tex_rect.x(), tex_rect.y(), tex_rect.width(), + tex_rect.height()); } GLint last_texture_unit = 0; - if (program->mask_sampler_location() != -1) { + if (current_program_->mask_sampler_location() != -1) { DCHECK(params->mask_resource_lock); - DCHECK_NE(program->mask_tex_coord_scale_location(), 1); - DCHECK_NE(program->mask_tex_coord_offset_location(), 1); - gl_->Uniform1i(program->mask_sampler_location(), 1); + DCHECK_NE(current_program_->mask_tex_coord_scale_location(), 1); + DCHECK_NE(current_program_->mask_tex_coord_offset_location(), 1); + gl_->Uniform1i(current_program_->mask_sampler_location(), 1); gfx::RectF mask_uv_rect = params->quad->MaskUVRect(); if (SamplerTypeFromTextureTarget(params->mask_resource_lock->target()) != @@ -1360,16 +1359,16 @@ // framebuffer and the RenderPass contents texture, so we flip the tex // coords from the RenderPass texture to find the mask texture coords. gl_->Uniform2f( - program->mask_tex_coord_offset_location(), mask_uv_rect.x(), + current_program_->mask_tex_coord_offset_location(), mask_uv_rect.x(), mask_uv_rect.height() / tex_rect.height() + mask_uv_rect.y()); - gl_->Uniform2f(program->mask_tex_coord_scale_location(), + gl_->Uniform2f(current_program_->mask_tex_coord_scale_location(), mask_uv_rect.width() / tex_rect.width(), -mask_uv_rect.height() / tex_rect.height()); } else { // Tile textures are oriented the same way as mask textures. - gl_->Uniform2f(program->mask_tex_coord_offset_location(), + gl_->Uniform2f(current_program_->mask_tex_coord_offset_location(), mask_uv_rect.x(), mask_uv_rect.y()); - gl_->Uniform2f(program->mask_tex_coord_scale_location(), + gl_->Uniform2f(current_program_->mask_tex_coord_scale_location(), mask_uv_rect.width() / tex_rect.width(), mask_uv_rect.height() / tex_rect.height()); } @@ -1377,34 +1376,35 @@ last_texture_unit = 1; } - if (program->edge_location() != -1) - gl_->Uniform3fv(program->edge_location(), 8, params->edge); + if (current_program_->edge_location() != -1) + gl_->Uniform3fv(current_program_->edge_location(), 8, params->edge); - if (program->color_matrix_location() != -1) { + if (current_program_->color_matrix_location() != -1) { float matrix[16]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) matrix[i * 4 + j] = SkScalarToFloat(params->color_matrix[j * 5 + i]); } - gl_->UniformMatrix4fv(program->color_matrix_location(), 1, false, matrix); + gl_->UniformMatrix4fv(current_program_->color_matrix_location(), 1, false, + matrix); } static const float kScale = 1.0f / 255.0f; - if (program->color_offset_location() != -1) { + if (current_program_->color_offset_location() != -1) { float offset[4]; for (int i = 0; i < 4; ++i) offset[i] = SkScalarToFloat(params->color_matrix[i * 5 + 4]) * kScale; - gl_->Uniform4fv(program->color_offset_location(), 1, offset); + gl_->Uniform4fv(current_program_->color_offset_location(), 1, offset); } - if (program->backdrop_location() != -1) { + if (current_program_->backdrop_location() != -1) { DCHECK(params->background_texture || params->background_image_id); - DCHECK_NE(program->backdrop_location(), 0); - DCHECK_NE(program->backdrop_rect_location(), 0); + DCHECK_NE(current_program_->backdrop_location(), 0); + DCHECK_NE(current_program_->backdrop_rect_location(), 0); - gl_->Uniform1i(program->backdrop_location(), ++last_texture_unit); + gl_->Uniform1i(current_program_->backdrop_location(), ++last_texture_unit); - gl_->Uniform4f(program->backdrop_rect_location(), + gl_->Uniform4f(current_program_->backdrop_rect_location(), params->background_rect.x(), params->background_rect.y(), params->background_rect.width(), params->background_rect.height()); @@ -1414,7 +1414,7 @@ gl_->BindTexture(GL_TEXTURE_2D, params->background_image_id); gl_->ActiveTexture(GL_TEXTURE0); if (params->mask_for_background) - gl_->Uniform1i(program->original_backdrop_location(), + gl_->Uniform1i(current_program_->original_backdrop_location(), ++last_texture_unit); } if (params->background_texture) { @@ -1748,13 +1748,15 @@ SetupQuadForClippingAndAntialiasing(device_transform, quad, aa_quad, clip_region, &local_quad, edge); - const Program* program = - GetProgram(ProgramKey::SolidColor(use_aa ? USE_AA : NO_AA)); - SetUseProgram(program); + // TODO(ccameron): Solid color draw quads need to specify their implied + // color space. Assume SRGB (which is wrong) for now. + gfx::ColorSpace quad_color_space = gfx::ColorSpace::CreateSRGB(); + SetUseProgram(ProgramKey::SolidColor(use_aa ? USE_AA : NO_AA), + quad_color_space); SetShaderColor(color, opacity); if (use_aa) { - gl_->Uniform3fv(program->edge_location(), 8, edge); + gl_->Uniform3fv(current_program_->edge_location(), 8, edge); } // Enable blending when the quad properties require it or if we decided @@ -1898,18 +1900,17 @@ fragment_tex_scale_y /= texture_size.height(); } - const Program* program = GetProgram(ProgramKey::Tile( - tex_coord_precision, sampler, USE_AA, - quad->swizzle_contents ? DO_SWIZZLE : NO_SWIZZLE, false)); + SetUseProgram( + ProgramKey::Tile(tex_coord_precision, sampler, USE_AA, + quad->swizzle_contents ? DO_SWIZZLE : NO_SWIZZLE, false), + quad_resource_lock.color_space()); - SetUseProgram(program); + gl_->Uniform3fv(current_program_->edge_location(), 8, edge); - gl_->Uniform3fv(program->edge_location(), 8, edge); - - gl_->Uniform4f(program->vertex_tex_transform_location(), + gl_->Uniform4f(current_program_->vertex_tex_transform_location(), vertex_tex_translate_x, vertex_tex_translate_y, vertex_tex_scale_x, vertex_tex_scale_y); - gl_->Uniform4f(program->fragment_tex_transform_location(), + gl_->Uniform4f(current_program_->fragment_tex_transform_location(), fragment_tex_translate_x, fragment_tex_translate_y, fragment_tex_scale_x, fragment_tex_scale_y); @@ -1975,14 +1976,13 @@ TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size); - const Program* program = GetProgram( + SetUseProgram( ProgramKey::Tile(tex_coord_precision, sampler, NO_AA, quad->swizzle_contents ? DO_SWIZZLE : NO_SWIZZLE, - !quad->ShouldDrawWithBlending())); + !quad->ShouldDrawWithBlending()), + quad_resource_lock.color_space()); - SetUseProgram(program); - - gl_->Uniform4f(program->vertex_tex_transform_location(), + gl_->Uniform4f(current_program_->vertex_tex_transform_location(), vertex_tex_translate_x, vertex_tex_translate_y, vertex_tex_scale_x, vertex_tex_scale_y); @@ -2021,7 +2021,7 @@ tile_quad.p1().y(), tile_quad.p2().x(), tile_quad.p2().y(), tile_quad.p3().x(), tile_quad.p3().y(), }; - gl_->Uniform2fv(program->quad_location(), 4, gl_quad); + gl_->Uniform2fv(current_program_->quad_location(), 4, gl_quad); SetShaderMatrix(current_frame()->projection_matrix * quad->shared_quad_state->quad_to_target_transform); @@ -2031,25 +2031,12 @@ // TODO(ccameron): This has been replicated in ui/gfx/color_transform.cc. Delete // one of the instances. -void ComputeYUVToRGBMatrices(YUVVideoDrawQuad::ColorSpace color_space, +void ComputeYUVToRGBMatrices(const gfx::ColorSpace& src_color_space, + const gfx::ColorSpace& dst_color_space, uint32_t bits_per_channel, float resource_multiplier, float resource_offset, - ColorConversionMode color_conversion_mode, float* yuv_to_rgb_matrix) { - gfx::ColorSpace gfx_color_space; - switch (color_space) { - case YUVVideoDrawQuad::REC_601: - gfx_color_space = gfx::ColorSpace::CreateREC601(); - break; - case YUVVideoDrawQuad::REC_709: - gfx_color_space = gfx::ColorSpace::CreateREC709(); - break; - case YUVVideoDrawQuad::JPEG: - gfx_color_space = gfx::ColorSpace::CreateJpeg(); - break; - } - // Compute the matrix |full_transform| which converts input YUV values to RGB // values. SkMatrix44 full_transform; @@ -2062,7 +2049,7 @@ // If we're using a LUT for conversion, we only need the resource adjust, // so just return this matrix. - if (color_conversion_mode == COLOR_CONVERSION_MODE_LUT) { + if (dst_color_space.IsValid()) { full_transform.asColMajorf(yuv_to_rgb_matrix); return; } @@ -2070,14 +2057,14 @@ // Then apply the range adjust. { SkMatrix44 range_adjust; - gfx_color_space.GetRangeAdjustMatrix(&range_adjust); + src_color_space.GetRangeAdjustMatrix(&range_adjust); full_transform.postConcat(range_adjust); } // Then apply the YUV to RGB full_transform. { SkMatrix44 rgb_to_yuv; - gfx_color_space.GetTransferMatrix(&rgb_to_yuv); + src_color_space.GetTransferMatrix(&rgb_to_yuv); SkMatrix44 yuv_to_rgb; rgb_to_yuv.invert(&yuv_to_rgb); full_transform.postConcat(yuv_to_rgb); @@ -2100,10 +2087,28 @@ quad->v_plane_resource_id() == quad->u_plane_resource_id() ? UV_TEXTURE_MODE_UV : UV_TEXTURE_MODE_U_V; - ColorConversionMode color_conversion_mode = - base::FeatureList::IsEnabled(media::kVideoColorManagement) - ? COLOR_CONVERSION_MODE_LUT - : COLOR_CONVERSION_MODE_NONE; + + // TODO(ccameron): There are currently three sources of the color space: the + // resource, quad->color_space, and quad->video_color_space. Remove two of + // them. + gfx::ColorSpace src_color_space = quad->video_color_space; + gfx::ColorSpace dst_color_space = current_frame()->device_color_space; + if (!base::FeatureList::IsEnabled(media::kVideoColorManagement)) { + if (!settings_->enable_color_correct_rendering) + dst_color_space = gfx::ColorSpace(); + switch (quad->color_space) { + case YUVVideoDrawQuad::REC_601: + src_color_space = gfx::ColorSpace::CreateREC601(); + break; + case YUVVideoDrawQuad::REC_709: + src_color_space = gfx::ColorSpace::CreateREC709(); + break; + case YUVVideoDrawQuad::JPEG: + src_color_space = gfx::ColorSpace::CreateJpeg(); + break; + } + } + ResourceProvider::ScopedSamplerGL y_plane_lock( resource_provider_, quad->y_plane_resource_id(), GL_TEXTURE1, GL_LINEAR); ResourceProvider::ScopedSamplerGL u_plane_lock( @@ -2129,10 +2134,9 @@ // All planes must have the same sampler type. SamplerType sampler = SamplerTypeFromTextureTarget(y_plane_lock.target()); - const Program* program = GetProgram( - ProgramKey::YUVVideo(tex_coord_precision, sampler, alpha_texture_mode, - uv_texture_mode, color_conversion_mode)); - SetUseProgram(program); + SetUseProgram(ProgramKey::YUVVideo(tex_coord_precision, sampler, + alpha_texture_mode, uv_texture_mode), + src_color_space, dst_color_space); gfx::SizeF ya_tex_scale(1.0f, 1.0f); gfx::SizeF uv_tex_scale(1.0f, 1.0f); @@ -2163,14 +2167,14 @@ float uv_vertex_tex_scale_y = quad->uv_tex_coord_rect.height() * uv_tex_scale.height(); - gl_->Uniform2f(program->ya_tex_scale_location(), ya_vertex_tex_scale_x, - ya_vertex_tex_scale_y); - gl_->Uniform2f(program->ya_tex_offset_location(), ya_vertex_tex_translate_x, - ya_vertex_tex_translate_y); - gl_->Uniform2f(program->uv_tex_scale_location(), uv_vertex_tex_scale_x, - uv_vertex_tex_scale_y); - gl_->Uniform2f(program->uv_tex_offset_location(), uv_vertex_tex_translate_x, - uv_vertex_tex_translate_y); + gl_->Uniform2f(current_program_->ya_tex_scale_location(), + ya_vertex_tex_scale_x, ya_vertex_tex_scale_y); + gl_->Uniform2f(current_program_->ya_tex_offset_location(), + ya_vertex_tex_translate_x, ya_vertex_tex_translate_y); + gl_->Uniform2f(current_program_->uv_tex_scale_location(), + uv_vertex_tex_scale_x, uv_vertex_tex_scale_y); + gl_->Uniform2f(current_program_->uv_tex_offset_location(), + uv_vertex_tex_translate_x, uv_vertex_tex_translate_y); gfx::RectF ya_clamp_rect(ya_vertex_tex_translate_x, ya_vertex_tex_translate_y, ya_vertex_tex_scale_x, ya_vertex_tex_scale_y); @@ -2180,38 +2184,29 @@ uv_vertex_tex_scale_x, uv_vertex_tex_scale_y); uv_clamp_rect.Inset(0.5f * uv_tex_scale.width(), 0.5f * uv_tex_scale.height()); - gl_->Uniform4f(program->ya_clamp_rect_location(), ya_clamp_rect.x(), + gl_->Uniform4f(current_program_->ya_clamp_rect_location(), ya_clamp_rect.x(), ya_clamp_rect.y(), ya_clamp_rect.right(), ya_clamp_rect.bottom()); - gl_->Uniform4f(program->uv_clamp_rect_location(), uv_clamp_rect.x(), + gl_->Uniform4f(current_program_->uv_clamp_rect_location(), uv_clamp_rect.x(), uv_clamp_rect.y(), uv_clamp_rect.right(), uv_clamp_rect.bottom()); - gl_->Uniform1i(program->y_texture_location(), 1); + gl_->Uniform1i(current_program_->y_texture_location(), 1); if (uv_texture_mode == UV_TEXTURE_MODE_UV) { - gl_->Uniform1i(program->uv_texture_location(), 2); + gl_->Uniform1i(current_program_->uv_texture_location(), 2); } else { - gl_->Uniform1i(program->u_texture_location(), 2); - gl_->Uniform1i(program->v_texture_location(), 3); + gl_->Uniform1i(current_program_->u_texture_location(), 2); + gl_->Uniform1i(current_program_->v_texture_location(), 3); } if (alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE) - gl_->Uniform1i(program->a_texture_location(), 4); + gl_->Uniform1i(current_program_->a_texture_location(), 4); - if (color_conversion_mode == COLOR_CONVERSION_MODE_LUT) { - ColorLUTCache::LUT lut = color_lut_cache_.GetLUT( - quad->video_color_space, current_frame()->device_color_space); - gl_->ActiveTexture(GL_TEXTURE5); - gl_->BindTexture(GL_TEXTURE_2D, lut.texture); - gl_->Uniform1i(program->lut_texture_location(), 5); - gl_->Uniform1f(program->lut_size_location(), lut.size); - gl_->ActiveTexture(GL_TEXTURE0); - } float yuv_to_rgb_matrix[16] = {0}; - ComputeYUVToRGBMatrices(quad->color_space, quad->bits_per_channel, - quad->resource_multiplier, quad->resource_offset, - color_conversion_mode, yuv_to_rgb_matrix); - gl_->UniformMatrix4fv(program->yuv_and_resource_matrix_location(), 1, 0, - yuv_to_rgb_matrix); + ComputeYUVToRGBMatrices(src_color_space, dst_color_space, + quad->bits_per_channel, quad->resource_multiplier, + quad->resource_offset, yuv_to_rgb_matrix); + gl_->UniformMatrix4fv(current_program_->yuv_and_resource_matrix_location(), 1, + 0, yuv_to_rgb_matrix); // The transform and vertex data are used to figure out the extents that the // un-antialiased quad should have and which vertex this is and the float @@ -2248,20 +2243,19 @@ gl_, &highp_threshold_cache_, highp_threshold_min_, quad->shared_quad_state->visible_quad_layer_rect.bottom_right()); - const Program* program = - GetProgram(ProgramKey::VideoStream(tex_coord_precision)); - SetUseProgram(program); - ResourceProvider::ScopedReadLockGL lock(resource_provider_, quad->resource_id()); + SetUseProgram(ProgramKey::VideoStream(tex_coord_precision), + lock.color_space()); + DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id()); static float gl_matrix[16]; ToGLMatrix(&gl_matrix[0], quad->matrix); gl_->UniformMatrix4fvStreamTextureMatrixCHROMIUM( - program->tex_matrix_location(), false, gl_matrix); + current_program_->tex_matrix_location(), false, gl_matrix); SetShaderOpacity(quad); if (!clip_region) { @@ -2282,7 +2276,7 @@ void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) { // Check to see if we have anything to draw. - if (!draw_cache_.program) + if (draw_cache_.is_empty) return; PrepareGeometry(flush_binding); @@ -2290,14 +2284,15 @@ // Set the correct blending mode. SetBlendEnabled(draw_cache_.needs_blending); - // Bind the program to the GL state. - SetUseProgram(draw_cache_.program); - // Assume the current active textures is 0. ResourceProvider::ScopedSamplerGL locked_quad( resource_provider_, draw_cache_.resource_id, draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR); + + // Bind the program to the GL state. + SetUseProgram(draw_cache_.program_key, locked_quad.color_space()); + DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); gl_->BindTexture(locked_quad.target(), locked_quad.texture_id()); @@ -2308,22 +2303,22 @@ // Upload the tranforms for both points and uvs. gl_->UniformMatrix4fv( - draw_cache_.program->matrix_location(), + current_program_->matrix_location(), static_cast<int>(draw_cache_.matrix_data.size()), false, reinterpret_cast<float*>(&draw_cache_.matrix_data.front())); - gl_->Uniform4fv(draw_cache_.program->vertex_tex_transform_location(), + gl_->Uniform4fv(current_program_->vertex_tex_transform_location(), static_cast<int>(draw_cache_.uv_xform_data.size()), reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front())); if (draw_cache_.background_color != SK_ColorTRANSPARENT) { Float4 background_color = PremultipliedColor(draw_cache_.background_color, 1.f); - gl_->Uniform4fv(draw_cache_.program->background_color_location(), 1, + gl_->Uniform4fv(current_program_->background_color_location(), 1, background_color.data); } gl_->Uniform1fv( - draw_cache_.program->vertex_opacity_location(), + current_program_->vertex_opacity_location(), static_cast<int>(draw_cache_.vertex_opacity_data.size()), static_cast<float*>(&draw_cache_.vertex_opacity_data.front())); @@ -2339,11 +2334,10 @@ // When we draw the composited borders we have one flush per quad. DCHECK_EQ(1u, draw_cache_.matrix_data.size()); SetBlendEnabled(false); - const Program* program = GetProgram(ProgramKey::DebugBorder()); - SetUseProgram(program); + SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB()); gl_->UniformMatrix4fv( - program->matrix_location(), 1, false, + current_program_->matrix_location(), 1, false, reinterpret_cast<float*>(&draw_cache_.matrix_data.front())); // Pick a random color based on the scale on X and Y. @@ -2359,7 +2353,7 @@ } // Clear the cache. - draw_cache_.program = nullptr; + draw_cache_.is_empty = true; draw_cache_.resource_id = -1; draw_cache_.uv_xform_data.resize(0); draw_cache_.vertex_opacity_data.resize(0); @@ -2391,21 +2385,22 @@ quad->resource_id()); const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target()); - const Program* program = GetProgram(ProgramKey::Texture( + ProgramKey program_key = ProgramKey::Texture( tex_coord_precision, sampler, quad->premultiplied_alpha ? PREMULTIPLIED_ALPHA : NON_PREMULTIPLIED_ALPHA, - quad->background_color != SK_ColorTRANSPARENT)); + quad->background_color != SK_ColorTRANSPARENT); int resource_id = quad->resource_id(); size_t max_quads = StaticGeometryBinding::NUM_QUADS; - if (draw_cache_.program != program || + if (draw_cache_.is_empty || draw_cache_.program_key != program_key || draw_cache_.resource_id != resource_id || draw_cache_.needs_blending != quad->ShouldDrawWithBlending() || draw_cache_.nearest_neighbor != quad->nearest_neighbor || draw_cache_.background_color != quad->background_color || draw_cache_.matrix_data.size() >= max_quads) { FlushTextureQuadCache(SHARED_BINDING); - draw_cache_.program = program; + draw_cache_.is_empty = false; + draw_cache_.program_key = program_key; draw_cache_.resource_id = resource_id; draw_cache_.needs_blending = quad->ShouldDrawWithBlending(); draw_cache_.nearest_neighbor = quad->nearest_neighbor; @@ -2537,7 +2532,7 @@ } void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad) { - if (!program_shadow_ || program_shadow_->quad_location() == -1) + if (!current_program_ || current_program_->quad_location() == -1) return; float gl_quad[8]; gl_quad[0] = quad.p1().x(); @@ -2548,30 +2543,30 @@ gl_quad[5] = quad.p3().y(); gl_quad[6] = quad.p4().x(); gl_quad[7] = quad.p4().y(); - gl_->Uniform2fv(program_shadow_->quad_location(), 4, gl_quad); + gl_->Uniform2fv(current_program_->quad_location(), 4, gl_quad); } void GLRenderer::SetShaderOpacity(const DrawQuad* quad) { - if (!program_shadow_ || program_shadow_->alpha_location() == -1) + if (!current_program_ || current_program_->alpha_location() == -1) return; - gl_->Uniform1f(program_shadow_->alpha_location(), + gl_->Uniform1f(current_program_->alpha_location(), quad->shared_quad_state->opacity); } void GLRenderer::SetShaderMatrix(const gfx::Transform& transform) { - if (!program_shadow_ || program_shadow_->matrix_location() == -1) + if (!current_program_ || current_program_->matrix_location() == -1) return; float gl_matrix[16]; ToGLMatrix(gl_matrix, transform); - gl_->UniformMatrix4fv(program_shadow_->matrix_location(), 1, false, + gl_->UniformMatrix4fv(current_program_->matrix_location(), 1, false, gl_matrix); } void GLRenderer::SetShaderColor(SkColor color, float opacity) { - if (!program_shadow_ || program_shadow_->color_location() == -1) + if (!current_program_ || current_program_->color_location() == -1) return; Float4 float_color = PremultipliedColor(color, opacity); - gl_->Uniform4fv(program_shadow_->color_location(), 1, float_color.data); + gl_->Uniform4fv(current_program_->color_location(), 1, float_color.data); } void GLRenderer::SetStencilEnabled(bool enabled) { @@ -2596,28 +2591,6 @@ blend_shadow_ = enabled; } -void GLRenderer::SetUseProgram(const Program* program) { - DCHECK(program); - DCHECK(program->initialized() || IsContextLost()); - if (program == program_shadow_) - return; - gl_->UseProgram(program->program()); - - // Set uniforms that are common to all programs. - if (program->sampler_location() != -1) - gl_->Uniform1i(program->sampler_location(), 0); - if (program->viewport_location() != -1) { - float viewport[4] = { - static_cast<float>(current_window_space_viewport_.x()), - static_cast<float>(current_window_space_viewport_.y()), - static_cast<float>(current_window_space_viewport_.width()), - static_cast<float>(current_window_space_viewport_.height()), - }; - gl_->Uniform4fv(program->viewport_location(), 1, viewport); - } - program_shadow_ = program; -} - void GLRenderer::DrawQuadGeometryClippedByQuadF( const gfx::Transform& draw_transform, const gfx::RectF& quad_rect, @@ -3043,13 +3016,58 @@ bound_geometry_ = binding; } -const Program* GLRenderer::GetProgram(const ProgramKey& desc) { - std::unique_ptr<Program>& program = program_cache_[desc]; +void GLRenderer::SetUseProgram(const ProgramKey& program_key, + const gfx::ColorSpace& src_color_space) { + gfx::ColorSpace dst_color_space; + if (settings_->enable_color_correct_rendering) + dst_color_space = current_frame()->device_color_space; + SetUseProgram(program_key, src_color_space, dst_color_space); +} + +void GLRenderer::SetUseProgram(const ProgramKey& program_key_no_color, + const gfx::ColorSpace& src_color_space, + const gfx::ColorSpace& dst_color_space) { + ProgramKey program_key = program_key_no_color; + if (src_color_space.IsValid() && dst_color_space.IsValid()) + program_key.SetColorConversionMode(COLOR_CONVERSION_MODE_LUT); + + // Create and set the program if needed. + std::unique_ptr<Program>& program = program_cache_[program_key]; if (!program) { program.reset(new Program); - program->Initialize(output_surface_->context_provider(), desc); + program->Initialize(output_surface_->context_provider(), program_key); } - return program.get(); + DCHECK(program); + if (current_program_ != program.get()) { + current_program_ = program.get(); + gl_->UseProgram(current_program_->program()); + } + if (!current_program_->initialized()) { + DCHECK(IsContextLost()); + return; + } + + // Set uniforms that are common to all programs. + if (current_program_->sampler_location() != -1) + gl_->Uniform1i(current_program_->sampler_location(), 0); + if (current_program_->viewport_location() != -1) { + float viewport[4] = { + static_cast<float>(current_window_space_viewport_.x()), + static_cast<float>(current_window_space_viewport_.y()), + static_cast<float>(current_window_space_viewport_.width()), + static_cast<float>(current_window_space_viewport_.height()), + }; + gl_->Uniform4fv(current_program_->viewport_location(), 1, viewport); + } + if (current_program_->lut_texture_location() != -1) { + ColorLUTCache::LUT lut = + color_lut_cache_.GetLUT(src_color_space, dst_color_space); + gl_->ActiveTexture(GL_TEXTURE5); + gl_->BindTexture(GL_TEXTURE_2D, lut.texture); + gl_->Uniform1i(current_program_->lut_texture_location(), 5); + gl_->Uniform1f(current_program_->lut_size_location(), lut.size); + gl_->ActiveTexture(GL_TEXTURE0); + } } const Program* GLRenderer::GetProgramIfInitialized( @@ -3081,7 +3099,7 @@ scissor_rect_ = gfx::Rect(); stencil_shadow_ = false; blend_shadow_ = true; - program_shadow_ = nullptr; + current_program_ = nullptr; RestoreGLState(); } @@ -3097,8 +3115,8 @@ gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); gl_->ActiveTexture(GL_TEXTURE0); - if (program_shadow_) - gl_->UseProgram(program_shadow_->program()); + if (current_program_) + gl_->UseProgram(current_program_->program()); if (stencil_shadow_) gl_->Enable(GL_STENCIL_TEST); @@ -3422,8 +3440,7 @@ PrepareGeometry(SHARED_BINDING); - const Program* program = GetProgram(ProgramKey::DebugBorder()); - SetUseProgram(program); + SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB()); gfx::Transform render_matrix; render_matrix.Translate(0.5 * output_rect.width() + output_rect.x(),
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h index 529d257..ea73b6f8 100644 --- a/cc/output/gl_renderer.h +++ b/cc/output/gl_renderer.h
@@ -215,7 +215,18 @@ void DrawQuadGeometry(const gfx::Transform& projection_matrix, const gfx::Transform& draw_transform, const gfx::RectF& quad_rect); - void SetUseProgram(const Program* program); + + // If |dst_color_space| is invalid, then no color conversion (apart from + // YUV to RGB conversion) is performed. This explicit argument is available + // so that video color conversion can be enabled separately from general color + // conversion. + // TODO(ccameron): Remove the version with an explicit |dst_color_space|, + // since that will always be the device color space. + void SetUseProgram(const ProgramKey& program_key, + const gfx::ColorSpace& src_color_space, + const gfx::ColorSpace& dst_color_space); + void SetUseProgram(const ProgramKey& program_key, + const gfx::ColorSpace& src_color_space); bool MakeContextCurrent(); @@ -280,10 +291,6 @@ std::unique_ptr<DynamicGeometryBinding> clipped_geometry_; gfx::QuadF shared_geometry_quad_; - // If the requested program has not yet been initialized, this will initialize - // the program before returning it. - const Program* GetProgram(const ProgramKey& key); - // This will return nullptr if the requested program has not yet been // initialized. const Program* GetProgramIfInitialized(const ProgramKey& key) const; @@ -302,7 +309,7 @@ bool is_scissor_enabled_ = false; bool stencil_shadow_ = false; bool blend_shadow_ = false; - const Program* program_shadow_ = nullptr; + const Program* current_program_ = nullptr; TexturedQuadDrawCache draw_cache_; int highp_threshold_min_ = 0; int highp_threshold_cache_ = 0;
diff --git a/cc/output/gl_renderer_draw_cache.h b/cc/output/gl_renderer_draw_cache.h index 493ae4ca2..a2e43f2 100644 --- a/cc/output/gl_renderer_draw_cache.h +++ b/cc/output/gl_renderer_draw_cache.h
@@ -8,12 +8,11 @@ #include <vector> #include "base/macros.h" +#include "cc/output/program_binding.h" #include "third_party/skia/include/core/SkColor.h" namespace cc { -class Program; - // Collects 4 floats at a time for easy upload to GL. struct Float4 { float data[4]; @@ -31,8 +30,10 @@ TexturedQuadDrawCache(); ~TexturedQuadDrawCache(); + bool is_empty = true; + // Values tracked to determine if textured quads may be coalesced. - const Program* program = nullptr; + ProgramKey program_key; int resource_id = -1; bool needs_blending = false; bool nearest_neighbor = false;
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc index 42cdb4f..c4683999 100644 --- a/cc/output/gl_renderer_unittest.cc +++ b/cc/output/gl_renderer_unittest.cc
@@ -133,28 +133,47 @@ ASSERT_FALSE(renderer()->IsContextLost()); } + void TestShader(const ProgramKey& program_key) { + renderer()->SetCurrentFrameForTesting(GLRenderer::DrawingFrame()); + const size_t kNumSrcColorSpaces = 3; + gfx::ColorSpace src_color_spaces[kNumSrcColorSpaces] = { + gfx::ColorSpace(), gfx::ColorSpace::CreateSRGB(), + gfx::ColorSpace::CreateREC709(), + }; + const size_t kNumDstColorSpaces = 3; + gfx::ColorSpace dst_color_spaces[kNumDstColorSpaces] = { + gfx::ColorSpace(), gfx::ColorSpace::CreateSRGB(), + gfx::ColorSpace::CreateSCRGBLinear(), + }; + for (size_t i = 0; i < kNumDstColorSpaces; ++i) { + for (size_t j = 0; j < kNumSrcColorSpaces; ++j) { + renderer()->SetUseProgram(program_key, src_color_spaces[j], + dst_color_spaces[i]); + EXPECT_TRUE(renderer()->current_program_->initialized()); + } + } + } + void TestBasicShaders() { - EXPECT_PROGRAM_VALID(renderer()->GetProgram(ProgramKey::DebugBorder())); - EXPECT_PROGRAM_VALID(renderer()->GetProgram(ProgramKey::SolidColor(NO_AA))); - EXPECT_PROGRAM_VALID( - renderer()->GetProgram(ProgramKey::SolidColor(USE_AA))); + TestShader(ProgramKey::DebugBorder()); + TestShader(ProgramKey::SolidColor(NO_AA)); + TestShader(ProgramKey::SolidColor(USE_AA)); } void TestShadersWithPrecision(TexCoordPrecision precision) { // This program uses external textures and sampler, so it won't compile // everywhere. - if (context_provider()->ContextCapabilities().egl_image_external) - EXPECT_PROGRAM_VALID( - renderer()->GetProgram(ProgramKey::VideoStream(precision))); + if (context_provider()->ContextCapabilities().egl_image_external) { + TestShader(ProgramKey::VideoStream(precision)); + } } void TestShadersWithPrecisionAndBlend(TexCoordPrecision precision, BlendMode blend_mode) { - EXPECT_PROGRAM_VALID(renderer()->GetProgram(ProgramKey::RenderPass( - precision, SAMPLER_TYPE_2D, blend_mode, NO_AA, NO_MASK, false, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA, - NO_MASK, false, false))); + TestShader(ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, + NO_AA, NO_MASK, false, false)); + TestShader(ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, + USE_AA, NO_MASK, false, false)); } void TestShadersWithPrecisionAndSampler(TexCoordPrecision precision, @@ -165,41 +184,29 @@ return; } - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA, true))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram(ProgramKey::Texture( - precision, sampler, NON_PREMULTIPLIED_ALPHA, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram(ProgramKey::Texture( - precision, sampler, NON_PREMULTIPLIED_ALPHA, true))); - - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::Tile(precision, sampler, USE_AA, NO_SWIZZLE, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::Tile(precision, sampler, USE_AA, DO_SWIZZLE, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE, true))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE, true))); + TestShader( + ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA, false)); + TestShader( + ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA, true)); + TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA, + false)); + TestShader( + ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA, true)); + TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE, false)); + TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE, false)); + TestShader(ProgramKey::Tile(precision, sampler, USE_AA, NO_SWIZZLE, false)); + TestShader(ProgramKey::Tile(precision, sampler, USE_AA, DO_SWIZZLE, false)); + TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE, true)); + TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE, true)); // Iterate over alpha plane, nv12, and color_lut parameters. UVTextureMode uv_modes[2] = {UV_TEXTURE_MODE_UV, UV_TEXTURE_MODE_U_V}; YUVAlphaTextureMode a_modes[2] = {YUV_NO_ALPHA_TEXTURE, YUV_HAS_ALPHA_TEXTURE}; - ColorConversionMode c_modes[2] = {COLOR_CONVERSION_MODE_NONE, - COLOR_CONVERSION_MODE_LUT}; for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { - for (int l = 0; l < 2; l++) { - const Program* program = renderer()->GetProgram(ProgramKey::YUVVideo( - precision, sampler, a_modes[j], uv_modes[k], c_modes[l])); - EXPECT_PROGRAM_VALID(program); - } + TestShader( + ProgramKey::YUVVideo(precision, sampler, a_modes[j], uv_modes[k])); } } } @@ -214,18 +221,14 @@ return; } - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA, HAS_MASK, - mask_for_background, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA, HAS_MASK, - mask_for_background, true))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA, HAS_MASK, - mask_for_background, false))); - EXPECT_PROGRAM_VALID(renderer()->GetProgram( - ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA, HAS_MASK, - mask_for_background, true))); + TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA, + HAS_MASK, mask_for_background, false)); + TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA, + HAS_MASK, mask_for_background, true)); + TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA, + HAS_MASK, mask_for_background, false)); + TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA, + HAS_MASK, mask_for_background, true)); } }; @@ -410,7 +413,7 @@ ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, NO_AA, NO_MASK, false, false)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } void TestRenderPassColorMatrixProgram(TexCoordPrecision precision, @@ -419,7 +422,7 @@ ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, NO_AA, NO_MASK, false, true)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } void TestRenderPassMaskProgram(TexCoordPrecision precision, @@ -429,7 +432,7 @@ renderer_->GetProgramIfInitialized(ProgramKey::RenderPass( precision, sampler, blend_mode, NO_AA, HAS_MASK, false, false)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision, @@ -439,7 +442,7 @@ renderer_->GetProgramIfInitialized(ProgramKey::RenderPass( precision, sampler, blend_mode, NO_AA, HAS_MASK, false, true)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } void TestRenderPassProgramAA(TexCoordPrecision precision, @@ -448,7 +451,7 @@ ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA, NO_MASK, false, false)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision, @@ -457,7 +460,7 @@ ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA, NO_MASK, false, true)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } void TestRenderPassMaskProgramAA(TexCoordPrecision precision, @@ -467,7 +470,7 @@ renderer_->GetProgramIfInitialized(ProgramKey::RenderPass( precision, sampler, blend_mode, USE_AA, HAS_MASK, false, false)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision, @@ -477,14 +480,14 @@ renderer_->GetProgramIfInitialized(ProgramKey::RenderPass( precision, sampler, blend_mode, USE_AA, HAS_MASK, false, true)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } void TestSolidColorProgramAA() { const Program* program = renderer_->GetProgramIfInitialized(ProgramKey::SolidColor(USE_AA)); EXPECT_PROGRAM_VALID(program); - EXPECT_EQ(program, renderer_->program_shadow_); + EXPECT_EQ(program, renderer_->current_program_); } RendererSettings settings_;
diff --git a/cc/output/program_binding.cc b/cc/output/program_binding.cc index d80ef68..dc8fe84 100644 --- a/cc/output/program_binding.cc +++ b/cc/output/program_binding.cc
@@ -32,6 +32,10 @@ color_conversion_mode_ == other.color_conversion_mode_; } +bool ProgramKey::operator!=(const ProgramKey& other) const { + return !(*this == other); +} + // static ProgramKey ProgramKey::DebugBorder() { ProgramKey result; @@ -110,8 +114,7 @@ ProgramKey ProgramKey::YUVVideo(TexCoordPrecision precision, SamplerType sampler, YUVAlphaTextureMode yuv_alpha_texture_mode, - UVTextureMode uv_texture_mode, - ColorConversionMode color_conversion_mode) { + UVTextureMode uv_texture_mode) { ProgramKey result; result.type_ = PROGRAM_TYPE_YUV_VIDEO; result.precision_ = precision; @@ -122,7 +125,6 @@ result.uv_texture_mode_ = uv_texture_mode; DCHECK(uv_texture_mode == UV_TEXTURE_MODE_UV || uv_texture_mode == UV_TEXTURE_MODE_U_V); - result.color_conversion_mode_ = color_conversion_mode; return result; }
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h index b79a0c29..3b9a382b 100644 --- a/cc/output/program_binding.h +++ b/cc/output/program_binding.h
@@ -66,6 +66,7 @@ class CC_EXPORT ProgramKey { public: + ProgramKey(); ProgramKey(const ProgramKey& other); ~ProgramKey(); @@ -93,13 +94,16 @@ static ProgramKey YUVVideo(TexCoordPrecision precision, SamplerType sampler, YUVAlphaTextureMode yuv_alpha_texture_mode, - UVTextureMode uv_texture_mode, - ColorConversionMode color_conversion_mode); + UVTextureMode uv_texture_mode); bool operator==(const ProgramKey& other) const; + bool operator!=(const ProgramKey& other) const; + + void SetColorConversionMode(ColorConversionMode color_conversion_mode) { + color_conversion_mode_ = color_conversion_mode; + } private: - ProgramKey(); friend struct ProgramKeyHash; friend class Program; @@ -159,6 +163,7 @@ fragment_shader_.premultiply_alpha_mode_ = key.premultiplied_alpha_; fragment_shader_.mask_mode_ = key.mask_mode_; fragment_shader_.mask_for_background_ = key.mask_for_background_; + fragment_shader_.color_conversion_mode_ = key.color_conversion_mode_; switch (key.type_) { case PROGRAM_TYPE_DEBUG_BORDER: @@ -382,7 +387,6 @@ fragment_shader_.has_uniform_alpha_ = true; fragment_shader_.yuv_alpha_texture_mode_ = key.yuv_alpha_texture_mode_; fragment_shader_.uv_texture_mode_ = key.uv_texture_mode_; - fragment_shader_.color_conversion_mode_ = key.color_conversion_mode_; } void InitializeInternal(ContextProvider* context_provider) {
diff --git a/cc/output/renderer_settings.cc b/cc/output/renderer_settings.cc index 6ba4b48..85b032c 100644 --- a/cc/output/renderer_settings.cc +++ b/cc/output/renderer_settings.cc
@@ -12,21 +12,7 @@ namespace cc { RendererSettings::RendererSettings() - : allow_antialiasing(true), - force_antialiasing(false), - force_blending_with_shaders(false), - partial_swap_enabled(false), - finish_rendering_on_resize(false), - should_clear_root_render_pass(true), - disable_display_vsync(false), - release_overlay_resources_after_gpu_query(false), - gl_composited_texture_quad_border(false), - show_overdraw_feedback(false), - refresh_rate(60.0), - highp_threshold_min(0), - texture_id_allocation_chunk_size(64), - use_gpu_memory_buffer_resources(false), - preferred_tile_format(PlatformColor::BestTextureFormat()) {} + : preferred_tile_format(PlatformColor::BestTextureFormat()) {} RendererSettings::RendererSettings(const RendererSettings& other) = default; @@ -46,6 +32,8 @@ gl_composited_texture_quad_border == other.gl_composited_texture_quad_border && show_overdraw_feedback == other.show_overdraw_feedback && + enable_color_correct_rendering == + other.enable_color_correct_rendering && refresh_rate == other.refresh_rate && highp_threshold_min == other.highp_threshold_min && texture_id_allocation_chunk_size ==
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h index c3e0d2d..ced1ec0c 100644 --- a/cc/output/renderer_settings.h +++ b/cc/output/renderer_settings.h
@@ -19,21 +19,22 @@ RendererSettings(const RendererSettings& other); ~RendererSettings(); - bool allow_antialiasing; - bool force_antialiasing; - bool force_blending_with_shaders; - bool partial_swap_enabled; - bool finish_rendering_on_resize; - bool should_clear_root_render_pass; - bool disable_display_vsync; - bool release_overlay_resources_after_gpu_query; - bool gl_composited_texture_quad_border; - bool show_overdraw_feedback; + bool allow_antialiasing = true; + bool force_antialiasing = false; + bool force_blending_with_shaders = false; + bool partial_swap_enabled = false; + bool finish_rendering_on_resize = false; + bool should_clear_root_render_pass = true; + bool disable_display_vsync = false; + bool release_overlay_resources_after_gpu_query = false; + bool gl_composited_texture_quad_border = false; + bool show_overdraw_feedback = false; + bool enable_color_correct_rendering = false; - double refresh_rate; - int highp_threshold_min; - size_t texture_id_allocation_chunk_size; - bool use_gpu_memory_buffer_resources; + double refresh_rate = 60.0; + int highp_threshold_min = 0; + size_t texture_id_allocation_chunk_size = 64; + bool use_gpu_memory_buffer_resources = false; ResourceFormat preferred_tile_format; BufferToTextureTargetMap buffer_to_texture_target_map;
diff --git a/cc/output/shader.cc b/cc/output/shader.cc index e64dd05..2972183 100644 --- a/cc/output/shader.cc +++ b/cc/output/shader.cc
@@ -60,28 +60,32 @@ static std::string SetFragmentTexCoordPrecision( TexCoordPrecision requested_precision, std::string shader_string) { + std::string prefix; switch (requested_precision) { case TEX_COORD_PRECISION_HIGH: DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos); - return "#ifdef GL_FRAGMENT_PRECISION_HIGH\n" - " #define TexCoordPrecision highp\n" - "#else\n" - " #define TexCoordPrecision mediump\n" - "#endif\n" + - shader_string; + prefix = + "#ifdef GL_FRAGMENT_PRECISION_HIGH\n" + " #define TexCoordPrecision highp\n" + "#else\n" + " #define TexCoordPrecision mediump\n" + "#endif\n"; + break; case TEX_COORD_PRECISION_MEDIUM: DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos); - return "#define TexCoordPrecision mediump\n" + shader_string; + prefix = "#define TexCoordPrecision mediump\n"; + break; case TEX_COORD_PRECISION_NA: DCHECK_EQ(shader_string.find("TexCoordPrecision"), std::string::npos); DCHECK_EQ(shader_string.find("texture2D"), std::string::npos); DCHECK_EQ(shader_string.find("texture2DRect"), std::string::npos); - return shader_string; + break; default: NOTREACHED(); break; } - return shader_string; + std::string lut_prefix = "#define LutLookup texture2D\n"; + return prefix + lut_prefix + shader_string; } TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context, @@ -884,8 +888,8 @@ HDR(" // [0.5 .. 31.5] / N (assuming a LUT size of 17^3)"); HDR(" pos.xy = (pos.xy + vec2(0.5)) / size;"); HDR(" pos.y = (pos.y + layer) / size;"); - HDR(" return mix(texture2D(sampler, pos.xy),"); - HDR(" texture2D(sampler, pos.xy + vec2(0, 1.0 / size)),"); + HDR(" return mix(LutLookup(sampler, pos.xy),"); + HDR(" LutLookup(sampler, pos.xy + vec2(0, 1.0 / size)),"); HDR(" pos.z - layer);"); HDR("}"); SRC("texColor.xyz = LUT(lut_texture, texColor.xyz, lut_size).xyz;");
diff --git a/chrome/VERSION b/chrome/VERSION index c39ca2e7..4e03bd3 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=58 MINOR=0 -BUILD=3009 +BUILD=3010 PATCH=0
diff --git a/chrome/browser/extensions/native_bindings_apitest.cc b/chrome/browser/extensions/native_bindings_apitest.cc index c1d5ed9..6585656 100644 --- a/chrome/browser/extensions/native_bindings_apitest.cc +++ b/chrome/browser/extensions/native_bindings_apitest.cc
@@ -5,6 +5,7 @@ #include "base/command_line.h" #include "chrome/browser/extensions/extension_apitest.h" #include "extensions/common/switches.h" +#include "net/dns/mock_host_resolver.h" namespace extensions { @@ -32,6 +33,7 @@ }; IN_PROC_BROWSER_TEST_F(NativeBindingsApiTest, SimpleEndToEndTest) { + host_resolver()->AddRule("*", "127.0.0.1"); embedded_test_server()->ServeFilesFromDirectory(test_data_dir_); ASSERT_TRUE(StartEmbeddedTestServer()); ASSERT_TRUE(RunExtensionTest("native_bindings/extension")) << message_;
diff --git a/chrome/test/data/extensions/api_test/native_bindings/extension/background.js b/chrome/test/data/extensions/api_test/native_bindings/extension/background.js index 7300d5c..7cfaa0fc 100644 --- a/chrome/test/data/extensions/api_test/native_bindings/extension/background.js +++ b/chrome/test/data/extensions/api_test/native_bindings/extension/background.js
@@ -93,7 +93,28 @@ chrome.test.assertTrue(!!chrome.cast.streaming.udpTransport); chrome.test.assertTrue(!!chrome.cast.streaming.udpTransport.setOptions); chrome.test.succeed(); - } + }, + function injectScript() { + var url = + 'http://example.com:' + portNumber + '/native_bindings/simple.html'; + // Create a tab, and inject code in it to change its title. + // chrome.tabs.executeScript relies on external type references + // (extensionTypes.InjectDetails), so this exercises that flow as well. + chrome.tabs.create({url: url}, function(tab) { + chrome.test.assertTrue(!!tab, 'tab'); + chrome.test.assertEq(new URL(url).host, new URL(tab.url).host); + var code = 'document.title = "new title";'; + chrome.tabs.executeScript(tab.id, {code: code}, function(results) { + chrome.test.assertTrue(!!results, 'results'); + chrome.test.assertEq(1, results.length); + chrome.test.assertEq('new title', results[0]); + chrome.tabs.get(tab.id, tab => { + chrome.test.assertEq('new title', tab.title); + chrome.test.succeed(); + }); + }); + }); + }, ]; chrome.test.getConfig(config => {
diff --git a/chrome/test/data/extensions/api_test/native_bindings/extension/manifest.json b/chrome/test/data/extensions/api_test/native_bindings/extension/manifest.json index d189c9ad..da21db2 100644 --- a/chrome/test/data/extensions/api_test/native_bindings/extension/manifest.json +++ b/chrome/test/data/extensions/api_test/native_bindings/extension/manifest.json
@@ -4,7 +4,7 @@ "description": "A simple e2e test for native bindings, id is ddchlicdkolnonkihahngkmmmjnjlkkf", "manifest_version": 2, "version": "0.1", - "permissions": ["idle", "tabs", "cast.streaming"], + "permissions": ["idle", "tabs", "cast.streaming", "*://example.com:*/*"], "background": { "persistent": false, "page": "background.html"
diff --git a/chrome/test/data/extensions/api_test/native_bindings/simple.html b/chrome/test/data/extensions/api_test/native_bindings/simple.html new file mode 100644 index 0000000..8fb2f0f --- /dev/null +++ b/chrome/test/data/extensions/api_test/native_bindings/simple.html
@@ -0,0 +1,9 @@ +<!doctype html> +<html> +<head> + <title>Original Title</title> +</head> +<body> +Content +</body> +</html>
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index 7b818ab..ae598c0 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -1105,10 +1105,7 @@ void RenderWidgetCompositor::DidSubmitCompositorFrame() {} -void RenderWidgetCompositor::DidLoseCompositorFrameSink() { - // The CompositorFrameSink is not lost in layout tests (single thread mode). - NOTREACHED(); -} +void RenderWidgetCompositor::DidLoseCompositorFrameSink() {} void RenderWidgetCompositor::SetFrameSinkId( const cc::FrameSinkId& frame_sink_id) {
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn index a7df614..34cfe50 100644 --- a/extensions/renderer/BUILD.gn +++ b/extensions/renderer/BUILD.gn
@@ -34,6 +34,8 @@ "api_request_handler.h", "api_signature.cc", "api_signature.h", + "api_type_reference_map.cc", + "api_type_reference_map.h", "app_window_custom_bindings.cc", "app_window_custom_bindings.h", "argument_spec.cc",
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/api_binding.cc index 6056346..1ffa3ba 100644 --- a/extensions/renderer/api_binding.cc +++ b/extensions/renderer/api_binding.cc
@@ -17,6 +17,7 @@ #include "extensions/renderer/api_event_handler.h" #include "extensions/renderer/api_request_handler.h" #include "extensions/renderer/api_signature.h" +#include "extensions/renderer/api_type_reference_map.h" #include "extensions/renderer/v8_helpers.h" #include "gin/arguments.h" #include "gin/per_context_data.h" @@ -99,7 +100,7 @@ const base::ListValue* event_definitions, const SendRequestMethod& callback, std::unique_ptr<APIBindingHooks> binding_hooks, - ArgumentSpec::RefMap* type_refs, + APITypeReferenceMap* type_refs, APIRequestHandler* request_handler) : api_name_(api_name), method_callback_(callback), @@ -129,9 +130,6 @@ CHECK(type->GetAsDictionary(&type_dict)); std::string id; CHECK(type_dict->GetString("id", &id)); - DCHECK(type_refs->find(id) == type_refs->end()); - // TODO(devlin): refs are sometimes preceeded by the API namespace; we - // might need to take that into account. auto argument_spec = base::MakeUnique<ArgumentSpec>(*type_dict); const std::set<std::string>& enum_values = argument_spec->enum_values(); if (!enum_values.empty()) { @@ -147,7 +145,7 @@ std::make_pair(enum_value, GetJSEnumEntryName(enum_value))); } } - (*type_refs)[id] = std::move(argument_spec); + type_refs->AddSpec(id, std::move(argument_spec)); } }
diff --git a/extensions/renderer/api_binding.h b/extensions/renderer/api_binding.h index 343c59de..8d9468b 100644 --- a/extensions/renderer/api_binding.h +++ b/extensions/renderer/api_binding.h
@@ -29,6 +29,7 @@ class APIEventHandler; class APIRequestHandler; class APISignature; +class APITypeReferenceMap; // A class that vends v8::Objects for extension APIs. These APIs have function // interceptors for all exposed methods, which call back into the APIBinding. @@ -66,7 +67,7 @@ // The callback type for handling an API call. using HandlerCallback = base::Callback<void(gin::Arguments*)>; - // The ArgumentSpec::RefMap is required to outlive this object. + // The APITypeReferenceMap is required to outlive this object. // |function_definitions|, |type_definitions| and |event_definitions| // may be null if the API does not specify any of that category. APIBinding(const std::string& name, @@ -75,7 +76,7 @@ const base::ListValue* event_definitions, const SendRequestMethod& callback, std::unique_ptr<APIBindingHooks> binding_hooks, - ArgumentSpec::RefMap* type_refs, + APITypeReferenceMap* type_refs, APIRequestHandler* request_handler); ~APIBinding(); @@ -120,7 +121,7 @@ std::unique_ptr<APIBindingHooks> binding_hooks_; // The reference map for all known types; required to outlive this object. - const ArgumentSpec::RefMap* type_refs_; + const APITypeReferenceMap* type_refs_; // The associated request handler, shared between this and other bindings. // Required to outlive this object.
diff --git a/extensions/renderer/api_binding_hooks.cc b/extensions/renderer/api_binding_hooks.cc index 78feb4b..2d07276 100644 --- a/extensions/renderer/api_binding_hooks.cc +++ b/extensions/renderer/api_binding_hooks.cc
@@ -223,7 +223,7 @@ v8::Local<v8::Context> context, const APISignature* signature, std::vector<v8::Local<v8::Value>>* arguments, - const ArgumentSpec::RefMap& type_refs) { + const APITypeReferenceMap& type_refs) { // Easy case: a native custom hook. auto request_hooks_iter = request_hooks_.find(method_name); if (request_hooks_iter != request_hooks_.end()) {
diff --git a/extensions/renderer/api_binding_hooks.h b/extensions/renderer/api_binding_hooks.h index d4d939b..4896771a 100644 --- a/extensions/renderer/api_binding_hooks.h +++ b/extensions/renderer/api_binding_hooks.h
@@ -61,7 +61,7 @@ base::Callback<RequestResult(const APISignature*, v8::Local<v8::Context> context, std::vector<v8::Local<v8::Value>>*, - const ArgumentSpec::RefMap&)>; + const APITypeReferenceMap&)>; explicit APIBindingHooks(const binding::RunJSFunctionSync& run_js); ~APIBindingHooks(); @@ -86,7 +86,7 @@ v8::Local<v8::Context> context, const APISignature* signature, std::vector<v8::Local<v8::Value>>* arguments, - const ArgumentSpec::RefMap& type_refs); + const APITypeReferenceMap& type_refs); // Returns a JS interface that can be used to register hooks. v8::Local<v8::Object> GetJSHookInterface(const std::string& api_name,
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc index 389d6ec..e56e93d9 100644 --- a/extensions/renderer/api_binding_unittest.cc +++ b/extensions/renderer/api_binding_unittest.cc
@@ -13,6 +13,7 @@ #include "extensions/renderer/api_binding_test_util.h" #include "extensions/renderer/api_event_handler.h" #include "extensions/renderer/api_request_handler.h" +#include "extensions/renderer/api_type_reference_map.h" #include "gin/arguments.h" #include "gin/converter.h" #include "gin/public/context_holder.h" @@ -131,7 +132,8 @@ } protected: - APIBindingUnittest() {} + APIBindingUnittest() + : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {} void SetUp() override { APIBindingTest::SetUp(); request_handler_ = base::MakeUnique<APIRequestHandler>( @@ -214,7 +216,7 @@ APIBinding* binding() { return binding_.get(); } APIEventHandler* event_handler() { return event_handler_.get(); } APIRequestHandler* request_handler() { return request_handler_.get(); } - const ArgumentSpec::RefMap& type_refs() const { return type_refs_; } + const APITypeReferenceMap& type_refs() const { return type_refs_; } private: void RunTest(v8::Local<v8::Context> context, @@ -229,7 +231,7 @@ std::unique_ptr<APIBinding> binding_; std::unique_ptr<APIEventHandler> event_handler_; std::unique_ptr<APIRequestHandler> request_handler_; - ArgumentSpec::RefMap type_refs_; + APITypeReferenceMap type_refs_; std::unique_ptr<base::ListValue> binding_functions_; std::unique_ptr<base::ListValue> binding_events_; @@ -431,8 +433,8 @@ SetTypes(kTypes); InitializeBinding(); EXPECT_EQ(2u, type_refs().size()); - EXPECT_TRUE(base::ContainsKey(type_refs(), "refObj")); - EXPECT_TRUE(base::ContainsKey(type_refs(), "refEnum")); + EXPECT_TRUE(type_refs().GetSpec("refObj")); + EXPECT_TRUE(type_refs().GetSpec("refEnum")); v8::HandleScope handle_scope(isolate()); v8::Local<v8::Context> context = ContextLocal(); @@ -585,7 +587,7 @@ auto hook = [](bool* did_call, const APISignature* signature, v8::Local<v8::Context> context, std::vector<v8::Local<v8::Value>>* arguments, - const ArgumentSpec::RefMap& ref_map) { + const APITypeReferenceMap& ref_map) { *did_call = true; APIBindingHooks::RequestResult result( APIBindingHooks::RequestResult::HANDLED); @@ -887,7 +889,7 @@ auto hook = [](bool* did_call, const APISignature* signature, v8::Local<v8::Context> context, std::vector<v8::Local<v8::Value>>* arguments, - const ArgumentSpec::RefMap& ref_map) { + const APITypeReferenceMap& ref_map) { APIBindingHooks::RequestResult result( APIBindingHooks::RequestResult::HANDLED); if (arguments->size() != 1u) { // ASSERT* messes with the return type.
diff --git a/extensions/renderer/api_bindings_system.cc b/extensions/renderer/api_bindings_system.cc index 040d620..868c465d 100644 --- a/extensions/renderer/api_bindings_system.cc +++ b/extensions/renderer/api_bindings_system.cc
@@ -17,7 +17,9 @@ const GetAPISchemaMethod& get_api_schema, const APIBinding::SendRequestMethod& send_request, const APIEventHandler::EventListenersChangedMethod& event_listeners_changed) - : request_handler_(call_js), + : type_reference_map_(base::Bind(&APIBindingsSystem::InitializeType, + base::Unretained(this))), + request_handler_(call_js), event_handler_(call_js, event_listeners_changed), call_js_(call_js), call_js_sync_(call_js_sync), @@ -70,6 +72,25 @@ send_request_, std::move(hooks), &type_reference_map_, &request_handler_); } +void APIBindingsSystem::InitializeType(const std::string& type_name) { + // In order to initialize the type, we just initialize the full binding. This + // seems like a lot of work, but in practice, trying to extract out only the + // types from the schema, and then update the reference map based on that, is + // close enough to the same cost. Additionally, this happens lazily on API + // use, and relatively few APIs specify types from another API. Finally, this + // will also go away if/when we generate all these specifications. + std::string::size_type dot = type_name.rfind('.'); + // The type name should be fully qualified (include the API name). + DCHECK_NE(std::string::npos, dot); + DCHECK_LT(dot, type_name.size() - 1); + std::string api_name = type_name.substr(0, dot); + // If we've already instantiated the binding, the type should have been in + // there. + DCHECK(api_bindings_.find(api_name) == api_bindings_.end()); + + api_bindings_[api_name] = CreateNewAPIBinding(api_name); +} + void APIBindingsSystem::CompleteRequest(int request_id, const base::ListValue& response) { request_handler_.CompleteRequest(request_id, response);
diff --git a/extensions/renderer/api_bindings_system.h b/extensions/renderer/api_bindings_system.h index 52cfdf89..ae7442d5 100644 --- a/extensions/renderer/api_bindings_system.h +++ b/extensions/renderer/api_bindings_system.h
@@ -15,7 +15,7 @@ #include "extensions/renderer/api_binding_types.h" #include "extensions/renderer/api_event_handler.h" #include "extensions/renderer/api_request_handler.h" -#include "extensions/renderer/argument_spec.h" +#include "extensions/renderer/api_type_reference_map.h" namespace base { class DictionaryValue; @@ -72,8 +72,12 @@ // Creates a new APIBinding for the given |api_name|. std::unique_ptr<APIBinding> CreateNewAPIBinding(const std::string& api_name); + // Callback for the APITypeReferenceMap in order to initialize an unknown + // type. + void InitializeType(const std::string& name); + // The map of cached API reference types. - ArgumentSpec::RefMap type_reference_map_; + APITypeReferenceMap type_reference_map_; // The request handler associated with the system. APIRequestHandler request_handler_;
diff --git a/extensions/renderer/api_bindings_system_unittest.cc b/extensions/renderer/api_bindings_system_unittest.cc index 9c4fa7b..e5df38d 100644 --- a/extensions/renderer/api_bindings_system_unittest.cc +++ b/extensions/renderer/api_bindings_system_unittest.cc
@@ -29,7 +29,7 @@ const char kAlphaAPISpec[] = "{" " 'types': [{" - " 'id': 'objRef'," + " 'id': 'alpha.objRef'," " 'type': 'object'," " 'properties': {" " 'prop1': {'type': 'string'}," @@ -49,7 +49,7 @@ " 'name': 'functionWithRefAndCallback'," " 'parameters': [{" " 'name': 'ref'," - " '$ref': 'objRef'" + " '$ref': 'alpha.objRef'" " }, {" " 'name': 'callback'," " 'type': 'function'" @@ -70,6 +70,15 @@ " }]" "}"; +const char kGammaAPIName[] = "gamma"; +const char kGammaAPISpec[] = + "{" + " 'functions': [{" + " 'name': 'functionWithExternalRef'," + " 'parameters': [{ 'name': 'someRef', '$ref': 'alpha.objRef' }]" + " }]" + "}"; + bool AllowAllAPIs(const std::string& name) { return true; } @@ -197,7 +206,9 @@ const char* name; const char* spec; } api_data[] = { - {kAlphaAPIName, kAlphaAPISpec}, {kBetaAPIName, kBetaAPISpec}, + {kAlphaAPIName, kAlphaAPISpec}, + {kBetaAPIName, kBetaAPISpec}, + {kGammaAPIName, kGammaAPISpec}, }; for (const auto& api : api_data) { std::unique_ptr<base::DictionaryValue> api_schema = @@ -301,10 +312,10 @@ v8::Local<v8::Context> context = ContextLocal(); bool did_call = false; - auto hook = [](bool* did_call, - const APISignature* signature, v8::Local<v8::Context> context, + auto hook = [](bool* did_call, const APISignature* signature, + v8::Local<v8::Context> context, std::vector<v8::Local<v8::Value>>* arguments, - const ArgumentSpec::RefMap& type_refs) { + const APITypeReferenceMap& type_refs) { *did_call = true; APIBindingHooks::RequestResult result( APIBindingHooks::RequestResult::HANDLED); @@ -405,6 +416,27 @@ } } +// Test that references to other API's types works. +TEST_F(APIBindingsSystemTest, CrossAPIReferences) { + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = ContextLocal(); + + // Instantiate gamma API. Note: It's important that we haven't instantiated + // alpha API yet, since this tests that we can lazily populate the type + // information. + v8::Local<v8::Object> gamma_api = bindings_system()->CreateAPIInstance( + kGammaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), nullptr); + ASSERT_FALSE(gamma_api.IsEmpty()); + + { + // Test a simple call -> response. + const char kTestCall[] = "obj.functionWithExternalRef({prop1: 'foo'});"; + CallFunctionOnObject(context, gamma_api, kTestCall); + ValidateLastRequest("gamma.functionWithExternalRef", "[{'prop1':'foo'}]"); + reset_last_request(); + } +} + // An implementation using real API schemas. class APIBindingsSystemTestWithRealAPI : public APIBindingsSystemTestBase { protected:
diff --git a/extensions/renderer/api_signature.cc b/extensions/renderer/api_signature.cc index 283f407..261775e5 100644 --- a/extensions/renderer/api_signature.cc +++ b/extensions/renderer/api_signature.cc
@@ -8,6 +8,7 @@ #include "base/memory/ptr_util.h" #include "base/values.h" +#include "extensions/renderer/argument_spec.h" #include "gin/arguments.h" namespace extensions { @@ -22,13 +23,13 @@ ArgumentParser(v8::Local<v8::Context> context, const std::vector<std::unique_ptr<ArgumentSpec>>& signature, const std::vector<v8::Local<v8::Value>>& arguments, - const ArgumentSpec::RefMap& type_refs, + const APITypeReferenceMap& type_refs, std::string* error) - : context_(context), - signature_(signature), - arguments_(arguments), - type_refs_(type_refs), - error_(error) {} + : context_(context), + signature_(signature), + arguments_(arguments), + type_refs_(type_refs), + error_(error) {} // Tries to parse the arguments against the expected signature. bool ParseArguments(); @@ -68,7 +69,7 @@ v8::Local<v8::Context> context_; const std::vector<std::unique_ptr<ArgumentSpec>>& signature_; const std::vector<v8::Local<v8::Value>>& arguments_; - const ArgumentSpec::RefMap& type_refs_; + const APITypeReferenceMap& type_refs_; std::string* error_; size_t current_index_ = 0; @@ -80,7 +81,7 @@ V8ArgumentParser(v8::Local<v8::Context> context, const std::vector<std::unique_ptr<ArgumentSpec>>& signature, const std::vector<v8::Local<v8::Value>>& arguments, - const ArgumentSpec::RefMap& type_refs, + const APITypeReferenceMap& type_refs, std::string* error, std::vector<v8::Local<v8::Value>>* values) : ArgumentParser(context, signature, arguments, type_refs, error), @@ -107,7 +108,7 @@ v8::Local<v8::Context> context, const std::vector<std::unique_ptr<ArgumentSpec>>& signature, const std::vector<v8::Local<v8::Value>>& arguments, - const ArgumentSpec::RefMap& type_refs, + const APITypeReferenceMap& type_refs, std::string* error, base::ListValue* list_value) : ArgumentParser(context, signature, arguments, type_refs, error), @@ -230,7 +231,7 @@ bool APISignature::ParseArgumentsToV8( v8::Local<v8::Context> context, const std::vector<v8::Local<v8::Value>>& arguments, - const ArgumentSpec::RefMap& type_refs, + const APITypeReferenceMap& type_refs, std::vector<v8::Local<v8::Value>>* v8_out, std::string* error) const { DCHECK(v8_out); @@ -246,7 +247,7 @@ bool APISignature::ParseArgumentsToJSON( v8::Local<v8::Context> context, const std::vector<v8::Local<v8::Value>>& arguments, - const ArgumentSpec::RefMap& type_refs, + const APITypeReferenceMap& type_refs, std::unique_ptr<base::ListValue>* json_out, v8::Local<v8::Function>* callback_out, std::string* error) const {
diff --git a/extensions/renderer/api_signature.h b/extensions/renderer/api_signature.h index 42d25df7..abc91e02 100644 --- a/extensions/renderer/api_signature.h +++ b/extensions/renderer/api_signature.h
@@ -9,7 +9,6 @@ #include <vector> #include "base/macros.h" -#include "extensions/renderer/argument_spec.h" #include "v8/include/v8.h" namespace base { @@ -18,6 +17,8 @@ } namespace extensions { +class APITypeReferenceMap; +class ArgumentSpec; // A representation of the expected signature for an API method, along with the // ability to match provided arguments and convert them to base::Values. @@ -33,7 +34,7 @@ // Returns true if the arguments were successfully parsed and converted. bool ParseArgumentsToV8(v8::Local<v8::Context> context, const std::vector<v8::Local<v8::Value>>& arguments, - const ArgumentSpec::RefMap& type_refs, + const APITypeReferenceMap& type_refs, std::vector<v8::Local<v8::Value>>* args_out, std::string* error) const; @@ -43,7 +44,7 @@ // callback values, respectively. On failure, returns false populates |error|. bool ParseArgumentsToJSON(v8::Local<v8::Context> context, const std::vector<v8::Local<v8::Value>>& arguments, - const ArgumentSpec::RefMap& type_refs, + const APITypeReferenceMap& type_refs, std::unique_ptr<base::ListValue>* args_out, v8::Local<v8::Function>* callback_out, std::string* error) const;
diff --git a/extensions/renderer/api_type_reference_map.cc b/extensions/renderer/api_type_reference_map.cc new file mode 100644 index 0000000..d700e34bc --- /dev/null +++ b/extensions/renderer/api_type_reference_map.cc
@@ -0,0 +1,32 @@ +// 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. + +#include "extensions/renderer/api_type_reference_map.h" + +#include "extensions/renderer/argument_spec.h" + +namespace extensions { + +APITypeReferenceMap::APITypeReferenceMap( + const InitializeTypeCallback& initialize_type) + : initialize_type_(initialize_type) {} +APITypeReferenceMap::~APITypeReferenceMap() = default; + +void APITypeReferenceMap::AddSpec(const std::string& name, + std::unique_ptr<ArgumentSpec> spec) { + DCHECK(type_refs_.find(name) == type_refs_.end()); + type_refs_[name] = std::move(spec); +} + +const ArgumentSpec* APITypeReferenceMap::GetSpec( + const std::string& name) const { + auto iter = type_refs_.find(name); + if (iter == type_refs_.end()) { + initialize_type_.Run(name); + iter = type_refs_.find(name); + } + return iter == type_refs_.end() ? nullptr : iter->second.get(); +} + +} // namespace extensions
diff --git a/extensions/renderer/api_type_reference_map.h b/extensions/renderer/api_type_reference_map.h new file mode 100644 index 0000000..cf572bd1 --- /dev/null +++ b/extensions/renderer/api_type_reference_map.h
@@ -0,0 +1,48 @@ +// 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. + +#ifndef EXTENSIONS_RENDERER_API_TYPE_REFERENCE_MAP_H_ +#define EXTENSIONS_RENDERER_API_TYPE_REFERENCE_MAP_H_ + +#include <map> +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" + +namespace extensions { +class ArgumentSpec; + +// A map from type name -> ArgumentSpec for API type definitions. This is used +// when an argument is declared to be a reference to a type defined elsewhere. +class APITypeReferenceMap { + public: + // A callback used to initialize an unknown type, so that these can be + // created lazily. + using InitializeTypeCallback = base::Callback<void(const std::string& name)>; + + explicit APITypeReferenceMap(const InitializeTypeCallback& initialize_type); + ~APITypeReferenceMap(); + + // Adds the |spec| to the map under the given |name|. + void AddSpec(const std::string& name, std::unique_ptr<ArgumentSpec> spec); + + // Returns the spec for the given |name|. + const ArgumentSpec* GetSpec(const std::string& name) const; + + bool empty() const { return type_refs_.empty(); } + size_t size() const { return type_refs_.size(); } + + private: + InitializeTypeCallback initialize_type_; + + std::map<std::string, std::unique_ptr<ArgumentSpec>> type_refs_; + + DISALLOW_COPY_AND_ASSIGN(APITypeReferenceMap); +}; + +} // namespace extensions + +#endif // EXTENSIONS_RENDERER_API_TYPE_REFERENCE_MAP_H_
diff --git a/extensions/renderer/argument_spec.cc b/extensions/renderer/argument_spec.cc index b72e3c0..cd8da0f 100644 --- a/extensions/renderer/argument_spec.cc +++ b/extensions/renderer/argument_spec.cc
@@ -7,6 +7,7 @@ #include "base/memory/ptr_util.h" #include "base/values.h" #include "content/public/child/v8_value_converter.h" +#include "extensions/renderer/api_type_reference_map.h" #include "gin/converter.h" #include "gin/dictionary.h" @@ -126,7 +127,7 @@ bool ArgumentSpec::ParseArgument(v8::Local<v8::Context> context, v8::Local<v8::Value> value, - const RefMap& refs, + const APITypeReferenceMap& refs, std::unique_ptr<base::Value>* out_value, std::string* error) const { if (type_ == ArgumentType::FUNCTION) { @@ -137,9 +138,9 @@ if (type_ == ArgumentType::REF) { DCHECK(ref_); - auto iter = refs.find(ref_.value()); - DCHECK(iter != refs.end()) << ref_.value(); - return iter->second->ParseArgument(context, value, refs, out_value, error); + const ArgumentSpec* reference = refs.GetSpec(ref_.value()); + DCHECK(reference) << ref_.value(); + return reference->ParseArgument(context, value, refs, out_value, error); } if (type_ == ArgumentType::CHOICES) { @@ -244,7 +245,7 @@ bool ArgumentSpec::ParseArgumentToObject( v8::Local<v8::Context> context, v8::Local<v8::Object> object, - const RefMap& refs, + const APITypeReferenceMap& refs, std::unique_ptr<base::Value>* out_value, std::string* error) const { DCHECK_EQ(ArgumentType::OBJECT, type_); @@ -288,7 +289,7 @@ bool ArgumentSpec::ParseArgumentToArray(v8::Local<v8::Context> context, v8::Local<v8::Array> value, - const RefMap& refs, + const APITypeReferenceMap& refs, std::unique_ptr<base::Value>* out_value, std::string* error) const { DCHECK_EQ(ArgumentType::LIST, type_);
diff --git a/extensions/renderer/argument_spec.h b/extensions/renderer/argument_spec.h index 8145d01..8c30d384 100644 --- a/extensions/renderer/argument_spec.h +++ b/extensions/renderer/argument_spec.h
@@ -21,6 +21,7 @@ } namespace extensions { +class APITypeReferenceMap; enum class ArgumentType { INTEGER, @@ -39,10 +40,6 @@ // A description of a given Argument to an Extension. class ArgumentSpec { public: - // A map from name -> definition for type definitions. This is used when an - // argument is declared to be a reference to a type defined elsewhere. - using RefMap = std::map<std::string, std::unique_ptr<ArgumentSpec>>; - // Reads the description from |value| and sets associated fields. // TODO(devlin): We should strongly think about generating these instead of // populating them at runtime. @@ -54,7 +51,7 @@ // |out_value|. Otherwise, no conversion is performed. bool ParseArgument(v8::Local<v8::Context> context, v8::Local<v8::Value> value, - const RefMap& refs, + const APITypeReferenceMap& refs, std::unique_ptr<base::Value>* out_value, std::string* error) const; @@ -78,12 +75,12 @@ std::string* error) const; bool ParseArgumentToObject(v8::Local<v8::Context> context, v8::Local<v8::Object> object, - const RefMap& refs, + const APITypeReferenceMap& refs, std::unique_ptr<base::Value>* out_value, std::string* error) const; bool ParseArgumentToArray(v8::Local<v8::Context> context, v8::Local<v8::Array> value, - const RefMap& refs, + const APITypeReferenceMap& refs, std::unique_ptr<base::Value>* out_value, std::string* error) const; bool ParseArgumentToAny(v8::Local<v8::Context> context,
diff --git a/extensions/renderer/argument_spec_unittest.cc b/extensions/renderer/argument_spec_unittest.cc index da2ac4e4..c6afd26 100644 --- a/extensions/renderer/argument_spec_unittest.cc +++ b/extensions/renderer/argument_spec_unittest.cc
@@ -5,6 +5,7 @@ #include "base/memory/ptr_util.h" #include "base/values.h" #include "extensions/renderer/api_binding_test_util.h" +#include "extensions/renderer/api_type_reference_map.h" #include "extensions/renderer/argument_spec.h" #include "gin/converter.h" #include "gin/public/isolate_holder.h" @@ -16,7 +17,8 @@ class ArgumentSpecUnitTest : public gin::V8Test { protected: - ArgumentSpecUnitTest() {} + ArgumentSpecUnitTest() + : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {} ~ArgumentSpecUnitTest() override {} void ExpectSuccess(const ArgumentSpec& spec, const std::string& script_source, @@ -59,7 +61,7 @@ } void AddTypeRef(const std::string& id, std::unique_ptr<ArgumentSpec> spec) { - type_refs_[id] = std::move(spec); + type_refs_.AddSpec(id, std::move(spec)); } private: @@ -73,7 +75,7 @@ const base::Value* expected_value, const std::string& expected_thrown_message); - ArgumentSpec::RefMap type_refs_; + APITypeReferenceMap type_refs_; DISALLOW_COPY_AND_ASSIGN(ArgumentSpecUnitTest); };
diff --git a/ios/chrome/browser/crash_report/crash_restore_helper.mm b/ios/chrome/browser/crash_report/crash_restore_helper.mm index 6a66ab7..29a14209 100644 --- a/ios/chrome/browser/crash_report/crash_restore_helper.mm +++ b/ios/chrome/browser/crash_report/crash_restore_helper.mm
@@ -296,7 +296,7 @@ tabRestoreService->LoadTabsFromLastSession(); web::WebState::CreateParams params(_browserState); - for (CRWNavigationManagerStorage* session in sessions) { + for (CRWSessionStorage* session in sessions) { std::unique_ptr<web::WebState> webState = web::WebState::Create(params, session); // Add all tabs at the 0 position as the position is relative to an old
diff --git a/ios/chrome/browser/sessions/session_service.mm b/ios/chrome/browser/sessions/session_service.mm index 4112e5ac..f7a4e8a 100644 --- a/ios/chrome/browser/sessions/session_service.mm +++ b/ios/chrome/browser/sessions/session_service.mm
@@ -21,7 +21,7 @@ #import "ios/chrome/browser/sessions/session_window.h" #import "ios/web/navigation/crw_session_certificate_policy_manager.h" #import "ios/web/public/crw_navigation_item_storage.h" -#import "ios/web/public/crw_navigation_manager_storage.h" +#import "ios/web/public/crw_session_storage.h" #include "ios/web/public/web_thread.h" // When C++ exceptions are disabled, the C++ library defines |try| and @@ -211,9 +211,9 @@ // class on disk. [SessionWindowUnarchiver setClass:[CRWSessionCertificatePolicyManager class] forClassName:@"SessionCertificatePolicyManager"]; - [SessionWindowUnarchiver setClass:[CRWNavigationManagerStorage class] + [SessionWindowUnarchiver setClass:[CRWSessionStorage class] forClassName:@"SessionController"]; - [SessionWindowUnarchiver setClass:[CRWNavigationManagerStorage class] + [SessionWindowUnarchiver setClass:[CRWSessionStorage class] forClassName:@"CRWSessionController"]; [SessionWindowUnarchiver setClass:[CRWNavigationItemStorage class] forClassName:@"SessionEntry"];
diff --git a/ios/chrome/browser/sessions/session_window.h b/ios/chrome/browser/sessions/session_window.h index 0e4615d..bfeddf1 100644 --- a/ios/chrome/browser/sessions/session_window.h +++ b/ios/chrome/browser/sessions/session_window.h
@@ -11,7 +11,7 @@ #import "ios/web/web_state/web_state_impl.h" -@class CRWNavigationManagerStorage; +@class CRWSessionStorage; // Encapsulates everything required to save a session "window". For iOS, there // will only be one window at a time. @@ -21,10 +21,10 @@ // initialized "empty" (without any sessions) and sessions are added one at a // time. For example: // SessionWindowIOS* window = [[SessionWindow alloc] init]; -// [window addSerializedSession:session_storage]; +// [window addSerializedSessionStorage:session_storage]; // ... // [window setSelectedIndex:mySelectedIndex]; -- (void)addSerializedSession:(CRWNavigationManagerStorage*)session; +- (void)addSerializedSessionStorage:(CRWSessionStorage*)session; // Clears all added sessions. - (void)clearSessions;
diff --git a/ios/chrome/browser/sessions/session_window.mm b/ios/chrome/browser/sessions/session_window.mm index 7334719..001b301 100644 --- a/ios/chrome/browser/sessions/session_window.mm +++ b/ios/chrome/browser/sessions/session_window.mm
@@ -61,7 +61,7 @@ #pragma mark - Public -- (void)addSerializedSession:(CRWNavigationManagerStorage*)session { +- (void)addSerializedSessionStorage:(CRWSessionStorage*)session { [_sessions addObject:session]; // Set the selected index to 0 (this session) if this is the first session // added.
diff --git a/ios/chrome/browser/sessions/session_window_unittest.mm b/ios/chrome/browser/sessions/session_window_unittest.mm index eb00a9d..8f9d4fd 100644 --- a/ios/chrome/browser/sessions/session_window_unittest.mm +++ b/ios/chrome/browser/sessions/session_window_unittest.mm
@@ -14,7 +14,7 @@ #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/sessions/session_service.h" #import "ios/web/navigation/crw_session_controller.h" -#import "ios/web/public/crw_navigation_manager_storage.h" +#import "ios/web/public/crw_session_storage.h" #include "ios/web/public/test/test_web_thread_bundle.h" #import "ios/web/public/web_state/web_state.h" #include "testing/gtest/include/gtest/gtest.h" @@ -66,10 +66,8 @@ std::unique_ptr<WebStateImpl> webState2(CreateWebState(@"window2", nil, NO)); base::scoped_nsobject<SessionWindowIOS> sessionWindow( [[SessionWindowIOS alloc] init]); - [sessionWindow - addSerializedSession:webState1->BuildSerializedNavigationManager()]; - [sessionWindow - addSerializedSession:webState2->BuildSerializedNavigationManager()]; + [sessionWindow addSerializedSessionStorage:webState1->BuildSessionStorage()]; + [sessionWindow addSerializedSessionStorage:webState2->BuildSessionStorage()]; [sessionWindow setSelectedIndex:1]; EXPECT_TRUE(sessionWindow.get() != nil); @@ -91,10 +89,8 @@ std::unique_ptr<WebStateImpl> webState2(CreateWebState(windowName2, nil, NO)); NSString* openerId2 = webState2->GetNavigationManagerImpl().GetSessionController().openerId; - [sessionWindow - addSerializedSession:webState1->BuildSerializedNavigationManager()]; - [sessionWindow - addSerializedSession:webState2->BuildSerializedNavigationManager()]; + [sessionWindow addSerializedSessionStorage:webState1->BuildSessionStorage()]; + [sessionWindow addSerializedSessionStorage:webState2->BuildSessionStorage()]; [sessionWindow setSelectedIndex:1]; @@ -109,12 +105,12 @@ EXPECT_EQ(unarchivedObj.selectedIndex, sessionWindow.get().selectedIndex); NSArray* sessions = unarchivedObj.sessions; ASSERT_EQ(2U, sessions.count); - CRWNavigationManagerStorage* unarchivedSession1 = sessions[0]; + CRWSessionStorage* unarchivedSession1 = sessions[0]; EXPECT_NSEQ(windowName1, unarchivedSession1.windowName); EXPECT_NSEQ(openerId1, unarchivedSession1.openerID); EXPECT_TRUE(unarchivedSession1.openedByDOM); - CRWNavigationManagerStorage* unarchivedSession2 = sessions[1]; + CRWSessionStorage* unarchivedSession2 = sessions[1]; EXPECT_NSEQ(windowName2, unarchivedSession2.windowName); EXPECT_NSEQ(openerId2, unarchivedSession2.openerID); EXPECT_FALSE(unarchivedSession2.openedByDOM);
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm index 6b405c2..a49cd809 100644 --- a/ios/chrome/browser/tabs/tab_model.mm +++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -809,7 +809,7 @@ for (Tab* tab in self) { web::WebState* webState = tab.webState; DCHECK(webState); - [window addSerializedSession:webState->BuildSerializedNavigationManager()]; + [window addSerializedSessionStorage:webState->BuildSessionStorage()]; } window.selectedIndex = [self indexOfTab:_currentTab]; return window; @@ -963,7 +963,7 @@ scoped_refptr<web::CertificatePolicyCache> policyCache = web::BrowserState::GetCertificatePolicyCache(_browserState); - for (CRWNavigationManagerStorage* session in sessions) { + for (CRWSessionStorage* session in sessions) { std::unique_ptr<web::WebState> webState = web::WebState::Create(params, session); DCHECK_EQ(webState->GetBrowserState(), _browserState);
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm index 56507f5..1213402f 100644 --- a/ios/chrome/browser/tabs/tab_model_unittest.mm +++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -183,8 +183,8 @@ SessionWindowIOS* window = [[SessionWindowIOS alloc] init]; for (int i = 0; i < entries; i++) { NSString* windowName = [NSString stringWithFormat:@"window %d", i + 1]; - [window addSerializedSession:CreateWebState(windowName) - ->BuildSerializedNavigationManager()]; + [window addSerializedSessionStorage:CreateWebState(windowName) + ->BuildSessionStorage()]; } if (entries) [window setSelectedIndex:1];
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn index d084d0f..1723dec7 100644 --- a/ios/web/BUILD.gn +++ b/ios/web/BUILD.gn
@@ -68,10 +68,12 @@ "navigation/navigation_manager_facade_delegate.h", "navigation/navigation_manager_impl.h", "navigation/navigation_manager_impl.mm", - "navigation/navigation_manager_storage_builder.h", - "navigation/navigation_manager_storage_builder.mm", "navigation/nscoder_util.h", "navigation/nscoder_util.mm", + "navigation/serializable_user_data_manager_impl.h", + "navigation/serializable_user_data_manager_impl.mm", + "navigation/session_storage_builder.h", + "navigation/session_storage_builder.mm", "navigation/time_smoother.cc", "navigation/time_smoother.h", "net/cert_host_pair.cc", @@ -103,8 +105,8 @@ "public/certificate_policy_cache.h", "public/crw_navigation_item_storage.h", "public/crw_navigation_item_storage.mm", - "public/crw_navigation_manager_storage.h", - "public/crw_navigation_manager_storage.mm", + "public/crw_session_storage.h", + "public/crw_session_storage.mm", "public/favicon_status.cc", "public/favicon_status.h", "public/favicon_url.cc", @@ -125,6 +127,7 @@ "public/referrer_util.cc", "public/referrer_util.h", "public/security_style.h", + "public/serializable_user_data_manager.h", "public/ssl_status.cc", "public/ssl_status.h", "public/url_data_source_ios.h", @@ -539,6 +542,7 @@ "payments/payment_request_unittest.cc", "public/origin_util_unittest.mm", "public/referrer_util_unittest.cc", + "public/serializable_user_data_manager_unittest.mm", "public/test/crw_mock_web_state_delegate.h", "public/test/crw_mock_web_state_delegate.mm", "public/web_state/page_viewport_state_unittest.mm",
diff --git a/ios/web/navigation/crw_session_controller.mm b/ios/web/navigation/crw_session_controller.mm index c0e48532..2374036 100644 --- a/ios/web/navigation/crw_session_controller.mm +++ b/ios/web/navigation/crw_session_controller.mm
@@ -91,7 +91,7 @@ CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager; // Expose setters for serialization properties. These are exposed in a category -// in NavigationManagerStorageBuilder, and will be removed as ownership of +// in SessionStorageBuilder, and will be removed as ownership of // their backing ivars moves to NavigationManagerImpl. @property(nonatomic, readwrite, copy) NSString* openerId; @property(nonatomic, readwrite, getter=isOpenedByDOM) BOOL openedByDOM;
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h index 33d4fbe6..cf1b295 100644 --- a/ios/web/navigation/navigation_manager_impl.h +++ b/ios/web/navigation/navigation_manager_impl.h
@@ -24,7 +24,7 @@ struct Referrer; class NavigationManagerDelegate; class NavigationManagerFacadeDelegate; -class NavigationManagerStorageBuilder; +class SessionStorageBuilder; // Implementation of NavigationManager. // Generally mirrors upstream's NavigationController. @@ -142,9 +142,9 @@ int GetIndexForOffset(int offset) const; private: - // The NavigationManagerStorageBuilder functions require access to - // private variables of NavigationManagerImpl. - friend NavigationManagerStorageBuilder; + // The SessionStorageBuilder functions require access to private variables of + // NavigationManagerImpl. + friend SessionStorageBuilder; // Returns true if the PageTransition for the underlying navigation item at // |index| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
diff --git a/ios/web/navigation/navigation_manager_storage_builder.h b/ios/web/navigation/navigation_manager_storage_builder.h deleted file mode 100644 index f979075..0000000 --- a/ios/web/navigation/navigation_manager_storage_builder.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2015 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 IOS_WEB_NAVIGATION_SERIALIZED_NAVIGATION_MANAGER_BUILDER_H_ -#define IOS_WEB_NAVIGATION_SERIALIZED_NAVIGATION_MANAGER_BUILDER_H_ - -#include <memory> - -@class CRWNavigationManagerStorage; - -namespace web { - -class NavigationManagerImpl; - -// Class that can serialize and deserialize NavigationManagers. -class NavigationManagerStorageBuilder { - public: - // Creates a serialized NavigationManager from |navigation_manager|. - CRWNavigationManagerStorage* BuildStorage( - NavigationManagerImpl* navigation_manager) const; - // Creates a NavigationManager from |navigation_manager_storage|. - std::unique_ptr<NavigationManagerImpl> BuildNavigationManagerImpl( - CRWNavigationManagerStorage* navigation_manager_storage) const; -}; - -} // namespace web - -#endif // IOS_WEB_NAVIGATION_SERIALIZED_NAVIGATION_MANAGER_BUILDER_H_
diff --git a/ios/web/navigation/serializable_user_data_manager_impl.h b/ios/web/navigation/serializable_user_data_manager_impl.h new file mode 100644 index 0000000..38fa1fb --- /dev/null +++ b/ios/web/navigation/serializable_user_data_manager_impl.h
@@ -0,0 +1,53 @@ +// 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. + +#ifndef IOS_WEB_NAVIGATION_SERIALIZABLE_USER_DATA_MANAGER_IMPL_H_ +#define IOS_WEB_NAVIGATION_SERIALIZABLE_USER_DATA_MANAGER_IMPL_H_ + +#import "base/mac/scoped_nsobject.h" +#import "ios/web/public/serializable_user_data_manager.h" + +namespace web { + +class SerializableUserDataImpl : public SerializableUserData { + public: + SerializableUserDataImpl(); + ~SerializableUserDataImpl(); + + // Constructor taking the NSDictionary holding the serializable data. + explicit SerializableUserDataImpl(NSDictionary* data); + + // SerializableUserData: + void Encode(NSCoder* coder) override; + void Decode(NSCoder* coder) override; + + // Returns the serializable data. + NSDictionary* data() { return data_; }; + + private: + // The dictionary passed on initialization. After calling Decode(), this will + // contain the data that is decoded from the NSCoder. + base::scoped_nsobject<NSDictionary> data_; +}; + +class SerializableUserDataManagerImpl : public SerializableUserDataManager { + public: + SerializableUserDataManagerImpl(); + ~SerializableUserDataManagerImpl(); + + // SerializableUserDataManager: + void AddSerializableData(id<NSCoding> data, NSString* key) override; + id<NSCoding> GetValueForSerializationKey(NSString* key) override; + std::unique_ptr<SerializableUserData> CreateSerializableUserData() + const override; + void AddSerializableUserData(SerializableUserData* data) override; + + private: + // The dictionary that stores serializable user data. + base::scoped_nsobject<NSMutableDictionary> data_; +}; + +} // namespace web + +#endif // IOS_WEB_NAVIGATION_SERIALIZABLE_USER_DATA_MANAGER_IMPL_H_
diff --git a/ios/web/navigation/serializable_user_data_manager_impl.mm b/ios/web/navigation/serializable_user_data_manager_impl.mm new file mode 100644 index 0000000..e3dd7177 --- /dev/null +++ b/ios/web/navigation/serializable_user_data_manager_impl.mm
@@ -0,0 +1,117 @@ +// 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. + +#import "ios/web/navigation/serializable_user_data_manager_impl.h" + +#import "base/mac/foundation_util.h" +#import "ios/web/public/web_state/web_state.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace web { +namespace { +// The key under which SerializableUserDataMangerWrapper are stored in the +// WebState's user data. +const void* const kSerializableUserDataManagerKey = + &kSerializableUserDataManagerKey; +// The key under which SerializableUserDataImpl's data is encoded. +NSString* const kSerializedUserDataKey = @"serializedUserData"; + +// Wrapper class used to associate SerializableUserDataManagerImpls with its +// associated WebState. +class SerializableUserDataManagerWrapper : base::SupportsUserData::Data { + public: + // Returns the SerializableUserDataMangerWrapper associated with |web_state|, + // creating one if necessary. + static SerializableUserDataManagerWrapper* FromWebState( + web::WebState* web_state) { + DCHECK(web_state); + SerializableUserDataManagerWrapper* wrapper = + static_cast<SerializableUserDataManagerWrapper*>( + web_state->GetUserData(kSerializableUserDataManagerKey)); + if (!wrapper) + wrapper = new SerializableUserDataManagerWrapper(web_state); + return wrapper; + } + + // Returns the manager owned by this wrapper. + SerializableUserDataManagerImpl* manager() { return &manager_; } + + private: + // The SerializableUserDataMangerWrapper owned by this object. + SerializableUserDataManagerImpl manager_; + + // Private constructor. The created object will be added to |web_state|'s + // user data. + SerializableUserDataManagerWrapper(web::WebState* web_state) { + DCHECK(web_state); + web_state->SetUserData(kSerializableUserDataManagerKey, this); + } +}; +} // namespace + +// static +std::unique_ptr<SerializableUserData> SerializableUserData::Create() { + return std::unique_ptr<SerializableUserData>(new SerializableUserDataImpl()); +} + +SerializableUserDataImpl::SerializableUserDataImpl() + : data_([[NSDictionary alloc] init]) {} + +SerializableUserDataImpl::~SerializableUserDataImpl() {} + +SerializableUserDataImpl::SerializableUserDataImpl(NSDictionary* data) + : data_([data copy]) {} + +void SerializableUserDataImpl::Encode(NSCoder* coder) { + [coder encodeObject:data_ forKey:kSerializedUserDataKey]; +} + +void SerializableUserDataImpl::Decode(NSCoder* coder) { + NSDictionary* data = base::mac::ObjCCastStrict<NSDictionary>( + [coder decodeObjectForKey:kSerializedUserDataKey]); + data_.reset([data mutableCopy]); +} + +// static +SerializableUserDataManager* SerializableUserDataManager::FromWebState( + web::WebState* web_state) { + DCHECK(web_state); + return SerializableUserDataManagerWrapper::FromWebState(web_state)->manager(); +} + +SerializableUserDataManagerImpl::SerializableUserDataManagerImpl() + : data_([[NSMutableDictionary alloc] init]) {} + +SerializableUserDataManagerImpl::~SerializableUserDataManagerImpl() {} + +void SerializableUserDataManagerImpl::AddSerializableData(id<NSCoding> data, + NSString* key) { + DCHECK(data); + DCHECK(key.length); + [data_ setObject:data forKey:key]; +} + +id<NSCoding> SerializableUserDataManagerImpl::GetValueForSerializationKey( + NSString* key) { + return [data_ objectForKey:key]; +} + +std::unique_ptr<SerializableUserData> +SerializableUserDataManagerImpl::CreateSerializableUserData() const { + return std::unique_ptr<SerializableUserData>( + new SerializableUserDataImpl(data_)); +} + +void SerializableUserDataManagerImpl::AddSerializableUserData( + SerializableUserData* data) { + DCHECK(data); + SerializableUserDataImpl* data_impl = + static_cast<SerializableUserDataImpl*>(data); + data_.reset([data_impl->data() mutableCopy]); +} + +} // namespace web
diff --git a/ios/web/navigation/session_storage_builder.h b/ios/web/navigation/session_storage_builder.h new file mode 100644 index 0000000..4f4c2b9 --- /dev/null +++ b/ios/web/navigation/session_storage_builder.h
@@ -0,0 +1,28 @@ +// Copyright 2015 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 IOS_WEB_NAVIGATION_SERIALIZED_NAVIGATION_MANAGER_BUILDER_H_ +#define IOS_WEB_NAVIGATION_SERIALIZED_NAVIGATION_MANAGER_BUILDER_H_ + +#include <memory> + +@class CRWSessionStorage; + +namespace web { + +class WebStateImpl; + +// Class that can serialize and deserialize session information. +class SessionStorageBuilder { + public: + // Creates a serializable session storage from |web_state|. + CRWSessionStorage* BuildStorage(WebStateImpl* web_state) const; + // Populates |web_state| with |storage|'s session information. + void ExtractSessionState(WebStateImpl* web_state, + CRWSessionStorage* storage) const; +}; + +} // namespace web + +#endif // IOS_WEB_NAVIGATION_SERIALIZED_NAVIGATION_MANAGER_BUILDER_H_
diff --git a/ios/web/navigation/navigation_manager_storage_builder.mm b/ios/web/navigation/session_storage_builder.mm similarity index 66% rename from ios/web/navigation/navigation_manager_storage_builder.mm rename to ios/web/navigation/session_storage_builder.mm index a039ec87..ba44f37 100644 --- a/ios/web/navigation/navigation_manager_storage_builder.mm +++ b/ios/web/navigation/session_storage_builder.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/web/navigation/navigation_manager_storage_builder.h" +#import "ios/web/navigation/session_storage_builder.h" #include "base/logging.h" #include "base/mac/foundation_util.h" @@ -12,7 +12,9 @@ #import "ios/web/navigation/navigation_item_impl.h" #import "ios/web/navigation/navigation_item_storage_builder.h" #include "ios/web/navigation/navigation_manager_impl.h" -#import "ios/web/public/crw_navigation_manager_storage.h" +#import "ios/web/public/crw_session_storage.h" +#import "ios/web/public/serializable_user_data_manager.h" +#import "ios/web/web_state/web_state_impl.h" // CRWSessionController's readonly properties redefined as readwrite. These // will be removed and NavigationManagerImpl's ivars will be written directly @@ -30,11 +32,14 @@ namespace web { -CRWNavigationManagerStorage* NavigationManagerStorageBuilder::BuildStorage( - NavigationManagerImpl* navigation_manager) const { +CRWSessionStorage* SessionStorageBuilder::BuildStorage( + WebStateImpl* web_state) const { + DCHECK(web_state); + web::NavigationManagerImpl* navigation_manager = + web_state->navigation_manager_.get(); DCHECK(navigation_manager); - CRWNavigationManagerStorage* serialized_navigation_manager = - [[CRWNavigationManagerStorage alloc] init]; + CRWSessionStorage* serialized_navigation_manager = + [[CRWSessionStorage alloc] init]; CRWSessionController* session_controller = navigation_manager->GetSessionController(); serialized_navigation_manager.tabID = session_controller.tabId; @@ -58,14 +63,19 @@ [item_storages addObject:item_storage_builder.BuildStorage(item)]; } serialized_navigation_manager.itemStorages = item_storages; + web::SerializableUserDataManager* user_data_manager = + web::SerializableUserDataManager::FromWebState(web_state); + [serialized_navigation_manager + setSerializableUserData:user_data_manager->CreateSerializableUserData()]; return serialized_navigation_manager; } -std::unique_ptr<NavigationManagerImpl> -NavigationManagerStorageBuilder::BuildNavigationManagerImpl( - CRWNavigationManagerStorage* navigation_manager_serialization) const { - DCHECK(navigation_manager_serialization); - NSArray* item_storages = navigation_manager_serialization.itemStorages; +void SessionStorageBuilder::ExtractSessionState( + WebStateImpl* web_state, + CRWSessionStorage* storage) const { + DCHECK(web_state); + DCHECK(storage); + NSArray* item_storages = storage.itemStorages; web::ScopedNavigationItemList items(item_storages.count); NavigationItemStorageBuilder item_storage_builder; for (size_t index = 0; index < item_storages.count; ++index) { @@ -73,32 +83,26 @@ item_storage_builder.BuildNavigationItemImpl(item_storages[index]); items[index] = std::move(item_impl); } - NSUInteger current_index = - navigation_manager_serialization.currentNavigationIndex; + NSUInteger current_index = storage.currentNavigationIndex; base::scoped_nsobject<CRWSessionController> session_controller( [[CRWSessionController alloc] initWithNavigationItems:std::move(items) currentIndex:current_index browserState:nullptr]); - [session_controller setTabId:navigation_manager_serialization.tabID]; - [session_controller setOpenerId:navigation_manager_serialization.openerID]; + [session_controller setTabId:storage.tabID]; + [session_controller setOpenerId:storage.openerID]; + [session_controller setOpenedByDOM:storage.openedByDOM]; + [session_controller setOpenerNavigationIndex:storage.openerNavigationIndex]; + [session_controller setWindowName:storage.windowName]; [session_controller - setOpenedByDOM:navigation_manager_serialization.openedByDOM]; - [session_controller setOpenerNavigationIndex:navigation_manager_serialization - .openerNavigationIndex]; + setPreviousNavigationIndex:storage.previousNavigationIndex]; + [session_controller setLastVisitedTimestamp:storage.lastVisitedTimestamp]; [session_controller - setWindowName:navigation_manager_serialization.windowName]; - [session_controller - setPreviousNavigationIndex:navigation_manager_serialization - .previousNavigationIndex]; - [session_controller setLastVisitedTimestamp:navigation_manager_serialization - .lastVisitedTimestamp]; - [session_controller - setSessionCertificatePolicyManager:navigation_manager_serialization + setSessionCertificatePolicyManager:storage .sessionCertificatePolicyManager]; - std::unique_ptr<NavigationManagerImpl> navigation_manager( - new NavigationManagerImpl()); - navigation_manager->SetSessionController(session_controller); - return navigation_manager; + web_state->navigation_manager_.reset(new NavigationManagerImpl()); + web_state->navigation_manager_->SetSessionController(session_controller); + web::SerializableUserDataManager::FromWebState(web_state) + ->AddSerializableUserData(storage.userData); } } // namespace web
diff --git a/ios/web/public/crw_navigation_manager_storage.h b/ios/web/public/crw_session_storage.h similarity index 63% rename from ios/web/public/crw_navigation_manager_storage.h rename to ios/web/public/crw_session_storage.h index 7360c7d9..fa74465 100644 --- a/ios/web/public/crw_navigation_manager_storage.h +++ b/ios/web/public/crw_session_storage.h
@@ -2,17 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef IOS_WEB_PUBLIC_CRW_NAVIGATION_MANAGER_STORAGE_H_ -#define IOS_WEB_PUBLIC_CRW_NAVIGATION_MANAGER_STORAGE_H_ +#ifndef IOS_WEB_PUBLIC_CRW_SESSION_STORAGE_H_ +#define IOS_WEB_PUBLIC_CRW_SESSION_STORAGE_H_ #import <Foundation/Foundation.h> +#include <memory> @class CRWSessionCertificatePolicyManager; -// NSCoding-compliant class used to serialize NavigationManager's persisted -// properties. +namespace web { +class SerializableUserData; +} + +// NSCoding-compliant class used to serialize session state. // TODO(crbug.com/685388): Investigate using code from the sessions component. -@interface CRWNavigationManagerStorage : NSObject<NSCoding> +@interface CRWSessionStorage : NSObject<NSCoding> @property(nonatomic, copy) NSString* tabID; @property(nonatomic, copy) NSString* openerID; @@ -25,7 +29,12 @@ @property(nonatomic, copy) NSArray* itemStorages; @property(nonatomic, retain) CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager; +@property(nonatomic, readonly) web::SerializableUserData* userData; + +// Setter for |userData|. The receiver takes ownership of |userData|. +- (void)setSerializableUserData: + (std::unique_ptr<web::SerializableUserData>)userData; @end -#endif // IOS_WEB_PUBLIC_CRW_NAVIGATION_MANAGER_STORAGE_H_ +#endif // IOS_WEB_PUBLIC_CRW_SESSION_STORAGE_H_
diff --git a/ios/web/public/crw_navigation_manager_storage.mm b/ios/web/public/crw_session_storage.mm similarity index 84% rename from ios/web/public/crw_navigation_manager_storage.mm rename to ios/web/public/crw_session_storage.mm index 8f77b09..c10d885c 100644 --- a/ios/web/public/crw_navigation_manager_storage.mm +++ b/ios/web/public/crw_session_storage.mm
@@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/web/public/crw_navigation_manager_storage.h" +#import "ios/web/public/crw_session_storage.h" #import "ios/web/navigation/crw_session_certificate_policy_manager.h" +#import "ios/web/public/serializable_user_data_manager.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -24,7 +25,14 @@ NSString* const kWindowNameKey = @"windowName"; } -@implementation CRWNavigationManagerStorage +@interface CRWSessionStorage () { + // Backing object for property of same name. + std::unique_ptr<web::SerializableUserData> _userData; +} + +@end + +@implementation CRWSessionStorage @synthesize tabID = _tabID; @synthesize openerID = _openerID; @@ -37,6 +45,19 @@ @synthesize itemStorages = _itemStorages; @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager; +#pragma mark - Accessors + +- (web::SerializableUserData*)userData { + return _userData.get(); +} + +- (void)setSerializableUserData: + (std::unique_ptr<web::SerializableUserData>)userData { + _userData = std::move(userData); +} + +#pragma mark - NSCoding + - (instancetype)initWithCoder:(nonnull NSCoder*)decoder { self = [super init]; if (self) { @@ -63,6 +84,8 @@ _sessionCertificatePolicyManager = [[CRWSessionCertificatePolicyManager alloc] init]; } + _userData = web::SerializableUserData::Create(); + _userData->Decode(decoder); } return self; } @@ -82,6 +105,8 @@ [coder encodeObject:self.itemStorages forKey:kItemStoragesKey]; [coder encodeObject:self.sessionCertificatePolicyManager forKey:kCertificatePolicyManagerKey]; + if (_userData) + _userData->Encode(coder); // rendererInitiated is deliberately not preserved, as upstream. }
diff --git a/ios/web/public/serializable_user_data_manager.h b/ios/web/public/serializable_user_data_manager.h new file mode 100644 index 0000000..d8a8596 --- /dev/null +++ b/ios/web/public/serializable_user_data_manager.h
@@ -0,0 +1,54 @@ +// 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. + +#ifndef IOS_WEB_PUBLIC_SERIALIZABLE_USER_DATA_MANAGER_H_ +#define IOS_WEB_PUBLIC_SERIALIZABLE_USER_DATA_MANAGER_H_ + +#import <Foundation/Foundation.h> +#include <memory> + +namespace web { + +class WebState; + +// Class used to serialize values added to SerializableUserDataManager. +class SerializableUserData { + public: + // Factory method. + static std::unique_ptr<SerializableUserData> Create(); + + // Encodes the data with |coder|. + virtual void Encode(NSCoder* coder) = 0; + + // Decodes the data from |coder|. + virtual void Decode(NSCoder* coder) = 0; +}; + +// Class that can be used to add serializable user data to a WebState. +class SerializableUserDataManager { + public: + // Returns the SerializableUserDataManager instance associated with + // |web_state|, instantiating one if necessary. + static SerializableUserDataManager* FromWebState(web::WebState* web_state); + + // Adds |data| to the user data, allowing it to be encoded under |key|. + // |data| is expected to be non-nil. If |key| has already been used, its + // associated value will be overwritten. + virtual void AddSerializableData(id<NSCoding> data, NSString* key) = 0; + + // Returns the value that has been stored under |key|. + virtual id<NSCoding> GetValueForSerializationKey(NSString* key) = 0; + + // Creates a SerializableUserData that can be used to encode the values added + // to the manager. + virtual std::unique_ptr<SerializableUserData> CreateSerializableUserData() + const = 0; + + // Adds the values decoded from |data| to the manager. + virtual void AddSerializableUserData(SerializableUserData* data) = 0; +}; + +} // namespace web + +#endif // IOS_WEB_PUBLIC_SERIALIZABLE_USER_DATA_MANAGER_H_
diff --git a/ios/web/public/serializable_user_data_manager_unittest.mm b/ios/web/public/serializable_user_data_manager_unittest.mm new file mode 100644 index 0000000..90d4019f --- /dev/null +++ b/ios/web/public/serializable_user_data_manager_unittest.mm
@@ -0,0 +1,64 @@ +// 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. + +#import "ios/web/public/serializable_user_data_manager.h" + +#import "base/mac/scoped_nsobject.h" +#import "ios/web/public/test/fakes/test_web_state.h" +#import "testing/gtest_mac.h" +#include "testing/platform_test.h" + +namespace { +// User Data and Key to use for tests. +NSString* const kTestUserData = @"TestUserData"; +NSString* const kTestUserDataKey = @"TestUserDataKey"; +} // namespace + +class SerializableUserDataManagerTest : public PlatformTest { + protected: + // Convenience getter for the user data manager. + web::SerializableUserDataManager* manager() { + return web::SerializableUserDataManager::FromWebState(&web_state_); + } + + web::TestWebState web_state_; +}; + +// Tests that serializable data can be successfully added and read. +TEST_F(SerializableUserDataManagerTest, SetAndReadData) { + manager()->AddSerializableData(kTestUserData, kTestUserDataKey); + id value = manager()->GetValueForSerializationKey(kTestUserDataKey); + EXPECT_NSEQ(value, kTestUserData); +} + +// Tests that SerializableUserData can successfully encode and decode. +TEST_F(SerializableUserDataManagerTest, EncodeDecode) { + // Create a SerializableUserData instance for the test data. + manager()->AddSerializableData(kTestUserData, kTestUserDataKey); + std::unique_ptr<web::SerializableUserData> user_data = + manager()->CreateSerializableUserData(); + + // Archive the serializable user data. + base::scoped_nsobject<NSMutableData> data([[NSMutableData alloc] init]); + base::scoped_nsobject<NSKeyedArchiver> archiver( + [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]); + user_data->Encode(archiver); + [archiver finishEncoding]; + + // Create a new SerializableUserData by unarchiving. + base::scoped_nsobject<NSKeyedUnarchiver> unarchiver( + [[NSKeyedUnarchiver alloc] initForReadingWithData:data]); + std::unique_ptr<web::SerializableUserData> decoded_data = + web::SerializableUserData::Create(); + decoded_data->Decode(unarchiver); + + // Add the decoded user data to a new WebState and verify its contents. + web::TestWebState decoded_web_state; + web::SerializableUserDataManager* decoded_manager = + web::SerializableUserDataManager::FromWebState(&decoded_web_state); + decoded_manager->AddSerializableUserData(decoded_data.get()); + id decoded_value = + decoded_manager->GetValueForSerializationKey(kTestUserDataKey); + EXPECT_NSEQ(decoded_value, kTestUserData); +}
diff --git a/ios/web/public/test/fakes/test_web_state.h b/ios/web/public/test/fakes/test_web_state.h index 15a8354..7b27256 100644 --- a/ios/web/public/test/fakes/test_web_state.h +++ b/ios/web/public/test/fakes/test_web_state.h
@@ -38,7 +38,7 @@ void Stop() override {} const NavigationManager* GetNavigationManager() const override; NavigationManager* GetNavigationManager() override; - CRWNavigationManagerStorage* BuildSerializedNavigationManager() override; + CRWSessionStorage* BuildSessionStorage() override; CRWJSInjectionReceiver* GetJSInjectionReceiver() const override; void ExecuteJavaScript(const base::string16& javascript) override; void ExecuteJavaScript(const base::string16& javascript,
diff --git a/ios/web/public/test/fakes/test_web_state.mm b/ios/web/public/test/fakes/test_web_state.mm index 9b821db7..3ef1a84 100644 --- a/ios/web/public/test/fakes/test_web_state.mm +++ b/ios/web/public/test/fakes/test_web_state.mm
@@ -68,7 +68,7 @@ return navigation_manager_.get(); } -CRWNavigationManagerStorage* TestWebState::BuildSerializedNavigationManager() { +CRWSessionStorage* TestWebState::BuildSessionStorage() { return nil; }
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h index 9ee59870..ec3f464 100644 --- a/ios/web/public/web_state/web_state.h +++ b/ios/web/public/web_state/web_state.h
@@ -24,7 +24,7 @@ class SkBitmap; @class CRWJSInjectionReceiver; -@class CRWNavigationManagerStorage; +@class CRWSessionStorage; @protocol CRWScrollableContent; @protocol CRWWebViewProxy; typedef id<CRWWebViewProxy> CRWWebViewProxyType; @@ -100,9 +100,8 @@ // Creates a new WebState. static std::unique_ptr<WebState> Create(const CreateParams& params); // Creates a new WebState from a serialized NavigationManager. - static std::unique_ptr<WebState> Create( - const CreateParams& params, - CRWNavigationManagerStorage* session_storage); + static std::unique_ptr<WebState> Create(const CreateParams& params, + CRWSessionStorage* session_storage); ~WebState() override {} @@ -140,9 +139,9 @@ virtual const NavigationManager* GetNavigationManager() const = 0; virtual NavigationManager* GetNavigationManager() = 0; - // Creates a serialized version of the NavigationManager. The returned value + // Creates a serializable representation of the session. The returned value // is autoreleased. - virtual CRWNavigationManagerStorage* BuildSerializedNavigationManager() = 0; + virtual CRWSessionStorage* BuildSessionStorage() = 0; // Gets the CRWJSInjectionReceiver associated with this WebState. virtual CRWJSInjectionReceiver* GetJSInjectionReceiver() const = 0;
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h index 28fa5c79..905e516 100644 --- a/ios/web/web_state/web_state_impl.h +++ b/ios/web/web_state/web_state_impl.h
@@ -25,7 +25,7 @@ #import "ios/web/public/web_state/web_state_delegate.h" #include "url/gurl.h" -@class CRWNavigationManagerStorage; +@class CRWSessionStorage; @class CRWWebController; @protocol CRWWebViewProxy; @class NSURLRequest; @@ -66,8 +66,7 @@ // Constructor for WebStateImpls created for new sessions. WebStateImpl(BrowserState* browser_state); // Constructor for WebStatesImpls created for deserialized sessions - WebStateImpl(BrowserState* browser_state, - CRWNavigationManagerStorage* session_storage); + WebStateImpl(BrowserState* browser_state, CRWSessionStorage* session_storage); ~WebStateImpl() override; // Gets/Sets the CRWWebController that backs this object. @@ -204,7 +203,7 @@ void Stop() override; const NavigationManager* GetNavigationManager() const override; NavigationManager* GetNavigationManager() override; - CRWNavigationManagerStorage* BuildSerializedNavigationManager() override; + CRWSessionStorage* BuildSessionStorage() override; CRWJSInjectionReceiver* GetJSInjectionReceiver() const override; void ExecuteJavaScript(const base::string16& javascript) override; void ExecuteJavaScript(const base::string16& javascript, @@ -282,6 +281,10 @@ void RemovePolicyDecider(WebStatePolicyDecider* decider) override; private: + // The SessionStorageBuilder functions require access to private variables of + // WebStateImpl. + friend SessionStorageBuilder; + // Creates a WebUIIOS object for |url| that is owned by the caller. Returns // nullptr if |url| does not correspond to a WebUI page. std::unique_ptr<web::WebUIIOS> CreateWebUIIOS(const GURL& url);
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm index 864fee3..99a3dfb 100644 --- a/ios/web/web_state/web_state_impl.mm +++ b/ios/web/web_state/web_state_impl.mm
@@ -15,9 +15,9 @@ #import "ios/web/navigation/crw_session_controller.h" #import "ios/web/navigation/crw_session_entry.h" #import "ios/web/navigation/navigation_item_impl.h" -#import "ios/web/navigation/navigation_manager_storage_builder.h" +#import "ios/web/navigation/session_storage_builder.h" #include "ios/web/public/browser_state.h" -#import "ios/web/public/crw_navigation_manager_storage.h" +#import "ios/web/public/crw_session_storage.h" #import "ios/web/public/image_fetcher/image_data_fetcher.h" #import "ios/web/public/java_script_dialog_presenter.h" #import "ios/web/public/navigation_item.h" @@ -66,9 +66,8 @@ } /* static */ -std::unique_ptr<WebState> WebState::Create( - const CreateParams& params, - CRWNavigationManagerStorage* session_storage) { +std::unique_ptr<WebState> WebState::Create(const CreateParams& params, + CRWSessionStorage* session_storage) { std::unique_ptr<WebStateImpl> web_state( new WebStateImpl(params.browser_state, session_storage)); @@ -82,7 +81,7 @@ : WebStateImpl(browser_state, nullptr) {} WebStateImpl::WebStateImpl(BrowserState* browser_state, - CRWNavigationManagerStorage* session_storage) + CRWSessionStorage* session_storage) : delegate_(nullptr), is_loading_(false), is_being_destroyed_(false), @@ -92,9 +91,8 @@ weak_factory_(this) { // Create or deserialize the NavigationManager. if (session_storage) { - NavigationManagerStorageBuilder session_storage_builder; - navigation_manager_ = - session_storage_builder.BuildNavigationManagerImpl(session_storage); + SessionStorageBuilder session_storage_builder; + session_storage_builder.ExtractSessionState(this, session_storage); } else { navigation_manager_.reset(new NavigationManagerImpl()); } @@ -656,9 +654,9 @@ return &GetNavigationManagerImpl(); } -CRWNavigationManagerStorage* WebStateImpl::BuildSerializedNavigationManager() { - NavigationManagerStorageBuilder session_storage_builder; - return session_storage_builder.BuildStorage(navigation_manager_.get()); +CRWSessionStorage* WebStateImpl::BuildSessionStorage() { + SessionStorageBuilder session_storage_builder; + return session_storage_builder.BuildStorage(this); } CRWJSInjectionReceiver* WebStateImpl::GetJSInjectionReceiver() const {
diff --git a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html new file mode 100644 index 0000000..bed039a2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<script src =../../resources/testharness.js></script> +<script src =../../resources/testharnessreport.js></script> +<script> + +async_test(t => { + var canvas = document.createElement('canvas'); + + var recorder = new MediaRecorder(canvas.captureStream()); + recorder.ondataavailable = function() { + t.step_func_done(function() { + assert_true(event.data.size > 0, 'Recorded data size should be > 0'); + })(); + recorder.stop(); + } + recorder.start(0); + + var ctx = canvas.getContext('2d'); + ctx.fillStyle = 'green'; + ctx.fillRect(0, 0, canvas.width, canvas.height); +}, "Verify that drawing to a 2D canvas that is not attached to the DOM dispatches a frame to an attached MediaRecorder." ); + +async_test(t => { + var canvas = document.createElement('canvas'); + + var recorder = new MediaRecorder(canvas.captureStream()); + recorder.ondataavailable = function() { + t.step_func_done(function() { + assert_true(event.data.size > 0, 'Recorded data size should be > 0'); + })(); + recorder.stop(); + } + recorder.start(0); + + var gl = canvas.getContext('webgl'); + gl.clearColor(0, 1, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); +}, "Verify that drawing to a webgl canvas that is not attached to the DOM dispatches a frame to an attached MediaRecorder." ); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index eba91ca..5e84495 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -325,8 +325,47 @@ buffer()->didDraw(rect); } -void HTMLCanvasElement::didFinalizeFrame() { +void HTMLCanvasElement::finalizeFrame() { + if (hasImageBuffer()) + m_imageBuffer->finalizeFrame(); + m_context->incrementFrameCount(); notifyListenersCanvasChanged(); +} + +void HTMLCanvasElement::didDisableAcceleration() { + // We must force a paint invalidation on the canvas even if it's + // content did not change because it layer was destroyed. + didDraw(FloatRect(0, 0, size().width(), size().height())); +} + +void HTMLCanvasElement::restoreCanvasMatrixClipStack(SkCanvas* canvas) const { + if (m_context) + m_context->restoreCanvasMatrixClipStack(canvas); +} + +void HTMLCanvasElement::doDeferredPaintInvalidation() { + DCHECK(!m_dirtyRect.isEmpty()); + if (m_context->is2d()) { + FloatRect srcRect(0, 0, size().width(), size().height()); + m_dirtyRect.intersect(srcRect); + LayoutBox* lb = layoutBox(); + FloatRect invalidationRect; + if (lb) { + FloatRect mappedDirtyRect = + mapRect(m_dirtyRect, srcRect, FloatRect(lb->contentBoxRect())); + if (m_context->isAccelerated()) { + // Accelerated 2D canvases need the dirty rect to be expressed relative + // to the content box, as opposed to the layout box. + mappedDirtyRect.move(-lb->contentBoxOffset()); + } + invalidationRect = mappedDirtyRect; + } else { + invalidationRect = m_dirtyRect; + } + if (hasImageBuffer()) { + m_imageBuffer->doPaintInvalidation(invalidationRect); + } + } if (m_dirtyRect.isEmpty()) return; @@ -388,48 +427,6 @@ m_pendingRenderingModeSwitch = false; } - m_context->incrementFrameCount(); -} - -void HTMLCanvasElement::didDisableAcceleration() { - // We must force a paint invalidation on the canvas even if it's - // content did not change because it layer was destroyed. - didDraw(FloatRect(0, 0, size().width(), size().height())); -} - -void HTMLCanvasElement::restoreCanvasMatrixClipStack( - PaintCanvas* canvas) const { - if (m_context) - m_context->restoreCanvasMatrixClipStack(canvas); -} - -void HTMLCanvasElement::doDeferredPaintInvalidation() { - DCHECK(!m_dirtyRect.isEmpty()); - if (!m_context->is2d()) { - didFinalizeFrame(); - } else { - FloatRect srcRect(0, 0, size().width(), size().height()); - m_dirtyRect.intersect(srcRect); - LayoutBox* lb = layoutBox(); - FloatRect invalidationRect; - if (lb) { - FloatRect mappedDirtyRect = - mapRect(m_dirtyRect, srcRect, FloatRect(lb->contentBoxRect())); - if (m_context->isAccelerated()) { - // Accelerated 2D canvases need the dirty rect to be expressed relative - // to the content box, as opposed to the layout box. - mappedDirtyRect.move(-lb->contentBoxOffset()); - } - invalidationRect = mappedDirtyRect; - } else { - invalidationRect = m_dirtyRect; - } - if (hasImageBuffer()) { - m_imageBuffer->finalizeFrame(invalidationRect); - } else { - didFinalizeFrame(); - } - } DCHECK(m_dirtyRect.isEmpty()); }
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h index 70ee8cb..4c9dfeb6 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -170,6 +170,12 @@ InsertionNotificationRequest insertedInto(ContainerNode*) override; + bool isDirty() { return !m_dirtyRect.isEmpty(); } + + void doDeferredPaintInvalidation(); + + void finalizeFrame(); + // ContextLifecycleObserver and PageVisibilityObserver implementation void contextDestroyed(ExecutionContext*) override; @@ -194,13 +200,9 @@ // ImageBufferClient implementation void notifySurfaceInvalid() override; - bool isDirty() override { return !m_dirtyRect.isEmpty(); } void didDisableAcceleration() override; - void didFinalizeFrame() override; void restoreCanvasMatrixClipStack(PaintCanvas*) const override; - void doDeferredPaintInvalidation(); - // ImageBitmapSource implementation IntSize bitmapSourceSize() const override; ScriptPromise createImageBitmap(ScriptState*,
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp index 7fdd8f3d..ce4019c1 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp +++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp
@@ -29,6 +29,7 @@ #include "core/html/canvas/CanvasImageSource.h" #include "platform/RuntimeEnabledFeatures.h" #include "platform/weborigin/SecurityOrigin.h" +#include "public/platform/Platform.h" constexpr const char* kLegacyCanvasColorSpaceName = "legacy-srgb"; constexpr const char* kSRGBCanvasColorSpaceName = "srgb"; @@ -127,11 +128,15 @@ } void CanvasRenderingContext::dispose() { + if (m_finalizeFrameScheduled) { + Platform::current()->currentThread()->removeTaskObserver(this); + } + // HTMLCanvasElement and CanvasRenderingContext have a circular reference. // When the pair is no longer reachable, their destruction order is non- // deterministic, so the first of the two to be destroyed needs to notify // the other in order to break the circular reference. This is to avoid - // an error when CanvasRenderingContext2D::didProcessTask() is invoked + // an error when CanvasRenderingContext::didProcessTask() is invoked // after the HTMLCanvasElement is destroyed. if (canvas()) { canvas()->detachContext(); @@ -143,6 +148,26 @@ } } +void CanvasRenderingContext::didDraw(const SkIRect& dirtyRect) { + canvas()->didDraw(SkRect::Make(dirtyRect)); + if (!m_finalizeFrameScheduled) { + m_finalizeFrameScheduled = true; + Platform::current()->currentThread()->addTaskObserver(this); + } +} + +void CanvasRenderingContext::didProcessTask() { + Platform::current()->currentThread()->removeTaskObserver(this); + m_finalizeFrameScheduled = false; + + if (!canvas()) + return; + + // The end of a script task that drew content to the canvas is the point + // at which the current frame may be considered complete. + canvas()->finalizeFrame(); +} + CanvasRenderingContext::ContextType CanvasRenderingContext::contextTypeFromId( const String& id) { if (id == "2d")
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h index 406457d..b420788 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h +++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -32,6 +32,7 @@ #include "core/layout/HitTestCanvasResult.h" #include "core/offscreencanvas/OffscreenCanvas.h" #include "platform/graphics/ColorBehavior.h" +#include "public/platform/WebThread.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "wtf/HashSet.h" @@ -56,7 +57,8 @@ class CORE_EXPORT CanvasRenderingContext : public GarbageCollectedFinalized<CanvasRenderingContext>, - public ScriptWrappable { + public ScriptWrappable, + public WebThread::TaskObserver { WTF_MAKE_NONCOPYABLE(CanvasRenderingContext); USING_PRE_FINALIZER(CanvasRenderingContext, dispose); @@ -109,6 +111,7 @@ NOTREACHED(); } virtual bool isPaintable() const = 0; + virtual void didDraw(const SkIRect& dirtyRect); // Return true if the content is updated. virtual bool paintRenderingResultsToCanvas(SourceDrawingBuffer) { @@ -131,6 +134,10 @@ }; virtual void loseContext(LostContextMode) {} + // WebThread::TaskObserver implementation + void didProcessTask() override; + void willProcessTask() final {} + // Canvas2D-specific interface virtual bool is2d() const { return false; } virtual void restoreCanvasMatrixClipStack(PaintCanvas*) const {} @@ -199,6 +206,7 @@ HashSet<String> m_dirtyURLs; CanvasColorSpace m_colorSpace; CanvasContextCreationAttributes m_creationAttributes; + bool m_finalizeFrameScheduled = false; }; } // namespace blink
diff --git a/third_party/WebKit/Source/devtools/front_end/perf_ui/ChartViewport.js b/third_party/WebKit/Source/devtools/front_end/perf_ui/ChartViewport.js index ede93ece8..0a1353e 100644 --- a/third_party/WebKit/Source/devtools/front_end/perf_ui/ChartViewport.js +++ b/third_party/WebKit/Source/devtools/front_end/perf_ui/ChartViewport.js
@@ -86,6 +86,7 @@ this._totalHeight = 0; this._pendingAnimationTimeLeft = 0; this._pendingAnimationTimeRight = 0; + this._updateContentElementSize(); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js b/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js index 2636587..2d334da8 100644 --- a/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js +++ b/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js
@@ -1201,12 +1201,14 @@ */ reset() { super.reset(); + this._rawTimelineData = null; + this._rawTimelineDataLength = 0; this._highlightedMarkerIndex = -1; this._highlightedEntryIndex = -1; this._selectedEntryIndex = -1; /** @type {!Map<string,!Map<string,number>>} */ this._textWidth = new Map(); - this.update(); + this.scheduleUpdate(); } _enabled() {
diff --git a/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js b/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js index b61661f..bfc5cd0 100644 --- a/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js +++ b/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js
@@ -260,7 +260,7 @@ for (var i = 0; i < this._overviewControls.length; ++i) this._overviewControls[i].reset(); this._popoverHelper.hidePopover(); - this._update(); + this.scheduleUpdate(); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineDetailsView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineDetailsView.js index 74c2ebb..3242212c 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineDetailsView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineDetailsView.js
@@ -56,6 +56,8 @@ this._model = model; this._tabbedPane.closeTabs( [Timeline.TimelineDetailsView.Tab.PaintProfiler, Timeline.TimelineDetailsView.Tab.LayerViewer], false); + for (var view of this._rangeDetailViews.values()) + view.setModel(model); this._lazyPaintProfilerView = null; this._lazyLayersView = null; }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js index e4729621..5e9b0bb 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js
@@ -119,12 +119,11 @@ this._mainView.alwaysShowVerticalScroll(); this._mainView.enableRuler(false); - var networkViewGroupExpansionSetting = + this._networkViewGroupExpansionSetting = Common.settings.createSetting('timelineFlamechartNetworkViewGroupExpansion', {}); this._networkDataProvider = new Timeline.TimelineFlameChartNetworkDataProvider(); - this._networkView = new PerfUI.FlameChart(this._networkDataProvider, this, networkViewGroupExpansionSetting); + this._networkView = new PerfUI.FlameChart(this._networkDataProvider, this, this._networkViewGroupExpansionSetting); this._networkView.alwaysShowVerticalScroll(); - networkViewGroupExpansionSetting.addChangeListener(this.resizeToPreferredHeights.bind(this)); this._networkPane = new UI.VBox(); this._networkPane.setMinimumSize(23, 23); @@ -201,18 +200,13 @@ _refresh() { this._dataProvider.setModel(this._model); - this._mainView.reset(); - this._networkDataProvider.setModel(this._model); - this._networkView.reset(); - - this._detailsView.setModel(this._model); + if (this._detailsView) + this._detailsView.setModel(this._model); this._nextExtensionIndex = 0; this._appendExtensionData(); - this._mainView.scheduleUpdate(); - this._networkDataProvider.reset(); if (this._networkDataProvider.isEmpty()) { this._mainView.enableRuler(true); this._splitWidget.hideSidebar(); @@ -221,7 +215,8 @@ this._splitWidget.showBoth(); this.resizeToPreferredHeights(); } - this._networkView.scheduleUpdate(); + this._mainView.reset(); + this._networkView.reset(); } _appendExtensionData() { @@ -250,6 +245,7 @@ * @override */ willHide() { + this._networkViewGroupExpansionSetting.removeChangeListener(this.resizeToPreferredHeights, this); Bindings.blackboxManager.removeChangeListener(this._boundRefresh); } @@ -257,7 +253,10 @@ * @override */ wasShown() { + this._networkViewGroupExpansionSetting.addChangeListener(this.resizeToPreferredHeights, this); Bindings.blackboxManager.addChangeListener(this._boundRefresh); + if (this._needsResizeToPreferredHeights) + this.resizeToPreferredHeights(); this._mainView.scheduleUpdate(); this._networkView.scheduleUpdate(); } @@ -320,6 +319,11 @@ } resizeToPreferredHeights() { + if (!this.isShowing()) { + this._needsResizeToPreferredHeights = true; + return; + } + this._needsResizeToPreferredHeights = false; this._networkPane.element.classList.toggle( 'timeline-network-resizer-disabled', !this._networkDataProvider.isExpanded()); this._splitWidget.setSidebarSize(
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js index 9250b3f..d066c15 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js
@@ -9,9 +9,7 @@ Timeline.TimelineFlameChartNetworkDataProvider = class { constructor() { this._font = '11px ' + Host.fontFamily(); - /** @type {?TimelineModel.TimelineModel} */ - this._model = null; - this.reset(); + this.setModel(null); this._style = { padding: 4, height: 17, @@ -32,6 +30,10 @@ */ setModel(performanceModel) { this._model = performanceModel && performanceModel.timelineModel(); + this._maxLevel = 0; + this._timelineData = null; + /** @type {!Array<!TimelineModel.TimelineModel.NetworkRequest>} */ + this._requests = []; } /** @@ -81,13 +83,6 @@ return this._timeSpan; } - reset() { - this._maxLevel = 0; - this._timelineData = null; - /** @type {!Array<!TimelineModel.TimelineModel.NetworkRequest>} */ - this._requests = []; - } - /** * @param {number} startTime * @param {number} endTime
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js index 57e5e602..acdbcf2 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -615,6 +615,7 @@ this._performanceModel.dispose(); this._performanceModel = model; this._currentViews.forEach(view => view.setModel(this._performanceModel)); + this._overviewPane.reset(); if (model) { this._overviewPane.setBounds( @@ -622,6 +623,7 @@ } for (var control of this._overviewControls) control.setModel(model); + if (model) { var cpuProfiles = model.timelineModel().cpuProfiles(); cpuProfiles.forEach(profile => PerfUI.LineLevelProfile.instance().appendCPUProfile(profile)); @@ -632,8 +634,13 @@ this.requestWindowTimes(0, Infinity); } this._overviewPane.scheduleUpdate(); + if (this._detailsView) + this._detailsView.setModel(model); + this.select(null); this._updateSearchHighlight(false, true); + if (this._flameChart) + this._flameChart.resizeToPreferredHeights(); } /** @@ -769,8 +776,6 @@ this._backingStorage = backingStorage; this._setModel(performanceModel); - if (this._flameChart) - this._flameChart.resizeToPreferredHeights(); if (this._detailsSplitWidget) this._detailsSplitWidget.showBoth(); }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js index 8f038cc1..c065640 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -30,6 +30,7 @@ */ setModel(model) { this._model = model; + this.refreshTree(); } /**
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp index 493afde..882496e8 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -134,7 +134,7 @@ canvas->document().frame()), this, &CanvasRenderingContext2D::tryRestoreContextEvent), - m_pruneLocalFontCacheScheduled(false) { + m_shouldPruneLocalFontCache(false) { if (document.settings() && document.settings()->getAntialiasedClips2dCanvasEnabled()) m_clipAntialiasing = AntiAliased; @@ -149,11 +149,6 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D() {} -void CanvasRenderingContext2D::dispose() { - if (m_pruneLocalFontCacheScheduled) - Platform::current()->currentThread()->removeTaskObserver(this); -} - void CanvasRenderingContext2D::validateStateStack() const { #if DCHECK_IS_ON() if (PaintCanvas* skCanvas = canvas()->existingDrawingCanvas()) { @@ -362,7 +357,7 @@ buffer->setHasExpensiveOp(); } - canvas()->didDraw(SkRect::Make(dirtyRect)); + CanvasRenderingContext::didDraw(dirtyRect); } bool CanvasRenderingContext2D::stateHasFilter() { @@ -490,7 +485,7 @@ DCHECK(!m_fontLRUList.contains(newFont)); m_fontLRUList.add(newFont); pruneLocalFontCache(canvasFontCache->hardMaxFonts()); // hard limit - schedulePruneLocalFontCacheIfNeeded(); // soft limit + m_shouldPruneLocalFontCache = true; // apply soft limit modifiableState().setFont( fontStyle->font(), canvas()->document().styleEngine().fontSelector()); } @@ -508,31 +503,19 @@ modifiableState().setUnparsedFont(newFontSafeCopy); } -void CanvasRenderingContext2D::schedulePruneLocalFontCacheIfNeeded() { - if (m_pruneLocalFontCacheScheduled) - return; - m_pruneLocalFontCacheScheduled = true; - Platform::current()->currentThread()->addTaskObserver(this); -} - void CanvasRenderingContext2D::didProcessTask() { - Platform::current()->currentThread()->removeTaskObserver(this); - + CanvasRenderingContext::didProcessTask(); // This should be the only place where canvas() needs to be checked for - // nullness because the circular refence with HTMLCanvasElement mean the - // canvas and the context keep each other alive as long as the pair is - // referenced the task observer is the only persisten refernce to this object - // that is not traced, so didProcessTask() may be call at a time when the + // nullness because the circular refence with HTMLCanvasElement means the + // canvas and the context keep each other alive. As long as the pair is + // referenced, the task observer is the only persistent refernce to this + // object + // that is not traced, so didProcessTask() may be called at a time when the // canvas has been garbage collected but not the context. - if (!canvas()) - return; - - // The rendering surface needs to be prepared now because it will be too late - // to create a layer once we are in the paint invalidation phase. - canvas()->prepareSurfaceForPaintingIfNeeded(); - - pruneLocalFontCache(canvas()->document().canvasFontCache()->maxFonts()); - m_pruneLocalFontCacheScheduled = false; + if (m_shouldPruneLocalFontCache && canvas()) { + m_shouldPruneLocalFontCache = false; + pruneLocalFontCache(canvas()->document().canvasFontCache()->maxFonts()); + } } void CanvasRenderingContext2D::pruneLocalFontCache(size_t targetSize) {
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h index 357c848..919bc97 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
@@ -67,11 +67,9 @@ class MODULES_EXPORT CanvasRenderingContext2D final : public CanvasRenderingContext, public BaseRenderingContext2D, - public WebThread::TaskObserver, public SVGResourceClient { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(CanvasRenderingContext2D); - USING_PRE_FINALIZER(CanvasRenderingContext2D, dispose); public: class Factory : public CanvasRenderingContextFactory { @@ -142,8 +140,7 @@ void restoreCanvasMatrixClipStack(PaintCanvas*) const override; // TaskObserver implementation - void didProcessTask() override; - void willProcessTask() override {} + void didProcessTask() final; void styleDidChange(const ComputedStyle* oldStyle, const ComputedStyle& newStyle) override; @@ -179,7 +176,9 @@ void disableDeferral(DisableDeferralReason) final; AffineTransform baseTransform() const final; - void didDraw(const SkIRect& dirtyRect) final; + void didDraw(const SkIRect& dirtyRect) final; // overrides + // BaseRenderingContext2D and + // CanvasRenderingContext bool stateHasFilter() final; sk_sp<SkImageFilter> stateGetFilter() final; @@ -208,14 +207,11 @@ const CanvasContextCreationAttributes& attrs, Document&); - void dispose(); - void dispatchContextLostEvent(TimerBase*); void dispatchContextRestoredEvent(TimerBase*); void tryRestoreContextEvent(TimerBase*); void pruneLocalFontCache(size_t targetSize); - void schedulePruneLocalFontCacheIfNeeded(); void scrollPathIntoViewInternal(const Path&); @@ -257,7 +253,7 @@ FilterOperations m_filterOperations; HashMap<String, Font> m_fontsResolvedUsingCurrentStyle; - bool m_pruneLocalFontCacheScheduled; + bool m_shouldPruneLocalFontCache; ListHashSet<String> m_fontLRUList; };
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp index 0863555..edd8a49 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -822,7 +822,7 @@ context2d()->save(); context2d()->translate(1.0f, 0.0f); } - canvasElement().doDeferredPaintInvalidation(); // To close the current frame + canvasElement().finalizeFrame(); // To close the current frame } TEST_F(CanvasRenderingContext2DTest, FallbackWithLargeState) { @@ -841,7 +841,7 @@ context2d()->save(); context2d()->translate(1.0f, 0.0f); } - canvasElement().doDeferredPaintInvalidation(); // To close the current frame + canvasElement().finalizeFrame(); // To close the current frame } TEST_F(CanvasRenderingContext2DTest, OpaqueDisplayListFallsBackForText) {
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h index 37040aa4..cd30654 100644 --- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h +++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
@@ -72,7 +72,9 @@ void disableDeferral(DisableDeferralReason) final; AffineTransform baseTransform() const final; - void didDraw(const SkIRect& dirtyRect) final; + void didDraw(const SkIRect& dirtyRect) final; // overrides + // BaseRenderingContext2D and + // CanvasRenderingContext bool stateHasFilter() final; sk_sp<SkImageFilter> stateGetFilter() final;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp index 10c2c319..010b60b6f 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -1399,15 +1399,12 @@ LayoutBox* layoutBox = canvas()->layoutBox(); if (layoutBox && layoutBox->hasAcceleratedCompositing()) { - m_markedCanvasDirty = true; - canvas()->clearCopiedImage(); layoutBox->contentChanged(changeType); - } else { - if (!m_markedCanvasDirty) { - m_markedCanvasDirty = true; - canvas()->didDraw( - FloatRect(FloatPoint(0, 0), FloatSize(clampedCanvasSize()))); - } + } + if (!m_markedCanvasDirty) { + m_markedCanvasDirty = true; + IntSize canvasSize = clampedCanvasSize(); + didDraw(SkIRect::MakeXYWH(0, 0, canvasSize.width(), canvasSize.height())); } }
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h index f7d04ef..67c11ffd4 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h
@@ -80,8 +80,9 @@ ~Canvas2DImageBufferSurface() override { m_layerBridge->beginDestruction(); } // ImageBufferSurface implementation - void finalizeFrame(const FloatRect& dirtyRect) override { - m_layerBridge->finalizeFrame(dirtyRect); + void finalizeFrame() override { m_layerBridge->finalizeFrame(); } + void doPaintInvalidation(const FloatRect& dirtyRect) override { + m_layerBridge->doPaintInvalidation(dirtyRect); } void willOverwriteCanvas() override { m_layerBridge->willOverwriteCanvas(); } PaintCanvas* canvas() override { return m_layerBridge->canvas(); } @@ -102,9 +103,6 @@ void didDraw(const FloatRect& rect) override { m_layerBridge->didDraw(rect); } void flush(FlushReason) override { m_layerBridge->flush(); } void flushGpu(FlushReason) override { m_layerBridge->flushGpu(); } - void prepareSurfaceForPaintingIfNeeded() override { - m_layerBridge->prepareSurfaceForPaintingIfNeeded(); - } bool writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp index dab2786f..cbd9476bf 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -853,9 +853,9 @@ bool Canvas2DLayerBridge::restoreSurface() { DCHECK(!m_destructionInProgress); - if (m_destructionInProgress) + if (m_destructionInProgress || !isAccelerated()) return false; - DCHECK(isAccelerated() && !m_surface); + DCHECK(!m_surface); gpu::gles2::GLES2Interface* sharedGL = nullptr; m_layer->clearTexture(); @@ -899,12 +899,6 @@ // 4. Here. return false; } - DCHECK(isAccelerated() || isHibernating() || m_softwareRenderingWhileHidden); - - // if hibernating but not hidden, we want to wake up from - // hibernation - if ((isHibernating() || m_softwareRenderingWhileHidden) && isHidden()) - return false; // If the context is lost, we don't know if we should be producing GPU or // software frames, until we get a new context, since the compositor will @@ -914,6 +908,13 @@ GL_NO_ERROR) return false; + DCHECK(isAccelerated() || isHibernating() || m_softwareRenderingWhileHidden); + + // if hibernating but not hidden, we want to wake up from + // hibernation + if ((isHibernating() || m_softwareRenderingWhileHidden) && isHidden()) + return false; + sk_sp<SkImage> image = newImageSnapshot(PreferAcceleration, SnapshotReasonUnknown); if (!image || !image->getTexture()) @@ -1042,19 +1043,24 @@ m_didDrawSinceLastGpuFlush = true; } -void Canvas2DLayerBridge::prepareSurfaceForPaintingIfNeeded() { - getOrCreateSurface(PreferAcceleration); -} - -void Canvas2DLayerBridge::finalizeFrame(const FloatRect& dirtyRect) { +void Canvas2DLayerBridge::finalizeFrame() { DCHECK(!m_destructionInProgress); - if (m_layer && m_accelerationMode != DisableAcceleration) - m_layer->layer()->invalidateRect(enclosingIntRect(dirtyRect)); + + // Make sure surface is ready for painting: fix the rendering mode now + // because it will be too late during the paint invalidation phase. + getOrCreateSurface(PreferAcceleration); + if (m_rateLimiter) m_rateLimiter->reset(); m_renderingTaskCompletedForCurrentFrame = false; } +void Canvas2DLayerBridge::doPaintInvalidation(const FloatRect& dirtyRect) { + DCHECK(!m_destructionInProgress); + if (m_layer && m_accelerationMode != DisableAcceleration) + m_layer->layer()->invalidateRect(enclosingIntRect(dirtyRect)); +} + void Canvas2DLayerBridge::didProcessTask() { TRACE_EVENT0("cc", "Canvas2DLayerBridge::didProcessTask"); DCHECK(m_isRegisteredTaskObserver);
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h index aff8e6a7..d1a7f13 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -113,7 +113,8 @@ bool lostResource); // ImageBufferSurface implementation - void finalizeFrame(const FloatRect& dirtyRect); + void finalizeFrame(); + void doPaintInvalidation(const FloatRect& dirtyRect); void willWritePixels(); void willOverwriteAllPixels(); void willOverwriteCanvas(); @@ -134,7 +135,6 @@ int y); void flush(); void flushGpu(); - void prepareSurfaceForPaintingIfNeeded(); bool isHidden() { return m_isHidden; } OpacityMode opacityMode() { return m_opacityMode; } void dontUseIdleSchedulingForTesting() {
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp index 75010c0..d234255 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -240,9 +240,7 @@ Canvas2DLayerBridge::ForceAccelerationForTesting, gfx::ColorSpace::CreateSRGB(), false, kN32_SkColorType))); - // TODO(junov): The PrepareTextureMailbox() method will fail a DCHECK if we - // don't do this before calling it the first time when the context is lost. - bridge->prepareSurfaceForPaintingIfNeeded(); + EXPECT_TRUE(bridge->isAccelerated()); // When the context is lost we are not sure if we should still be producing // GL frames for the compositor or not, so fail to generate frames. @@ -263,10 +261,8 @@ Canvas2DLayerBridge::ForceAccelerationForTesting, gfx::ColorSpace::CreateSRGB(), false, kN32_SkColorType))); - // TODO(junov): The PrepareTextureMailbox() method will fail a DCHECK if we - // don't do this before calling it the first time when the context is lost. - bridge->prepareSurfaceForPaintingIfNeeded(); - + bridge->getOrCreateSurface(); + EXPECT_TRUE(bridge->checkSurfaceValid()); // When the context is lost we are not sure if we should still be producing // GL frames for the compositor or not, so fail to generate frames. gl.setIsContextLost(true); @@ -420,7 +416,7 @@ Canvas2DLayerBridge::EnableAcceleration); // draw+flush to trigger the creation of a GPU surface (*bridgePtr)->didDraw(FloatRect(0, 0, 1, 1)); - (*bridgePtr)->finalizeFrame(FloatRect(0, 0, 1, 1)); + (*bridgePtr)->finalizeFrame(); (*bridgePtr)->flush(); doneEvent->signal(); } @@ -679,7 +675,7 @@ void runRenderingTask(Canvas2DLayerBridge* bridge, WaitableEvent* doneEvent) { bridge->didDraw(FloatRect(0, 0, 1, 1)); - bridge->finalizeFrame(FloatRect(0, 0, 1, 1)); + bridge->finalizeFrame(); bridge->flush(); doneEvent->signal(); }
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp index fa041cb..2e38b19 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp +++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -148,18 +148,12 @@ return m_surface->isValid(); } -bool ImageBuffer::isDirty() { - return m_client ? m_client->isDirty() : false; +void ImageBuffer::finalizeFrame() { + m_surface->finalizeFrame(); } -void ImageBuffer::didFinalizeFrame() { - if (m_client) - m_client->didFinalizeFrame(); -} - -void ImageBuffer::finalizeFrame(const FloatRect& dirtyRect) { - m_surface->finalizeFrame(dirtyRect); - didFinalizeFrame(); +void ImageBuffer::doPaintInvalidation(const FloatRect& dirtyRect) { + m_surface->doPaintInvalidation(dirtyRect); } bool ImageBuffer::restoreSurface() const {
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h index 9c53f8c..8e38810 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h +++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
@@ -115,10 +115,8 @@ void disableDeferral(DisableDeferralReason) const; // Called at the end of a task that rendered a whole frame - void finalizeFrame(const FloatRect& dirtyRect); - void didFinalizeFrame(); - - bool isDirty(); + void finalizeFrame(); + void doPaintInvalidation(const FloatRect& dirtyRect); bool writePixels(const SkImageInfo&, const void* pixels,
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h b/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h index a256f53..25bbb3e4 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h +++ b/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h
@@ -40,9 +40,7 @@ public: virtual ~ImageBufferClient() {} virtual void notifySurfaceInvalid() = 0; - virtual bool isDirty() = 0; virtual void didDisableAcceleration() = 0; - virtual void didFinalizeFrame() = 0; virtual void restoreCanvasMatrixClipStack(PaintCanvas*) const = 0; };
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h index 870425fb..8ae2b2f 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h +++ b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h
@@ -75,7 +75,8 @@ virtual void setIsHidden(bool) {} virtual void setImageBuffer(ImageBuffer*) {} virtual sk_sp<PaintRecord> getRecord(); - virtual void finalizeFrame(const FloatRect& dirtyRect) {} + virtual void finalizeFrame() {} + virtual void doPaintInvalidation(const FloatRect& dirtyRect) {} virtual void draw(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect,
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp index 2afaaeeb..8e56c8c 100644 --- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp +++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
@@ -229,7 +229,6 @@ FallbackReason fallbackReason = FallbackReasonUnknown; bool canUseRecord = finalizeFrameInternal(&fallbackReason); - m_imageBuffer->didFinalizeFrame(); DCHECK(canUseRecord || m_fallbackFactory); @@ -242,9 +241,9 @@ return nullptr; } -void RecordingImageBufferSurface::finalizeFrame(const FloatRect& dirtyRect) { +void RecordingImageBufferSurface::finalizeFrame() { if (m_fallbackSurface) { - m_fallbackSurface->finalizeFrame(dirtyRect); + m_fallbackSurface->finalizeFrame(); return; } @@ -253,6 +252,13 @@ fallBackToRasterCanvas(fallbackReason); } +void RecordingImageBufferSurface::doPaintInvalidation( + const FloatRect& dirtyRect) { + if (m_fallbackSurface) { + m_fallbackSurface->doPaintInvalidation(dirtyRect); + } +} + static RecordingImageBufferSurface::FallbackReason flushReasonToFallbackReason( FlushReason reason) { switch (reason) { @@ -298,9 +304,8 @@ CHECK(m_currentFrame); DCHECK(m_currentFrame->getRecordingCanvas()); DCHECK(fallbackReason); - DCHECK_EQ(*fallbackReason, FallbackReasonUnknown); - - if (!m_imageBuffer->isDirty()) { + DCHECK(*fallbackReason == FallbackReasonUnknown); + if (!m_didRecordDrawCommandsInCurrentFrame) { if (!m_previousFrame) { // Create an initial blank frame m_previousFrame = m_currentFrame->finishRecordingAsPicture();
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h index c348e216..41ae58f 100644 --- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h +++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
@@ -65,7 +65,8 @@ int x, int y) override; void willOverwriteCanvas() override; - virtual void finalizeFrame(const FloatRect&); + void finalizeFrame() override; + void doPaintInvalidation(const FloatRect&) override; void setImageBuffer(ImageBuffer*) override; sk_sp<SkImage> newImageSnapshot(AccelerationHint, SnapshotReason) override; void draw(GraphicsContext&,
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp index 36f8203..47f063b 100644 --- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
@@ -25,51 +25,6 @@ namespace blink { -class FakeImageBufferClient : public ImageBufferClient, - public WebThread::TaskObserver { - public: - FakeImageBufferClient(ImageBuffer* imageBuffer) - : m_isDirty(false), m_imageBuffer(imageBuffer), m_frameCount(0) {} - - ~FakeImageBufferClient() override {} - - // ImageBufferClient implementation - void notifySurfaceInvalid() override {} - bool isDirty() override { return m_isDirty; } - void didDisableAcceleration() override {} - void didFinalizeFrame() override { - if (m_isDirty) { - Platform::current()->currentThread()->removeTaskObserver(this); - m_isDirty = false; - } - ++m_frameCount; - } - - // TaskObserver implementation - void willProcessTask() override { NOTREACHED(); } - void didProcessTask() override { - ASSERT_TRUE(m_isDirty); - FloatRect dirtyRect(0, 0, 1, 1); - m_imageBuffer->finalizeFrame(dirtyRect); - ASSERT_FALSE(m_isDirty); - } - void restoreCanvasMatrixClipStack(PaintCanvas*) const override {} - - void fakeDraw() { - if (m_isDirty) - return; - m_isDirty = true; - Platform::current()->currentThread()->addTaskObserver(this); - } - - int frameCount() { return m_frameCount; } - - private: - bool m_isDirty; - ImageBuffer* m_imageBuffer; - int m_frameCount; -}; - class MockSurfaceFactory : public RecordingImageBufferFallbackSurfaceFactory { public: MockSurfaceFactory() : m_createSurfaceCount(0) {} @@ -107,113 +62,13 @@ // properly initialized with a GraphicsContext m_imageBuffer = ImageBuffer::create(std::move(testSurface)); EXPECT_FALSE(!m_imageBuffer); - m_fakeImageBufferClient = - WTF::wrapUnique(new FakeImageBufferClient(m_imageBuffer.get())); - m_imageBuffer->setClient(m_fakeImageBufferClient.get()); + m_testSurface->initializeCurrentFrame(); } public: - void testEmptyRecord() { - m_testSurface->initializeCurrentFrame(); - sk_sp<PaintRecord> record = m_testSurface->getRecord(); - EXPECT_TRUE((bool)record.get()); - EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - } - - void testNoFallbackWithClear() { - m_testSurface->initializeCurrentFrame(); - m_testSurface->willOverwriteCanvas(); - m_testSurface->getRecord(); - EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - } - - void testNonAnimatedCanvasUpdate() { - m_testSurface->initializeCurrentFrame(); - // Acquire record twice to simulate a static canvas: nothing drawn between - // updates. - m_fakeImageBufferClient->fakeDraw(); - m_testSurface->getRecord(); - m_testSurface->getRecord(); - EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - } - - void testAnimatedWithoutClear() { - m_testSurface->initializeCurrentFrame(); - m_fakeImageBufferClient->fakeDraw(); - m_testSurface->getRecord(); - EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); - EXPECT_EQ(0, m_surfaceFactory->createSurfaceCount()); - expectDisplayListEnabled(true); // first frame has an implicit clear - m_fakeImageBufferClient->fakeDraw(); - m_testSurface->getRecord(); - EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(false); - } - - void testFrameFinalizedByTaskObserver1() { - m_testSurface->initializeCurrentFrame(); - expectDisplayListEnabled(true); - m_testSurface->getRecord(); - EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - m_fakeImageBufferClient->fakeDraw(); - EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - m_testSurface->getRecord(); - EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - m_fakeImageBufferClient->fakeDraw(); - EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - // Display list will be disabled only after exiting the runLoop - } - void testFrameFinalizedByTaskObserver2() { - EXPECT_EQ(3, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(false); - m_testSurface->getRecord(); - EXPECT_EQ(3, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(false); - m_fakeImageBufferClient->fakeDraw(); - EXPECT_EQ(3, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(false); - } - - void testAnimatedWithClear() { - m_testSurface->initializeCurrentFrame(); - m_testSurface->getRecord(); - m_testSurface->willOverwriteCanvas(); - m_fakeImageBufferClient->fakeDraw(); - EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); - m_testSurface->getRecord(); - EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - // clear after use - m_fakeImageBufferClient->fakeDraw(); - m_testSurface->willOverwriteCanvas(); - EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); - m_testSurface->getRecord(); - EXPECT_EQ(3, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - } - - void testClearRect() { - m_testSurface->initializeCurrentFrame(); - m_testSurface->getRecord(); - PaintFlags clearPaint; - clearPaint.setBlendMode(SkBlendMode::kClear); - m_imageBuffer->canvas()->drawRect( - SkRect::MakeWH(m_testSurface->size().width(), - m_testSurface->size().height()), - clearPaint); - m_fakeImageBufferClient->fakeDraw(); - EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); - m_testSurface->getRecord(); - EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); - expectDisplayListEnabled(true); - } + RecordingImageBufferSurface* testSurface() { return m_testSurface; } + int createSurfaceCount() { return m_surfaceFactory->createSurfaceCount(); } + SkCanvas* canvas() { return m_imageBuffer->canvas(); } void expectDisplayListEnabled(bool displayListEnabled) { EXPECT_EQ(displayListEnabled, (bool)m_testSurface->m_currentFrame.get()); @@ -227,53 +82,62 @@ private: MockSurfaceFactory* m_surfaceFactory; RecordingImageBufferSurface* m_testSurface; - std::unique_ptr<FakeImageBufferClient> m_fakeImageBufferClient; std::unique_ptr<ImageBuffer> m_imageBuffer; }; -#define CALL_TEST_TASK_WRAPPER(TEST_METHOD) \ - { \ - ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> \ - platform; \ - Platform::current()->currentThread()->getWebTaskRunner()->postTask( \ - BLINK_FROM_HERE, \ - WTF::bind(&RecordingImageBufferSurfaceTest::TEST_METHOD, \ - WTF::unretained(this))); \ - platform->runUntilIdle(); \ - } - -TEST_F(RecordingImageBufferSurfaceTest, testEmptyRecord) { - testEmptyRecord(); +TEST_F(RecordingImageBufferSurfaceTest, testEmptyPicture) { + sk_sp<SkPicture> picture = testSurface()->getRecord(); + EXPECT_TRUE((bool)picture.get()); + expectDisplayListEnabled(true); } TEST_F(RecordingImageBufferSurfaceTest, testNoFallbackWithClear) { - testNoFallbackWithClear(); + testSurface()->willOverwriteCanvas(); + testSurface()->getRecord(); + expectDisplayListEnabled(true); } TEST_F(RecordingImageBufferSurfaceTest, testNonAnimatedCanvasUpdate) { - CALL_TEST_TASK_WRAPPER(testNonAnimatedCanvasUpdate) + // Acquire picture twice to simulate a static canvas: nothing drawn between + // updates. + testSurface()->didDraw(FloatRect(0, 0, 1, 1)); + testSurface()->getRecord(); + testSurface()->getRecord(); expectDisplayListEnabled(true); } TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithoutClear) { - CALL_TEST_TASK_WRAPPER(testAnimatedWithoutClear) - expectDisplayListEnabled(false); -} - -TEST_F(RecordingImageBufferSurfaceTest, testFrameFinalizedByTaskObserver) { - CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver1) - expectDisplayListEnabled(false); - CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver2) + testSurface()->didDraw(FloatRect(0, 0, 1, 1)); + testSurface()->getRecord(); + EXPECT_EQ(0, createSurfaceCount()); + expectDisplayListEnabled(true); // first frame has an implicit clear + testSurface()->didDraw(FloatRect(0, 0, 1, 1)); + testSurface()->getRecord(); expectDisplayListEnabled(false); } TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithClear) { - CALL_TEST_TASK_WRAPPER(testAnimatedWithClear) + testSurface()->getRecord(); + testSurface()->willOverwriteCanvas(); + testSurface()->didDraw(FloatRect(0, 0, 1, 1)); + testSurface()->getRecord(); + expectDisplayListEnabled(true); + // clear after use + testSurface()->didDraw(FloatRect(0, 0, 1, 1)); + testSurface()->willOverwriteCanvas(); + testSurface()->getRecord(); expectDisplayListEnabled(true); } TEST_F(RecordingImageBufferSurfaceTest, testClearRect) { - CALL_TEST_TASK_WRAPPER(testClearRect); + testSurface()->getRecord(); + SkPaint clearPaint; + clearPaint.setBlendMode(SkBlendMode::kClear); + canvas()->drawRect(SkRect::MakeWH(testSurface()->size().width(), + testSurface()->size().height()), + clearPaint); + testSurface()->didDraw(FloatRect(0, 0, 1, 1)); + testSurface()->getRecord(); expectDisplayListEnabled(true); }
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 318c7361..09c5d2ef 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -163,6 +163,8 @@ settings.enable_color_correct_rendering = command_line->HasSwitch(cc::switches::kEnableColorCorrectRendering) || command_line->HasSwitch(cc::switches::kEnableTrueColorRendering); + settings.renderer_settings.enable_color_correct_rendering = + settings.enable_color_correct_rendering; // UI compositor always uses partial raster if not using zero-copy. Zero copy // doesn't currently support partial raster.