diff --git a/AUTHORS.txt b/AUTHORS.txt new file mode 100644 index 000000000..5bf04b70d --- /dev/null +++ b/AUTHORS.txt @@ -0,0 +1,5 @@ +# This file is an addendum to the Chromium AUTHORS file. +# Names should be added to this file like so: +# Name or Organization + +Marshall Greenblatt \ No newline at end of file diff --git a/CHROMIUM_BUILD_COMPATIBILITY.txt b/CHROMIUM_BUILD_COMPATIBILITY.txt new file mode 100644 index 000000000..ae4a54a02 --- /dev/null +++ b/CHROMIUM_BUILD_COMPATIBILITY.txt @@ -0,0 +1,10 @@ +The Chromium Embedded Framework (CEF) project is built on top of the Chromium +project source tree. Because of the Chromium project's constant state of flux +certain revisions of the CEF project may not be compatible with all Chromium +revisions, and visa-versa. This document tracks the combination of CEF +revision and Chromium revision that have been officially tested by the CEF +development team. + +Date | CEF Revision | Chromium Revision +------------------------------------------------------------------------------- +2008-12-02 | /trunk@2 | /trunk@6213 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..7f70e183f --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,29 @@ +// Copyright (c) 2008 Marshall A. Greenblatt. Portions Copyright (c) +// 2006-2008 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the name Chromium Embedded +// Framework nor the names of its contributors may be used to endorse +// or promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cef.sln b/cef.sln new file mode 100644 index 000000000..cbbe26489 --- /dev/null +++ b/cef.sln @@ -0,0 +1,751 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebKit (readonly)", "WebKit (readonly)", "{1088577A-0C49-4DE0-85CD-B68AD0BE55AA}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebCore", "..\webkit\build\WebCore\WebCore.vcproj", "{1C16337B-ACF3-4D03-AA90-851C5B5EADA6}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {2E2D3301-2EC4-4C0F-B889-87073B30F673} = {2E2D3301-2EC4-4C0F-B889-87073B30F673} + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9} = {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9} + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} = {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B} = {4BD929D4-494B-4EE8-91F6-FD0277A51D2B} + {31D88CBF-DC28-47A8-8838-BF81D528EE74} = {31D88CBF-DC28-47A8-8838-BF81D528EE74} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Port", "..\webkit\build\port\port.vcproj", "{5597AD47-3494-4750-A235-4F9C2F864700}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} = {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} + {2E2D3301-2EC4-4C0F-B889-87073B30F673} = {2E2D3301-2EC4-4C0F-B889-87073B30F673} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Glue", "..\webkit\build\glue\glue.vcproj", "{C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {2E2D3301-2EC4-4C0F-B889-87073B30F673} = {2E2D3301-2EC4-4C0F-B889-87073B30F673} + {60B43839-95E6-4526-A661-209F16335E0E} = {60B43839-95E6-4526-A661-209F16335E0E} + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6} = {1C16337B-ACF3-4D03-AA90-851C5B5EADA6} + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} = {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "skia", "..\skia\skia.vcproj", "{CD9CA56E-4E94-444C-87D4-58CA1E6F300D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WTF", "..\webkit\build\JavaScriptCore\WTF.vcproj", "{AA8A5A85-592B-4357-BC60-E0E91E026AF6}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite", "..\third_party\sqlite\sqlite.vcproj", "{6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {8C27D792-2648-4F5E-9ED0-374276327308} = {8C27D792-2648-4F5E-9ED0-374276327308} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebKit (ours)", "WebKit (ours)", "{CB43561E-A6F8-49E2-96A2-3F2BA1FFF21E}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "icu", "..\third_party\icu38\build\icu.vcproj", "{8C27D792-2648-4F5E-9ED0-374276327308}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {A0D94973-D355-47A5-A1E2-3456F321F010} = {A0D94973-D355-47A5-A1E2-3456F321F010} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "icu", "icu", "{1AFC1EC3-24FA-4260-B099-76319EC9977A}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "..\third_party\libpng\libpng.vcproj", "{C564F145-9172-42C3-BFCB-6014CA97DBCD}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\third_party\zlib\zlib.vcproj", "{8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "..\third_party\libjpeg\libjpeg.vcproj", "{238CE175-76CE-4A25-A676-69D115885601}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Breakpad", "Breakpad", "{873D095E-150E-4262-8C41-2D8ED02F0F57}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "breakpad_handler", "..\breakpad\breakpad_handler.vcproj", "{B55CA863-B374-4BAF-95AC-539E4FA4C90C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml", "..\third_party\libxml\build\libxml.vcproj", "{F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {31D88CBF-DC28-47A8-8838-BF81D528EE74} = {31D88CBF-DC28-47A8-8838-BF81D528EE74} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxslt", "..\third_party\libxslt\build\libxslt.vcproj", "{FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7} = {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7} + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B} = {4BD929D4-494B-4EE8-91F6-FD0277A51D2B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "V8Bindings", "..\webkit\build\V8Bindings\V8Bindings.vcproj", "{625A8F11-2B4E-45B4-BD99-C6D629C606C0}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {2E2D3301-2EC4-4C0F-B889-87073B30F673} = {2E2D3301-2EC4-4C0F-B889-87073B30F673} + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} = {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "..\third_party\bzip2\bzip2.vcproj", "{2A70CBF0-847E-4E3A-B926-542A656DC7FE}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcef", "libcef\libcef.vcproj", "{FA39524D-3067-4141-888D-28A86C66F2B9}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED} = {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED} + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0} = {F54ABC59-5C00-414A-A9BA-BAF26D1699F0} + {F4F4BCAA-EA59-445C-A119-3E6C29647A51} = {F4F4BCAA-EA59-445C-A119-3E6C29647A51} + {EF5E94AB-B646-4E5B-A058-52EF07B8351C} = {EF5E94AB-B646-4E5B-A058-52EF07B8351C} + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} = {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09} = {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09} + {C564F145-9172-42C3-BFCB-6014CA97DBCD} = {C564F145-9172-42C3-BFCB-6014CA97DBCD} + {C0334F9A-1168-4101-9DD8-C30FB252D435} = {C0334F9A-1168-4101-9DD8-C30FB252D435} + {B55CA863-B374-4BAF-95AC-539E4FA4C90C} = {B55CA863-B374-4BAF-95AC-539E4FA4C90C} + {AA8A5A85-592B-4357-BC60-E0E91E026AF6} = {AA8A5A85-592B-4357-BC60-E0E91E026AF6} + {A508ADD3-CECE-4E0F-8448-2F5E454DF551} = {A508ADD3-CECE-4E0F-8448-2F5E454DF551} + {8C27D792-2648-4F5E-9ED0-374276327308} = {8C27D792-2648-4F5E-9ED0-374276327308} + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C} = {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C} + {7100F41F-868D-4E99-80A2-AF8E6574749D} = {7100F41F-868D-4E99-80A2-AF8E6574749D} + {625A8F11-2B4E-45B4-BD99-C6D629C606C0} = {625A8F11-2B4E-45B4-BD99-C6D629C606C0} + {5916D37D-8C97-424F-A904-74E52594C2D6} = {5916D37D-8C97-424F-A904-74E52594C2D6} + {5597AD47-3494-4750-A235-4F9C2F864700} = {5597AD47-3494-4750-A235-4F9C2F864700} + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934} = {49909552-0B0C-4C14-8CF6-DB8A2ADE0934} + {326E9795-E760-410A-B69A-3F79DB3F5243} = {326E9795-E760-410A-B69A-3F79DB3F5243} + {2A70CBF0-847E-4E3A-B926-542A656DC7FE} = {2A70CBF0-847E-4E3A-B926-542A656DC7FE} + {238CE175-76CE-4A25-A676-69D115885601} = {238CE175-76CE-4A25-A676-69D115885601} + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6} = {1C16337B-ACF3-4D03-AA90-851C5B5EADA6} + {1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "V8", "V8", "{B353A6A5-9551-4B76-908E-0F0A9B31E4CE}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "googleurl", "..\googleurl\build\googleurl.vcproj", "{EF5E94AB-B646-4E5B-A058-52EF07B8351C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "modp_b64", "..\third_party\modp_b64\modp_b64.vcproj", "{7100F41F-868D-4E99-80A2-AF8E6574749D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "activex_shim", "..\webkit\activex_shim\activex_shim.vcproj", "{F4F4BCAA-EA59-445C-A119-3E6C29647A51}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {EF5E94AB-B646-4E5B-A058-52EF07B8351C} = {EF5E94AB-B646-4E5B-A058-52EF07B8351C} + {8C27D792-2648-4F5E-9ED0-374276327308} = {8C27D792-2648-4F5E-9ED0-374276327308} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net", "..\net\build\net.vcproj", "{326E9795-E760-410A-B69A-3F79DB3F5243}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41} = {E13045CD-7E1F-4A41-9B18-8D288B2E7B41} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base", "..\base\build\base.vcproj", "{1832A374-8A74-4F9E-B536-69A699B3E165}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {8C27D792-2648-4F5E-9ED0-374276327308} = {8C27D792-2648-4F5E-9ED0-374276327308} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base_gfx", "..\base\build\base_gfx.vcproj", "{A508ADD3-CECE-4E0F-8448-2F5E454DF551}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libxml projects", "libxml projects", "{032541FB-1E7C-4423-B657-4A71FE180C8A}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml_config", "..\third_party\libxml\build\libxml_config.vcproj", "{31D88CBF-DC28-47A8-8838-BF81D528EE74}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libxslt projects", "libxslt projects", "{BC732CFC-DE0A-4CF5-B8AA-3269C2F6D399}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxslt_config", "..\third_party\libxslt\build\libxslt_config.vcproj", "{4BD929D4-494B-4EE8-91F6-FD0277A51D2B}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "default_plugin", "..\webkit\default_plugin\default_plugin.vcproj", "{5916D37D-8C97-424F-A904-74E52594C2D6}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {31D88CBF-DC28-47A8-8838-BF81D528EE74} = {31D88CBF-DC28-47A8-8838-BF81D528EE74} + {60B43839-95E6-4526-A661-209F16335E0E} = {60B43839-95E6-4526-A661-209F16335E0E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaScriptCore_pcre", "..\webkit\build\JavaScriptCore\JavaScriptCore_pcre.vcproj", "{49909552-0B0C-4C14-8CF6-DB8A2ADE0934}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "V8Bindings_prebuild", "..\webkit\build\V8Bindings\V8Bindings_prebuild.vcproj", "{2F7EDFA2-EE27-4D83-8454-9EFBD5779203}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_snapshot", "..\v8\tools\visual_studio\v8_snapshot.vcproj", "{C0334F9A-1168-4101-9DD8-C30FB252D435}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {865575D0-37E2-405E-8CBA-5F6C485B5A26} = {865575D0-37E2-405E-8CBA-5F6C485B5A26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdch", "..\sdch\sdch.vcproj", "{F54ABC59-5C00-414A-A9BA-BAF26D1699F0}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cef", "Cef", "{08BAF606-555E-4048-A47E-22CFA89A21B4}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{A507014E-5F1D-4A60-963B-518FCED4B8AD}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tld_cleanup", "..\net\build\tld_cleanup.vcproj", "{E13045CD-7E1F-4A41-9B18-8D288B2E7B41}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165} + {8C27D792-2648-4F5E-9ED0-374276327308} = {8C27D792-2648-4F5E-9ED0-374276327308} + {EF5E94AB-B646-4E5B-A058-52EF07B8351C} = {EF5E94AB-B646-4E5B-A058-52EF07B8351C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_mksnapshot", "..\v8\tools\visual_studio\v8_mksnapshot.vcproj", "{865575D0-37E2-405E-8CBA-5F6C485B5A26}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {21E22961-22BF-4493-BD3A-868F93DA5179} = {21E22961-22BF-4493-BD3A-868F93DA5179} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8", "..\v8\tools\visual_studio\v8.vcproj", "{21E22961-22BF-4493-BD3A-868F93DA5179}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {EC8B7909-62AF-470D-A75D-E1D89C837142} = {EC8B7909-62AF-470D-A75D-E1D89C837142} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_base", "..\v8\tools\visual_studio\v8_base.vcproj", "{EC8B7909-62AF-470D-A75D-E1D89C837142}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "V8Config", "..\webkit\build\JSConfig\V8Config.vcproj", "{2E2D3301-2EC4-4C0F-B889-87073B30F673}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "localized_strings", "..\webkit\build\localized_strings\localized_strings.vcproj", "{60B43839-95E6-4526-A661-209F16335E0E}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cefclient", "tests\cefclient\cefclient.vcproj", "{6617FED9-C5D4-4907-BF55-A90062A6683F}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {EC8B7909-62AF-470D-A75D-E1D89C837142} = {EC8B7909-62AF-470D-A75D-E1D89C837142} + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C} = {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C} + {625A8F11-2B4E-45B4-BD99-C6D629C606C0} = {625A8F11-2B4E-45B4-BD99-C6D629C606C0} + {7100F41F-868D-4E99-80A2-AF8E6574749D} = {7100F41F-868D-4E99-80A2-AF8E6574749D} + {60B43839-95E6-4526-A661-209F16335E0E} = {60B43839-95E6-4526-A661-209F16335E0E} + {C564F145-9172-42C3-BFCB-6014CA97DBCD} = {C564F145-9172-42C3-BFCB-6014CA97DBCD} + {5597AD47-3494-4750-A235-4F9C2F864700} = {5597AD47-3494-4750-A235-4F9C2F864700} + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9} = {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9} + {FA39524D-3067-4141-888D-28A86C66F2B9} = {FA39524D-3067-4141-888D-28A86C66F2B9} + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0} = {F54ABC59-5C00-414A-A9BA-BAF26D1699F0} + {21E22961-22BF-4493-BD3A-868F93DA5179} = {21E22961-22BF-4493-BD3A-868F93DA5179} + {B55CA863-B374-4BAF-95AC-539E4FA4C90C} = {B55CA863-B374-4BAF-95AC-539E4FA4C90C} + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09} = {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09} + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} = {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} + {1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165} + {238CE175-76CE-4A25-A676-69D115885601} = {238CE175-76CE-4A25-A676-69D115885601} + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6} = {1C16337B-ACF3-4D03-AA90-851C5B5EADA6} + {5916D37D-8C97-424F-A904-74E52594C2D6} = {5916D37D-8C97-424F-A904-74E52594C2D6} + {AA8A5A85-592B-4357-BC60-E0E91E026AF6} = {AA8A5A85-592B-4357-BC60-E0E91E026AF6} + {8C27D792-2648-4F5E-9ED0-374276327308} = {8C27D792-2648-4F5E-9ED0-374276327308} + {326E9795-E760-410A-B69A-3F79DB3F5243} = {326E9795-E760-410A-B69A-3F79DB3F5243} + {C0334F9A-1168-4101-9DD8-C30FB252D435} = {C0334F9A-1168-4101-9DD8-C30FB252D435} + {F4F4BCAA-EA59-445C-A119-3E6C29647A51} = {F4F4BCAA-EA59-445C-A119-3E6C29647A51} + {EF5E94AB-B646-4E5B-A058-52EF07B8351C} = {EF5E94AB-B646-4E5B-A058-52EF07B8351C} + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED} = {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED} + {A508ADD3-CECE-4E0F-8448-2F5E454DF551} = {A508ADD3-CECE-4E0F-8448-2F5E454DF551} + {2A70CBF0-847E-4E3A-B926-542A656DC7FE} = {2A70CBF0-847E-4E3A-B926-542A656DC7FE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "icudt", "..\third_party\icu38\build\icudt.vcproj", "{A0D94973-D355-47A5-A1E2-3456F321F010}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6}.Debug|Win32.ActiveCfg = Debug|Win32 + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6}.Debug|Win32.Build.0 = Debug|Win32 + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6}.Release|Mixed Platforms.Build.0 = Release|Win32 + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6}.Release|Win32.ActiveCfg = Release|Win32 + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6}.Release|Win32.Build.0 = Release|Win32 + {5597AD47-3494-4750-A235-4F9C2F864700}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {5597AD47-3494-4750-A235-4F9C2F864700}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {5597AD47-3494-4750-A235-4F9C2F864700}.Debug|Win32.ActiveCfg = Debug|Win32 + {5597AD47-3494-4750-A235-4F9C2F864700}.Debug|Win32.Build.0 = Debug|Win32 + {5597AD47-3494-4750-A235-4F9C2F864700}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {5597AD47-3494-4750-A235-4F9C2F864700}.Release|Mixed Platforms.Build.0 = Release|Win32 + {5597AD47-3494-4750-A235-4F9C2F864700}.Release|Win32.ActiveCfg = Release|Win32 + {5597AD47-3494-4750-A235-4F9C2F864700}.Release|Win32.Build.0 = Release|Win32 + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}.Debug|Win32.ActiveCfg = Debug|Win32 + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}.Debug|Win32.Build.0 = Debug|Win32 + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}.Release|Mixed Platforms.Build.0 = Release|Win32 + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}.Release|Win32.ActiveCfg = Release|Win32 + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09}.Release|Win32.Build.0 = Release|Win32 + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D}.Debug|Win32.ActiveCfg = Debug|Win32 + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D}.Debug|Win32.Build.0 = Debug|Win32 + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D}.Release|Mixed Platforms.Build.0 = Release|Win32 + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D}.Release|Win32.ActiveCfg = Release|Win32 + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D}.Release|Win32.Build.0 = Release|Win32 + {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug|Win32.Build.0 = Debug|Win32 + {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release|Mixed Platforms.Build.0 = Release|Win32 + {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release|Win32.ActiveCfg = Release|Win32 + {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release|Win32.Build.0 = Release|Win32 + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}.Debug|Win32.ActiveCfg = Debug|Win32 + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}.Debug|Win32.Build.0 = Debug|Win32 + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}.Release|Mixed Platforms.Build.0 = Release|Win32 + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}.Release|Win32.ActiveCfg = Release|Win32 + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9}.Release|Win32.Build.0 = Release|Win32 + {8C27D792-2648-4F5E-9ED0-374276327308}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {8C27D792-2648-4F5E-9ED0-374276327308}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {8C27D792-2648-4F5E-9ED0-374276327308}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C27D792-2648-4F5E-9ED0-374276327308}.Debug|Win32.Build.0 = Debug|Win32 + {8C27D792-2648-4F5E-9ED0-374276327308}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {8C27D792-2648-4F5E-9ED0-374276327308}.Release|Mixed Platforms.Build.0 = Release|Win32 + {8C27D792-2648-4F5E-9ED0-374276327308}.Release|Win32.ActiveCfg = Release|Win32 + {8C27D792-2648-4F5E-9ED0-374276327308}.Release|Win32.Build.0 = Release|Win32 + {C564F145-9172-42C3-BFCB-6014CA97DBCD}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {C564F145-9172-42C3-BFCB-6014CA97DBCD}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {C564F145-9172-42C3-BFCB-6014CA97DBCD}.Debug|Win32.ActiveCfg = Debug|Win32 + {C564F145-9172-42C3-BFCB-6014CA97DBCD}.Debug|Win32.Build.0 = Debug|Win32 + {C564F145-9172-42C3-BFCB-6014CA97DBCD}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C564F145-9172-42C3-BFCB-6014CA97DBCD}.Release|Mixed Platforms.Build.0 = Release|Win32 + {C564F145-9172-42C3-BFCB-6014CA97DBCD}.Release|Win32.ActiveCfg = Release|Win32 + {C564F145-9172-42C3-BFCB-6014CA97DBCD}.Release|Win32.Build.0 = Release|Win32 + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}.Debug|Win32.ActiveCfg = Debug|Win32 + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}.Debug|Win32.Build.0 = Debug|Win32 + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}.Release|Mixed Platforms.Build.0 = Release|Win32 + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}.Release|Win32.ActiveCfg = Release|Win32 + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C}.Release|Win32.Build.0 = Release|Win32 + {238CE175-76CE-4A25-A676-69D115885601}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {238CE175-76CE-4A25-A676-69D115885601}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {238CE175-76CE-4A25-A676-69D115885601}.Debug|Win32.ActiveCfg = Debug|Win32 + {238CE175-76CE-4A25-A676-69D115885601}.Debug|Win32.Build.0 = Debug|Win32 + {238CE175-76CE-4A25-A676-69D115885601}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {238CE175-76CE-4A25-A676-69D115885601}.Release|Mixed Platforms.Build.0 = Release|Win32 + {238CE175-76CE-4A25-A676-69D115885601}.Release|Win32.ActiveCfg = Release|Win32 + {238CE175-76CE-4A25-A676-69D115885601}.Release|Win32.Build.0 = Release|Win32 + {B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Win32.ActiveCfg = Debug|Win32 + {B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Win32.Build.0 = Debug|Win32 + {B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Mixed Platforms.Build.0 = Release|Win32 + {B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Win32.ActiveCfg = Release|Win32 + {B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Win32.Build.0 = Release|Win32 + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}.Debug|Win32.ActiveCfg = Debug|Win32 + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}.Debug|Win32.Build.0 = Debug|Win32 + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}.Release|Mixed Platforms.Build.0 = Release|Win32 + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}.Release|Win32.ActiveCfg = Release|Win32 + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7}.Release|Win32.Build.0 = Release|Win32 + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}.Debug|Win32.ActiveCfg = Debug|Win32 + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}.Debug|Win32.Build.0 = Debug|Win32 + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}.Release|Mixed Platforms.Build.0 = Release|Win32 + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}.Release|Win32.ActiveCfg = Release|Win32 + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED}.Release|Win32.Build.0 = Release|Win32 + {625A8F11-2B4E-45B4-BD99-C6D629C606C0}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {625A8F11-2B4E-45B4-BD99-C6D629C606C0}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {625A8F11-2B4E-45B4-BD99-C6D629C606C0}.Debug|Win32.ActiveCfg = Debug|Win32 + {625A8F11-2B4E-45B4-BD99-C6D629C606C0}.Debug|Win32.Build.0 = Debug|Win32 + {625A8F11-2B4E-45B4-BD99-C6D629C606C0}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {625A8F11-2B4E-45B4-BD99-C6D629C606C0}.Release|Mixed Platforms.Build.0 = Release|Win32 + {625A8F11-2B4E-45B4-BD99-C6D629C606C0}.Release|Win32.ActiveCfg = Release|Win32 + {625A8F11-2B4E-45B4-BD99-C6D629C606C0}.Release|Win32.Build.0 = Release|Win32 + {2A70CBF0-847E-4E3A-B926-542A656DC7FE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {2A70CBF0-847E-4E3A-B926-542A656DC7FE}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {2A70CBF0-847E-4E3A-B926-542A656DC7FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {2A70CBF0-847E-4E3A-B926-542A656DC7FE}.Debug|Win32.Build.0 = Debug|Win32 + {2A70CBF0-847E-4E3A-B926-542A656DC7FE}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {2A70CBF0-847E-4E3A-B926-542A656DC7FE}.Release|Mixed Platforms.Build.0 = Release|Win32 + {2A70CBF0-847E-4E3A-B926-542A656DC7FE}.Release|Win32.ActiveCfg = Release|Win32 + {2A70CBF0-847E-4E3A-B926-542A656DC7FE}.Release|Win32.Build.0 = Release|Win32 + {FA39524D-3067-4141-888D-28A86C66F2B9}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {FA39524D-3067-4141-888D-28A86C66F2B9}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {FA39524D-3067-4141-888D-28A86C66F2B9}.Debug|Win32.ActiveCfg = Debug|Win32 + {FA39524D-3067-4141-888D-28A86C66F2B9}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {FA39524D-3067-4141-888D-28A86C66F2B9}.Release|Mixed Platforms.Build.0 = Release|Win32 + {FA39524D-3067-4141-888D-28A86C66F2B9}.Release|Win32.ActiveCfg = Release|Win32 + {FA39524D-3067-4141-888D-28A86C66F2B9}.Release|Win32.Build.0 = Release|Win32 + {EF5E94AB-B646-4E5B-A058-52EF07B8351C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {EF5E94AB-B646-4E5B-A058-52EF07B8351C}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {EF5E94AB-B646-4E5B-A058-52EF07B8351C}.Debug|Win32.ActiveCfg = Debug|Win32 + {EF5E94AB-B646-4E5B-A058-52EF07B8351C}.Debug|Win32.Build.0 = Debug|Win32 + {EF5E94AB-B646-4E5B-A058-52EF07B8351C}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {EF5E94AB-B646-4E5B-A058-52EF07B8351C}.Release|Mixed Platforms.Build.0 = Release|Win32 + {EF5E94AB-B646-4E5B-A058-52EF07B8351C}.Release|Win32.ActiveCfg = Release|Win32 + {EF5E94AB-B646-4E5B-A058-52EF07B8351C}.Release|Win32.Build.0 = Release|Win32 + {7100F41F-868D-4E99-80A2-AF8E6574749D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {7100F41F-868D-4E99-80A2-AF8E6574749D}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {7100F41F-868D-4E99-80A2-AF8E6574749D}.Debug|Win32.ActiveCfg = Debug|Win32 + {7100F41F-868D-4E99-80A2-AF8E6574749D}.Debug|Win32.Build.0 = Debug|Win32 + {7100F41F-868D-4E99-80A2-AF8E6574749D}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {7100F41F-868D-4E99-80A2-AF8E6574749D}.Release|Mixed Platforms.Build.0 = Release|Win32 + {7100F41F-868D-4E99-80A2-AF8E6574749D}.Release|Win32.ActiveCfg = Release|Win32 + {7100F41F-868D-4E99-80A2-AF8E6574749D}.Release|Win32.Build.0 = Release|Win32 + {F4F4BCAA-EA59-445C-A119-3E6C29647A51}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {F4F4BCAA-EA59-445C-A119-3E6C29647A51}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {F4F4BCAA-EA59-445C-A119-3E6C29647A51}.Debug|Win32.ActiveCfg = Debug|Win32 + {F4F4BCAA-EA59-445C-A119-3E6C29647A51}.Debug|Win32.Build.0 = Debug|Win32 + {F4F4BCAA-EA59-445C-A119-3E6C29647A51}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {F4F4BCAA-EA59-445C-A119-3E6C29647A51}.Release|Mixed Platforms.Build.0 = Release|Win32 + {F4F4BCAA-EA59-445C-A119-3E6C29647A51}.Release|Win32.ActiveCfg = Release|Win32 + {F4F4BCAA-EA59-445C-A119-3E6C29647A51}.Release|Win32.Build.0 = Release|Win32 + {326E9795-E760-410A-B69A-3F79DB3F5243}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {326E9795-E760-410A-B69A-3F79DB3F5243}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {326E9795-E760-410A-B69A-3F79DB3F5243}.Debug|Win32.ActiveCfg = Debug|Win32 + {326E9795-E760-410A-B69A-3F79DB3F5243}.Debug|Win32.Build.0 = Debug|Win32 + {326E9795-E760-410A-B69A-3F79DB3F5243}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {326E9795-E760-410A-B69A-3F79DB3F5243}.Release|Mixed Platforms.Build.0 = Release|Win32 + {326E9795-E760-410A-B69A-3F79DB3F5243}.Release|Win32.ActiveCfg = Release|Win32 + {326E9795-E760-410A-B69A-3F79DB3F5243}.Release|Win32.Build.0 = Release|Win32 + {1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Win32.ActiveCfg = Debug|Win32 + {1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Win32.Build.0 = Debug|Win32 + {1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Mixed Platforms.Build.0 = Release|Win32 + {1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Win32.ActiveCfg = Release|Win32 + {1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Win32.Build.0 = Release|Win32 + {A508ADD3-CECE-4E0F-8448-2F5E454DF551}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {A508ADD3-CECE-4E0F-8448-2F5E454DF551}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {A508ADD3-CECE-4E0F-8448-2F5E454DF551}.Debug|Win32.ActiveCfg = Debug|Win32 + {A508ADD3-CECE-4E0F-8448-2F5E454DF551}.Debug|Win32.Build.0 = Debug|Win32 + {A508ADD3-CECE-4E0F-8448-2F5E454DF551}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {A508ADD3-CECE-4E0F-8448-2F5E454DF551}.Release|Mixed Platforms.Build.0 = Release|Win32 + {A508ADD3-CECE-4E0F-8448-2F5E454DF551}.Release|Win32.ActiveCfg = Release|Win32 + {A508ADD3-CECE-4E0F-8448-2F5E454DF551}.Release|Win32.Build.0 = Release|Win32 + {31D88CBF-DC28-47A8-8838-BF81D528EE74}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {31D88CBF-DC28-47A8-8838-BF81D528EE74}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {31D88CBF-DC28-47A8-8838-BF81D528EE74}.Debug|Win32.ActiveCfg = Debug|Win32 + {31D88CBF-DC28-47A8-8838-BF81D528EE74}.Debug|Win32.Build.0 = Debug|Win32 + {31D88CBF-DC28-47A8-8838-BF81D528EE74}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {31D88CBF-DC28-47A8-8838-BF81D528EE74}.Release|Mixed Platforms.Build.0 = Release|Win32 + {31D88CBF-DC28-47A8-8838-BF81D528EE74}.Release|Win32.ActiveCfg = Release|Win32 + {31D88CBF-DC28-47A8-8838-BF81D528EE74}.Release|Win32.Build.0 = Release|Win32 + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B}.Debug|Win32.ActiveCfg = Debug|Win32 + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B}.Debug|Win32.Build.0 = Debug|Win32 + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B}.Release|Mixed Platforms.Build.0 = Release|Win32 + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B}.Release|Win32.ActiveCfg = Release|Win32 + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B}.Release|Win32.Build.0 = Release|Win32 + {5916D37D-8C97-424F-A904-74E52594C2D6}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {5916D37D-8C97-424F-A904-74E52594C2D6}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {5916D37D-8C97-424F-A904-74E52594C2D6}.Debug|Win32.ActiveCfg = Debug|Win32 + {5916D37D-8C97-424F-A904-74E52594C2D6}.Debug|Win32.Build.0 = Debug|Win32 + {5916D37D-8C97-424F-A904-74E52594C2D6}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {5916D37D-8C97-424F-A904-74E52594C2D6}.Release|Mixed Platforms.Build.0 = Release|Win32 + {5916D37D-8C97-424F-A904-74E52594C2D6}.Release|Win32.ActiveCfg = Release|Win32 + {5916D37D-8C97-424F-A904-74E52594C2D6}.Release|Win32.Build.0 = Release|Win32 + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934}.Debug|Win32.ActiveCfg = Debug|Win32 + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934}.Debug|Win32.Build.0 = Debug|Win32 + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934}.Release|Mixed Platforms.Build.0 = Release|Win32 + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934}.Release|Win32.ActiveCfg = Release|Win32 + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934}.Release|Win32.Build.0 = Release|Win32 + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203}.Debug|Win32.ActiveCfg = Debug|Win32 + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203}.Debug|Win32.Build.0 = Debug|Win32 + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203}.Release|Mixed Platforms.Build.0 = Release|Win32 + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203}.Release|Win32.ActiveCfg = Release|Win32 + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203}.Release|Win32.Build.0 = Release|Win32 + {C0334F9A-1168-4101-9DD8-C30FB252D435}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {C0334F9A-1168-4101-9DD8-C30FB252D435}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {C0334F9A-1168-4101-9DD8-C30FB252D435}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0334F9A-1168-4101-9DD8-C30FB252D435}.Debug|Win32.Build.0 = Debug|Win32 + {C0334F9A-1168-4101-9DD8-C30FB252D435}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C0334F9A-1168-4101-9DD8-C30FB252D435}.Release|Mixed Platforms.Build.0 = Release|Win32 + {C0334F9A-1168-4101-9DD8-C30FB252D435}.Release|Win32.ActiveCfg = Release|Win32 + {C0334F9A-1168-4101-9DD8-C30FB252D435}.Release|Win32.Build.0 = Release|Win32 + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0}.Debug|Win32.ActiveCfg = Debug|Win32 + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0}.Debug|Win32.Build.0 = Debug|Win32 + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0}.Release|Mixed Platforms.Build.0 = Release|Win32 + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0}.Release|Win32.ActiveCfg = Release|Win32 + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0}.Release|Win32.Build.0 = Release|Win32 + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41}.Debug|Win32.ActiveCfg = Debug|Win32 + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41}.Debug|Win32.Build.0 = Debug|Win32 + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41}.Release|Mixed Platforms.Build.0 = Release|Win32 + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41}.Release|Win32.ActiveCfg = Release|Win32 + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41}.Release|Win32.Build.0 = Release|Win32 + {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Debug|Win32.ActiveCfg = Debug|Win32 + {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Debug|Win32.Build.0 = Debug|Win32 + {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Release|Mixed Platforms.Build.0 = Release|Win32 + {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Release|Win32.ActiveCfg = Release|Win32 + {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Release|Win32.Build.0 = Release|Win32 + {21E22961-22BF-4493-BD3A-868F93DA5179}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {21E22961-22BF-4493-BD3A-868F93DA5179}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {21E22961-22BF-4493-BD3A-868F93DA5179}.Debug|Win32.ActiveCfg = Debug|Win32 + {21E22961-22BF-4493-BD3A-868F93DA5179}.Debug|Win32.Build.0 = Debug|Win32 + {21E22961-22BF-4493-BD3A-868F93DA5179}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {21E22961-22BF-4493-BD3A-868F93DA5179}.Release|Mixed Platforms.Build.0 = Release|Win32 + {21E22961-22BF-4493-BD3A-868F93DA5179}.Release|Win32.ActiveCfg = Release|Win32 + {21E22961-22BF-4493-BD3A-868F93DA5179}.Release|Win32.Build.0 = Release|Win32 + {EC8B7909-62AF-470D-A75D-E1D89C837142}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {EC8B7909-62AF-470D-A75D-E1D89C837142}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {EC8B7909-62AF-470D-A75D-E1D89C837142}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC8B7909-62AF-470D-A75D-E1D89C837142}.Debug|Win32.Build.0 = Debug|Win32 + {EC8B7909-62AF-470D-A75D-E1D89C837142}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {EC8B7909-62AF-470D-A75D-E1D89C837142}.Release|Mixed Platforms.Build.0 = Release|Win32 + {EC8B7909-62AF-470D-A75D-E1D89C837142}.Release|Win32.ActiveCfg = Release|Win32 + {EC8B7909-62AF-470D-A75D-E1D89C837142}.Release|Win32.Build.0 = Release|Win32 + {2E2D3301-2EC4-4C0F-B889-87073B30F673}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {2E2D3301-2EC4-4C0F-B889-87073B30F673}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {2E2D3301-2EC4-4C0F-B889-87073B30F673}.Debug|Win32.ActiveCfg = Debug|Win32 + {2E2D3301-2EC4-4C0F-B889-87073B30F673}.Debug|Win32.Build.0 = Debug|Win32 + {2E2D3301-2EC4-4C0F-B889-87073B30F673}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {2E2D3301-2EC4-4C0F-B889-87073B30F673}.Release|Mixed Platforms.Build.0 = Release|Win32 + {2E2D3301-2EC4-4C0F-B889-87073B30F673}.Release|Win32.ActiveCfg = Release|Win32 + {2E2D3301-2EC4-4C0F-B889-87073B30F673}.Release|Win32.Build.0 = Release|Win32 + {60B43839-95E6-4526-A661-209F16335E0E}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {60B43839-95E6-4526-A661-209F16335E0E}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {60B43839-95E6-4526-A661-209F16335E0E}.Debug|Win32.ActiveCfg = Debug|Win32 + {60B43839-95E6-4526-A661-209F16335E0E}.Debug|Win32.Build.0 = Debug|Win32 + {60B43839-95E6-4526-A661-209F16335E0E}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {60B43839-95E6-4526-A661-209F16335E0E}.Release|Mixed Platforms.Build.0 = Release|Win32 + {60B43839-95E6-4526-A661-209F16335E0E}.Release|Win32.ActiveCfg = Release|Win32 + {60B43839-95E6-4526-A661-209F16335E0E}.Release|Win32.Build.0 = Release|Win32 + {6617FED9-C5D4-4907-BF55-A90062A6683F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {6617FED9-C5D4-4907-BF55-A90062A6683F}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {6617FED9-C5D4-4907-BF55-A90062A6683F}.Debug|Win32.ActiveCfg = Debug|Win32 + {6617FED9-C5D4-4907-BF55-A90062A6683F}.Debug|Win32.Build.0 = Debug|Win32 + {6617FED9-C5D4-4907-BF55-A90062A6683F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {6617FED9-C5D4-4907-BF55-A90062A6683F}.Release|Mixed Platforms.Build.0 = Release|Win32 + {6617FED9-C5D4-4907-BF55-A90062A6683F}.Release|Win32.ActiveCfg = Release|Win32 + {6617FED9-C5D4-4907-BF55-A90062A6683F}.Release|Win32.Build.0 = Release|Win32 + {A0D94973-D355-47A5-A1E2-3456F321F010}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {A0D94973-D355-47A5-A1E2-3456F321F010}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {A0D94973-D355-47A5-A1E2-3456F321F010}.Debug|Win32.ActiveCfg = Debug|Win32 + {A0D94973-D355-47A5-A1E2-3456F321F010}.Debug|Win32.Build.0 = Debug|Win32 + {A0D94973-D355-47A5-A1E2-3456F321F010}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {A0D94973-D355-47A5-A1E2-3456F321F010}.Release|Mixed Platforms.Build.0 = Release|Win32 + {A0D94973-D355-47A5-A1E2-3456F321F010}.Release|Win32.ActiveCfg = Release|Win32 + {A0D94973-D355-47A5-A1E2-3456F321F010}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1C16337B-ACF3-4D03-AA90-851C5B5EADA6} = {1088577A-0C49-4DE0-85CD-B68AD0BE55AA} + {AA8A5A85-592B-4357-BC60-E0E91E026AF6} = {1088577A-0C49-4DE0-85CD-B68AD0BE55AA} + {49909552-0B0C-4C14-8CF6-DB8A2ADE0934} = {1088577A-0C49-4DE0-85CD-B68AD0BE55AA} + {2E2D3301-2EC4-4C0F-B889-87073B30F673} = {1088577A-0C49-4DE0-85CD-B68AD0BE55AA} + {C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09} = {CB43561E-A6F8-49E2-96A2-3F2BA1FFF21E} + {5597AD47-3494-4750-A235-4F9C2F864700} = {CB43561E-A6F8-49E2-96A2-3F2BA1FFF21E} + {625A8F11-2B4E-45B4-BD99-C6D629C606C0} = {CB43561E-A6F8-49E2-96A2-3F2BA1FFF21E} + {F4F4BCAA-EA59-445C-A119-3E6C29647A51} = {CB43561E-A6F8-49E2-96A2-3F2BA1FFF21E} + {5916D37D-8C97-424F-A904-74E52594C2D6} = {CB43561E-A6F8-49E2-96A2-3F2BA1FFF21E} + {2F7EDFA2-EE27-4D83-8454-9EFBD5779203} = {CB43561E-A6F8-49E2-96A2-3F2BA1FFF21E} + {60B43839-95E6-4526-A661-209F16335E0E} = {CB43561E-A6F8-49E2-96A2-3F2BA1FFF21E} + {6EAD4A4B-2BBC-4974-8E45-BB5C16CC2AC9} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {1AFC1EC3-24FA-4260-B099-76319EC9977A} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {C564F145-9172-42C3-BFCB-6014CA97DBCD} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {8423AF0D-4B88-4EBF-94E1-E4D00D00E21C} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {238CE175-76CE-4A25-A676-69D115885601} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {873D095E-150E-4262-8C41-2D8ED02F0F57} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {032541FB-1E7C-4423-B657-4A71FE180C8A} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {BC732CFC-DE0A-4CF5-B8AA-3269C2F6D399} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {2A70CBF0-847E-4E3A-B926-542A656DC7FE} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {EF5E94AB-B646-4E5B-A058-52EF07B8351C} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {7100F41F-868D-4E99-80A2-AF8E6574749D} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {326E9795-E760-410A-B69A-3F79DB3F5243} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {1832A374-8A74-4F9E-B536-69A699B3E165} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {A508ADD3-CECE-4E0F-8448-2F5E454DF551} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {F54ABC59-5C00-414A-A9BA-BAF26D1699F0} = {EF78C1F9-AA17-4CA5-B6CB-39B37A73A3DA} + {8C27D792-2648-4F5E-9ED0-374276327308} = {1AFC1EC3-24FA-4260-B099-76319EC9977A} + {A0D94973-D355-47A5-A1E2-3456F321F010} = {1AFC1EC3-24FA-4260-B099-76319EC9977A} + {B55CA863-B374-4BAF-95AC-539E4FA4C90C} = {873D095E-150E-4262-8C41-2D8ED02F0F57} + {F9810DE8-CBC3-4605-A7B1-ECA2D5292FD7} = {032541FB-1E7C-4423-B657-4A71FE180C8A} + {31D88CBF-DC28-47A8-8838-BF81D528EE74} = {032541FB-1E7C-4423-B657-4A71FE180C8A} + {FC0E1FD0-5DD7-4041-A1C9-CD3C376E4EED} = {BC732CFC-DE0A-4CF5-B8AA-3269C2F6D399} + {4BD929D4-494B-4EE8-91F6-FD0277A51D2B} = {BC732CFC-DE0A-4CF5-B8AA-3269C2F6D399} + {FA39524D-3067-4141-888D-28A86C66F2B9} = {08BAF606-555E-4048-A47E-22CFA89A21B4} + {6617FED9-C5D4-4907-BF55-A90062A6683F} = {08BAF606-555E-4048-A47E-22CFA89A21B4} + {C0334F9A-1168-4101-9DD8-C30FB252D435} = {B353A6A5-9551-4B76-908E-0F0A9B31E4CE} + {865575D0-37E2-405E-8CBA-5F6C485B5A26} = {B353A6A5-9551-4B76-908E-0F0A9B31E4CE} + {21E22961-22BF-4493-BD3A-868F93DA5179} = {B353A6A5-9551-4B76-908E-0F0A9B31E4CE} + {EC8B7909-62AF-470D-A75D-E1D89C837142} = {B353A6A5-9551-4B76-908E-0F0A9B31E4CE} + {E13045CD-7E1F-4A41-9B18-8D288B2E7B41} = {A507014E-5F1D-4A60-963B-518FCED4B8AD} + EndGlobalSection +EndGlobal diff --git a/include/cef.h b/include/cef.h new file mode 100644 index 000000000..030c90a69 --- /dev/null +++ b/include/cef.h @@ -0,0 +1,751 @@ +// Copyright (c) 2008 Marshall A. Greenblatt. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the name Chromium Embedded +// Framework nor the names of its contributors may be used to endorse +// or promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#ifndef _CEF_H +#define _CEF_H + +#include +#include +#include +#include "cef_ptr.h" + + +// This function should only be called once when the application is started. +// Create the thread to host the UI message loop. A return value of true +// indicates that it succeeded and false indicates that it failed. +bool CefInitialize(); + +// This function should only be called once before the application exits. +// Shut down the thread hosting the UI message loop and destroy any created +// windows. +void CefShutdown(); + + +// Interface defining the the reference count implementation methods. All +// framework classes must implement the CefBase class. +class CefBase +{ +public: + // The AddRef method increments the reference count for the object. It should + // be called for every new copy of a pointer to a given object. The resulting + // reference count value is returned and should be used for diagnostic/testing + // purposes only. + virtual int AddRef() =0; + + // The Release method decrements the reference count for the object. If the + // reference count on the object falls to 0, then the object should free + // itself from memory. The resulting reference count value is returned and + // should be used for diagnostic/testing purposes only. + virtual int Release() =0; +}; + + +// Bring in platform-specific definitions. +#ifdef _WIN32 +#include "cef_win.h" +#endif + + +// Template that provides atomic implementations of AddRef() and Release() +// along with Lock() and Unlock() methods to protect critical sections of +// code from simultaneous access by multiple threads. +// +// The below example demonstrates how to use the CefThreadSafeBase template. +// +// class MyHandler : public CefThreadSafeBase +// { +// std::wstring m_title; +// +// virtual RetVal HandleTitleChange(const std::wstring& title) +// { +// Lock(); // Begin protecting code +// m_title = title; +// Unlock(); // Done protecting code +// return RV_HANDLED; +// } +// ... +// } +// +template +class CefThreadSafeBase : public ClassName +{ +public: + CefThreadSafeBase() + { + m_dwRef = 0L; + } + ~CefThreadSafeBase() + { + } + + // Atomic reference increment. + int AddRef() + { + return CefAtomicIncrement(&m_dwRef); + } + + // Atomic reference decrement. Delete this object when no references remain. + int Release() + { + int retval = CefAtomicDecrement(&m_dwRef); + if(retval == 0) + delete this; + return retval; + } + + // Use the Lock() and Unlock() methods to protect a section of code from + // simultaneous access by multiple threads. + void Lock() { m_critsec.Lock(); } + void Unlock() { m_critsec.Unlock(); } + +protected: + long m_dwRef; + CefCriticalSection m_critsec; +}; + + +class CefHandler; +class CefRequest; +class CefStreamReader; +class CefStreamWriter; +class CefPostData; +class CefPostDataElement; +class CefJSHandler; +class CefVariant; + + +// Class used to represent a browser window. All methods exposed by this +// class should be thread safe. +class CefBrowser : public CefBase +{ +public: + // Create a new browser window using the window parameters specified + // by |windowInfo|. All values will be copied internally and the actual + // window will be created on the UI thread. The |popup| parameter should + // be true if the new window is a popup window. This method call will not + // block. + static bool CreateBrowser(CefWindowInfo& windowInfo, bool popup, + CefRefPtr handler, + const std::wstring& url); + + // Returns true if the browser can navigate backwards. + virtual bool CanGoBack() =0; + // Navigate backwards. + virtual void GoBack() =0; + // Returns true if the browser can navigate forwards. + virtual bool CanGoForward() =0; + // Navigate backwards. + virtual void GoForward() =0; + // Reload the current page. + virtual void Reload() =0; + // Stop loading the page. + virtual void StopLoad() =0; + + // Define frame target types. Using TF_FOCUSED will target the focused + // frame and using TF_MAIN will target the main frame. + enum TargetFrame + { + TF_FOCUSED = 0, + TF_MAIN = 1 + }; + + // Execute undo in the target frame. + virtual void Undo(TargetFrame targetFrame) =0; + // Execute redo in the target frame. + virtual void Redo(TargetFrame targetFrame) =0; + // Execute cut in the target frame. + virtual void Cut(TargetFrame targetFrame) =0; + // Execute copy in the target frame. + virtual void Copy(TargetFrame targetFrame) =0; + // Execute paste in the target frame. + virtual void Paste(TargetFrame targetFrame) =0; + // Execute delete in the target frame. + virtual void Delete(TargetFrame targetFrame) =0; + // Execute select all in the target frame. + virtual void SelectAll(TargetFrame targetFrame) =0; + + // Execute printing in the target frame. The user will be prompted with + // the print dialog appropriate to the operating system. + virtual void Print(TargetFrame targetFrame) =0; + + // Save the target frame's HTML source to a temporary file and open it in + // the default text viewing application. + virtual void ViewSource(TargetFrame targetFrame) =0; + + // Returns the target frame's HTML source as a string. + virtual std::wstring GetSource(TargetFrame targetFrame) =0; + + // Returns the target frame's display text as a string. + virtual std::wstring GetText(TargetFrame targetFrame) =0; + + // Load the request represented by the |request| object. + virtual void LoadRequest(CefRefPtr request) =0; + + // Convenience method for loading the specified |url| in the optional target + // |frame|. + virtual void LoadURL(const std::wstring& url, const std::wstring& frame) =0; + + // Load the contents of |string| with the optional dummy target |url|. + virtual void LoadString(const std::wstring& string, + const std::wstring& url) =0; + + // Load the contents of |stream| with the optional dummy target |url|. + virtual void LoadStream(CefRefPtr stream, + const std::wstring& url) =0; + + // Register a new handler tied to the specified JS object |name|. Returns + // true if the handler is registered successfully. + // A JS handler will be accessible to JavaScript as window.. + virtual bool AddJSHandler(const std::wstring& classname, + CefRefPtr handler) =0; + + // Returns true if a JS handler with the specified |name| is currently + // registered. + virtual bool HasJSHandler(const std::wstring& classname) =0; + + // Returns the JS handler registered with the specified |name|. + virtual CefRefPtr GetJSHandler(const std::wstring& classname) =0; + + // Unregister the JS handler registered with the specified |name|. Returns + // true if the handler is unregistered successfully. + virtual bool RemoveJSHandler(const std::wstring& classname) =0; + + // Unregister all JS handlers that are currently registered. + virtual void RemoveAllJSHandlers() =0; + + // Retrieve the window handle for this browser. + virtual CefWindowHandle GetWindowHandle() =0; + + // Returns true if the window is a popup window. + virtual bool IsPopup() =0; + + // Returns the handler for this browser. + virtual CefRefPtr GetHandler() =0; + + // Return the currently loaded URL. + virtual std::wstring GetURL() =0; +}; + + +// Interface that should be implemented to handle events generated by the +// browser window. All methods exposed by this class should be thread safe. +// Each method in the interface returns a RetVal value. +class CefHandler : public CefBase +{ +public: + // Define handler return value types. Returning RV_HANDLED indicates + // that the implementation completely handled the method and that no further + // processing is required. Returning RV_CONTINUE indicates that the + // implementation did not handle the method and that the default handler + // should be called. + enum RetVal + { + RV_HANDLED = 0, + RV_CONTINUE = 1 + }; + + // Event called before a new window is created. The |parentBrowser| parameter + // will point to the parent browser window, if any. The |popup| parameter + // will be true if the new window is a popup window. If you create the window + // yourself you should populate the window handle member of |createInfo| and + // return RV_HANDLED. Otherwise, return RV_CONTINUE and the framework will + // create the window. By default, a newly created window will recieve the + // same handler as the parent window. To change the handler for the new + // window modify the object that |handler| points to. + virtual RetVal HandleBeforeCreated(CefRefPtr parentBrowser, + CefWindowInfo& createInfo, bool popup, + CefRefPtr& handler, + std::wstring& url) =0; + + // Event called after a new window is created. The return value is currently + // ignored. + virtual RetVal HandleAfterCreated(CefRefPtr browser) =0; + + // Event called when the address bar changes. The return value is currently + // ignored. + virtual RetVal HandleAddressChange(CefRefPtr browser, + const std::wstring& url) =0; + + // Event called when the page title changes. The return value is currently + // ignored. + virtual RetVal HandleTitleChange(CefRefPtr browser, + const std::wstring& title) =0; + + // Various browser navigation types supported by chrome. + enum NavType + { + NAVTYPE_LINKCLICKED = 0, + NAVTYPE_FORMSUBMITTED, + NAVTYPE_BACKFORWARD, + NAVTYPE_RELOAD, + NAVTYPE_FORMRESUBMITTED, + NAVTYPE_OTHER + }; + + // Event called before browser navigation. The client has an opportunity to + // modify the |request| object if desired. Return RV_HANDLED to cancel + // navigation. + virtual RetVal HandleBeforeBrowse(CefRefPtr browser, + CefRefPtr request, + NavType navType, bool isRedirect) =0; + + // Event called when the browser begins loading a page. The return value is + // currently ignored. + virtual RetVal HandleLoadStart(CefRefPtr browser) =0; + + // Event called when the browser is done loading a page. This event will + // be generated irrespective of whether the request completes successfully. + // The return value is currently ignored. + virtual RetVal HandleLoadEnd(CefRefPtr browser) =0; + + // Supported error code values. See net\base\net_error_list.h for complete + // descriptions of the error codes. + enum ErrorCode + { + ERR_FAILED = -2, + ERR_ABORTED = -3, + ERR_INVALID_ARGUMENT = -4, + ERR_INVALID_HANDLE = -5, + ERR_FILE_NOT_FOUND = -6, + ERR_TIMED_OUT = -7, + ERR_FILE_TOO_BIG = -8, + ERR_UNEXPECTED = -9, + ERR_ACCESS_DENIED = -10, + ERR_NOT_IMPLEMENTED = -11, + ERR_CONNECTION_CLOSED = -100, + ERR_CONNECTION_RESET = -101, + ERR_CONNECTION_REFUSED = -102, + ERR_CONNECTION_ABORTED = -103, + ERR_CONNECTION_FAILED = -104, + ERR_NAME_NOT_RESOLVED = -105, + ERR_INTERNET_DISCONNECTED = -106, + ERR_SSL_PROTOCOL_ERROR = -107, + ERR_ADDRESS_INVALID = -108, + ERR_ADDRESS_UNREACHABLE = -109, + ERR_SSL_CLIENT_AUTH_CERT_NEEDED = -110, + ERR_TUNNEL_CONNECTION_FAILED = -111, + ERR_NO_SSL_VERSIONS_ENABLED = -112, + ERR_SSL_VERSION_OR_CIPHER_MISMATCH = -113, + ERR_SSL_RENEGOTIATION_REQUESTED = -114, + ERR_CERT_COMMON_NAME_INVALID = -200, + ERR_CERT_DATE_INVALID = -201, + ERR_CERT_AUTHORITY_INVALID = -202, + ERR_CERT_CONTAINS_ERRORS = -203, + ERR_CERT_NO_REVOCATION_MECHANISM = -204, + ERR_CERT_UNABLE_TO_CHECK_REVOCATION = -205, + ERR_CERT_REVOKED = -206, + ERR_CERT_INVALID = -207, + ERR_CERT_END = -208, + ERR_INVALID_URL = -300, + ERR_DISALLOWED_URL_SCHEME = -301, + ERR_UNKNOWN_URL_SCHEME = -302, + ERR_TOO_MANY_REDIRECTS = -310, + ERR_UNSAFE_REDIRECT = -311, + ERR_UNSAFE_PORT = -312, + ERR_INVALID_RESPONSE = -320, + ERR_INVALID_CHUNKED_ENCODING = -321, + ERR_METHOD_NOT_SUPPORTED = -322, + ERR_UNEXPECTED_PROXY_AUTH = -323, + ERR_EMPTY_RESPONSE = -324, + ERR_RESPONSE_HEADERS_TOO_BIG = -325, + ERR_CACHE_MISS = -400, + ERR_INSECURE_RESPONSE = -501, + }; + + // Called when the browser fails to load a resource. |errorCode is the + // error code number and |failedUrl| is the URL that failed to load. To + // provide custom error text assign the text to |errorText| and return + // RV_HANDLED. Otherwise, return RV_CONTINUE for the default error text. + virtual RetVal HandleLoadError(CefRefPtr browser, + ErrorCode errorCode, + const std::wstring& failedUrl, + std::wstring& errorText) =0; + + // Event called before a resource is loaded. To allow the resource to load + // normally return RV_CONTINUE. To redirect the resource to a new url + // populate the |redirectUrl| value and return RV_CONTINUE. To specify + // data for the resource return a CefStream object in |resourceStream|, set + // 'mimeType| to the resource stream's mime type, and return RV_CONTINUE. + // To cancel loading of the resource return RV_HANDLED. + virtual RetVal HandleBeforeResourceLoad(CefRefPtr browser, + CefRefPtr request, + std::wstring& redirectUrl, + CefRefPtr& resourceStream, + std::wstring& mimeType, + int loadFlags) =0; + + // Various context menu types supported by chrome. + enum MenuType + { + MENUTYPE_NONE = 0, + MENUTYPE_PAGE, + MENUTYPE_FRAME, + MENUTYPE_LINK, + MENUTYPE_IMAGE, + MENUTYPE_IMAGE_LINK, + MENUTYPE_SELECTION, + MENUTYPE_EDITABLE + }; + + // Structure representing menu information + struct MenuInfo + { + MenuType menuType; + int x; + int y; + std::wstring linkUrl; + std::wstring imageUrl; + std::wstring pageUrl; + std::wstring frameUrl; + std::wstring selectionText; + std::wstring misspelledWord; + int editFlags; + std::string securityInfo; + }; + + // The MenuInfo editFlags value will be a combination of the following + enum MenuCapability + { + CAN_DO_NONE = 0x0, + CAN_UNDO = 0x1, + CAN_REDO = 0x2, + CAN_CUT = 0x4, + CAN_COPY = 0x8, + CAN_PASTE = 0x10, + CAN_DELETE = 0x20, + CAN_SELECT_ALL = 0x40, + CAN_GO_FORWARD = 0x80, + CAN_GO_BACK = 0x100, + }; + + // Event called before a context menu is displayed. To cancel display of the + // default context menu return RV_HANDLED. + virtual RetVal HandleBeforeMenu(CefRefPtr browser, + const MenuInfo& menuInfo) =0; + + // Supported menu ID values + enum MenuId + { + ID_NAV_BACK = 10, + ID_NAV_FORWARD = 11, + ID_NAV_RELOAD = 12, + ID_NAV_STOP = 13, + ID_UNDO = 20, + ID_REDO = 21, + ID_CUT = 22, + ID_COPY = 23, + ID_PASTE = 24, + ID_DELETE = 25, + ID_SELECTALL = 26, + ID_PRINT = 30, + ID_VIEWSOURCE = 31, + }; + + // Event called to optionally override the default text for a context menu + // item. |label| contains the default text and may be modified to substitute + // alternate text. The return value is currently ignored. + virtual RetVal HandleGetMenuLabel(CefRefPtr browser, + MenuId menuId, std::wstring& label) =0; + + // Event called when an option is selected from the default context menu. + // Return RV_HANDLED to cancel default handling of the action. + virtual RetVal HandleMenuAction(CefRefPtr browser, + MenuId menuId) =0; + + // Event called to format print headers and footers. |printInfo| contains + // platform-specific information about the printer context. |url| is the + // URL if the currently printing page, |title| is the title of the currently + // printing page, |currentPage| is the current page number and |maxPages| is + // the total number of pages. Six default header locations are provided + // by the implementation: top left, top center, top right, bottom left, + // bottom center and bottom right. To use one of these default locations + // just assign a string to the appropriate variable. To draw the header + // and footer yourself return RV_HANDLED. Otherwise, populate the approprate + // variables and return RV_CONTINUE. + virtual RetVal HandlePrintHeaderFooter(CefRefPtr browser, + CefPrintInfo& printInfo, + const std::wstring& url, + const std::wstring& title, + int currentPage, int maxPages, + std::wstring& topLeft, + std::wstring& topCenter, + std::wstring& topRight, + std::wstring& bottomLeft, + std::wstring& bottomCenter, + std::wstring& bottomRight) =0; + + // Run a JS alert message. Return RV_CONTINUE to display the default alert + // or RV_HANDLED if you displayed a custom alert. + virtual RetVal HandleJSAlert(CefRefPtr browser, + const std::wstring& message) =0; + + // Run a JS confirm request. Return RV_CONTINUE to display the default alert + // or RV_HANDLED if you displayed a custom alert. If you handled the alert + // set |retval| to true if the user accepted the confirmation. + virtual RetVal HandleJSConfirm(CefRefPtr browser, + const std::wstring& message, bool& retval) =0; + + // Run a JS prompt request. Return RV_CONTINUE to display the default prompt + // or RV_HANDLED if you displayed a custom prompt. If you handled the prompt + // set |retval| to true if the user accepted the prompt and request and + // |result| to the resulting value. + virtual RetVal HandleJSPrompt(CefRefPtr browser, + const std::wstring& message, + const std::wstring& default_value, + bool& retval, + std::wstring& result) =0; + +}; + + +// Class used to represent a web request. +class CefRequest : public CefBase +{ +public: + typedef std::map HeaderMap; + + // Create a new CefRequest object. + static CefRefPtr CreateRequest(); + + // Fully qualified URL to load. + virtual std::wstring GetURL() =0; + virtual void SetURL(const std::wstring& url) =0; + + // Optional name of the target frame. + virtual std::wstring GetFrame() =0; + virtual void SetFrame(const std::wstring& url) =0; + + // Optional request method type, defaulting to POST if post data is provided + // and GET otherwise. + virtual std::wstring GetMethod() =0; + virtual void SetMethod(const std::wstring& method) =0; + + // Optional post data. + virtual CefRefPtr GetPostData() =0; + virtual void SetPostData(CefRefPtr postData) =0; + + // Optional header values. + virtual void GetHeaderMap(HeaderMap& headerMap) =0; + virtual void SetHeaderMap(const HeaderMap& headerMap) =0; + + // Set all values at one time. + virtual void Set(const std::wstring& url, + const std::wstring& frame, + const std::wstring& method, + CefRefPtr postData, + const HeaderMap& headerMap) =0; +}; + + +// Class used to represent post data for a web request. +class CefPostData : public CefBase +{ +public: + typedef std::vector > ElementVector; + + // Create a new CefPostData object. + static CefRefPtr CreatePostData(); + + // Returns the number of existing post data elements. + virtual size_t GetElementCount() =0; + + // Retrieve the post data elements. + virtual void GetElements(ElementVector& elements) =0; + + // Remove the specified post data element. Returns true if the removal + // succeeds. + virtual bool RemoveElement(CefRefPtr element) =0; + + // Add the specified post data element. Returns true if the add + // succeeds. + virtual bool AddElement(CefRefPtr element) =0; + + // Remove all existing post data elements. + virtual void RemoveElements() =0; +}; + + +// Class used to represent a single element in the request post data. +class CefPostDataElement : public CefBase +{ +public: + // Post data elements may represent either bytes or files. + enum Type + { + TYPE_EMPTY = 0, + TYPE_BYTES, + TYPE_FILE + }; + + // Create a new CefPostDataElement object. + static CefRefPtr CreatePostDataElement(); + + // Remove all contents from the post data element. + virtual void SetToEmpty() =0; + + // The post data element will represent a file. + virtual void SetToFile(const std::wstring& fileName) =0; + + // The post data element will represent bytes. The bytes passed + // in will be copied. + virtual void SetToBytes(size_t size, const void* bytes) =0; + + // Return the type of this post data element. + virtual Type GetType() =0; + + // Return the file name. + virtual std::wstring GetFile() =0; + + // Return the number of bytes. + virtual size_t GetBytesCount() =0; + + // Read up to |size| bytes into |bytes| and return the number of bytes + // actually read. + virtual size_t GetBytes(size_t size, void *bytes) =0; +}; + + +// Class used to read data from a stream. +class CefStreamReader : public CefBase +{ +public: + static CefRefPtr CreateForFile(const std::wstring& fileName); + static CefRefPtr CreateForData(void *data, size_t size); + + // Read raw binary data. + virtual size_t Read(void *ptr, size_t size, size_t n) =0; + + // Seek to the specified offset position. |whence| may be any one of + // SEEK_CUR, SEEK_END or SEEK_SET. + virtual int Seek(long offset, int whence) =0; + + // Return the current offset position. + virtual long Tell() =0; + + // Return non-zero if at end of file. + virtual int Eof() =0; +}; + + +// Class used to write data to a stream. +class CefStreamWriter : public CefBase +{ +public: + // Write raw binary data. + virtual size_t Write(const void *ptr, size_t size, size_t n) =0; + + // Seek to the specified offset position. |whence| may be any one of + // SEEK_CUR, SEEK_END or SEEK_SET. + virtual int Seek(long offset, int whence) =0; + + // Return the current offset position. + virtual long Tell() =0; + + // Flush the stream. + virtual int Flush() =0; +}; + + +// Class for implementing external JavaScript objects. +class CefJSHandler : public CefBase +{ +public: + typedef std::vector > VariantVector; + + // Return true if the specified method exists. + virtual bool HasMethod(CefRefPtr browser, + const std::wstring& name) =0; + + // Return true if the specified property exists. + virtual bool HasProperty(CefRefPtr browser, + const std::wstring& name) =0; + + // Set the property value. Return true if the property is accepted. + virtual bool SetProperty(CefRefPtr browser, + const std::wstring& name, + const CefRefPtr value) =0; + + // Get the property value. Return true if the value is returned. + virtual bool GetProperty(CefRefPtr browser, + const std::wstring& name, + CefRefPtr value) =0; + + // Execute a method with the specified argument vector and return + // value. Return true if the method was handled. + virtual bool ExecuteMethod(CefRefPtr browser, + const std::wstring& name, + const VariantVector& args, + CefRefPtr retval) =0; +}; + + +// Class that represents multiple data types as a single object. +class CefVariant : public CefBase +{ +public: + enum Type + { + TYPE_NULL = 0, + TYPE_BOOL, + TYPE_INT, + TYPE_DOUBLE, + TYPE_STRING, + TYPE_BOOL_ARRAY, + TYPE_INT_ARRAY, + TYPE_DOUBLE_ARRAY, + TYPE_STRING_ARRAY + }; + + // Return the variant data type. + virtual Type GetType() =0; + + // Assign various data types. + virtual void SetNull() =0; + virtual void SetBool(bool val) =0; + virtual void SetInt(int val) =0; + virtual void SetDouble(double val) =0; + virtual void SetString(const std::wstring& val) =0; + virtual void SetBoolArray(const std::vector& val) =0; + virtual void SetIntArray(const std::vector& val) =0; + virtual void SetDoubleArray(const std::vector& val) =0; + virtual void SetStringArray(const std::vector& val) =0; + + // Retrieve various data types. + virtual bool GetBool() =0; + virtual int GetInt() =0; + virtual double GetDouble() =0; + virtual std::wstring GetString() =0; + virtual bool GetBoolArray(std::vector& val) =0; + virtual bool GetIntArray(std::vector& val) =0; + virtual bool GetDoubleArray(std::vector& val) =0; + virtual bool GetStringArray(std::vector& val) =0; +}; + +#endif // _CEF_H diff --git a/include/cef_ptr.h b/include/cef_ptr.h new file mode 100644 index 000000000..7a091e2df --- /dev/null +++ b/include/cef_ptr.h @@ -0,0 +1,193 @@ +// Copyright (c) 2008 Marshall A. Greenblatt. Portions Copyright (c) +// 2006-2008 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the name Chromium Embedded +// Framework nor the names of its contributors may be used to endorse +// or promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#ifndef _CEF_PTR_H +#define _CEF_PTR_H + +// Smart pointer implementation borrowed from base/ref_counted.h +// +// A smart pointer class for reference counted objects. Use this class instead +// of calling AddRef and Release manually on a reference counted object to +// avoid common memory leaks caused by forgetting to Release an object +// reference. Sample usage: +// +// class MyFoo : public CefBase { +// ... +// }; +// +// void some_function() { +// // The MyFoo object that |foo| represents starts with a single +// // reference. +// CefRefPtr foo = new MyFoo(); +// foo->Method(param); +// // |foo| is released when this function returns +// } +// +// void some_other_function() { +// CefRefPtr foo = new MyFoo(); +// ... +// foo = NULL; // explicitly releases |foo| +// ... +// if (foo) +// foo->Method(param); +// } +// +// The above examples show how CefRefPtr acts like a pointer to T. +// Given two CefRefPtr classes, it is also possible to exchange +// references between the two objects, like so: +// +// { +// CefRefPtr a = new MyFoo(); +// CefRefPtr b; +// +// b.swap(a); +// // now, |b| references the MyFoo object, and |a| references NULL. +// } +// +// To make both |a| and |b| in the above example reference the same MyFoo +// object, simply use the assignment operator: +// +// { +// CefRefPtr a = new MyFoo(); +// CefRefPtr b; +// +// b = a; +// // now, |a| and |b| each own a reference to the same MyFoo object. +// // the reference count of the underlying MyFoo object will be 2. +// } +// +// Reference counted objects can also be passed as function parameters and +// used as function return values: +// +// void some_func_with_param(CefRefPtr param) { +// // A reference is added to the MyFoo object that |param| represents +// // during the scope of some_func_with_param() and released when +// // some_func_with_param() goes out of scope. +// } +// +// CefRefPtr some_func_with_retval() { +// // The MyFoo object that |foox| represents starts with a single +// // reference. +// CefRefPtr foox = new MyFoo(); +// +// // Creating the return value adds an additional reference. +// return foox; +// +// // When some_func_with_retval() goes out of scope the original |foox| +// // reference is released. +// } +// +// void and_another_function() { +// CefRefPtr foo = new MyFoo(); +// +// // pass |foo| as a parameter. +// some_function(foo); +// +// CefRefPtr foo2 = some_func_with_retval(); +// // Now, since we kept a reference to the some_func_with_retval() return +// // value, |foo2| is the only class pointing to the MyFoo object created +// in some_func_with_retval(), and it has a reference count of 1. +// +// some_func_with_retval(); +// // Now, since we didn't keep a reference to the some_func_with_retval() +// // return value, the MyFoo object created in some_func_with_retval() +// // will automatically be released. +// } +// +// And in standard containers: +// +// { +// // Create a vector that holds MyFoo objects. +// std::vector > MyFooVec; +// +// // The MyFoo object that |foo| represents starts with a single +// // reference. +// CefRefPtr foo = new MyFoo(); +// +// // When the MyFoo object is added to |MyFooVec| the reference count +// // is increased to 2. +// MyFooVec.push_back(foo); +// } +// +template +class CefRefPtr { + public: + CefRefPtr() : ptr_(NULL) { + } + + CefRefPtr(T* p) : ptr_(p) { + if (ptr_) + ptr_->AddRef(); + } + + CefRefPtr(const CefRefPtr& r) : ptr_(r.ptr_) { + if (ptr_) + ptr_->AddRef(); + } + + ~CefRefPtr() { + if (ptr_) + ptr_->Release(); + } + + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + T* operator->() const { return ptr_; } + + CefRefPtr& operator=(T* p) { + // AddRef first so that self assignment should work + if (p) + p->AddRef(); + if (ptr_ ) + ptr_ ->Release(); + ptr_ = p; + return *this; + } + + CefRefPtr& operator=(const CefRefPtr& r) { + return *this = r.ptr_; + } + + void swap(T** pp) { + T* p = ptr_; + ptr_ = *pp; + *pp = p; + } + + void swap(CefRefPtr& r) { + swap(&r.ptr_); + } + + private: + T* ptr_; +}; + +#endif // _CEF_PTR_H diff --git a/include/cef_win.h b/include/cef_win.h new file mode 100644 index 000000000..40aed640a --- /dev/null +++ b/include/cef_win.h @@ -0,0 +1,186 @@ +// Copyright (c) 2008 Marshall A. Greenblatt. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the name Chromium Embedded +// Framework nor the names of its contributors may be used to endorse +// or promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#ifndef _CEF_WIN_H +#define _CEF_WIN_H + +#ifdef _WIN32 +#include + +// Atomic increment and decrement. +#define CefAtomicIncrement(p) InterlockedIncrement(p) +#define CefAtomicDecrement(p) InterlockedDecrement(p) + +// Critical section wrapper. +class CefCriticalSection +{ +public: + CefCriticalSection() + { + memset(&m_sec, 0, sizeof(CRITICAL_SECTION)); + InitializeCriticalSection(&m_sec); + } + ~CefCriticalSection() + { + DeleteCriticalSection(&m_sec); + } + void Lock() + { + EnterCriticalSection(&m_sec); + } + void Unlock() + { + LeaveCriticalSection(&m_sec); + } + + CRITICAL_SECTION m_sec; +}; + +// Class representing window information. +class CefWindowInfo +{ +public: + CefWindowInfo() + { + m_dwExStyle = 0; + m_dwStyle = 0; + m_x = 0; + m_y = 0; + m_nWidth = 0; + m_nHeight = 0; + m_hWndParent = NULL; + m_hMenu = 0; + m_hWnd = NULL; + } + ~CefWindowInfo() + { + } + + CefWindowInfo(const CefWindowInfo& r) + { + *this = r; + } + + CefWindowInfo& operator=(const CefWindowInfo& r) + { + m_dwExStyle = r.m_dwExStyle; + m_windowName = r.m_windowName; + m_dwStyle = r.m_dwStyle; + m_x = r.m_x; + m_y = r.m_y; + m_nWidth = r.m_nWidth; + m_nHeight = r.m_nHeight; + m_hWndParent = r.m_hWndParent; + m_hMenu = r.m_hMenu; + m_hWnd = r.m_hWnd; + m_ClientInfo = r.m_ClientInfo; + return *this; + } + + void SetAsChild(HWND hWndParent, RECT windowRect) + { + m_dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN + | WS_CLIPSIBLINGS | WS_TABSTOP; + m_hWndParent = hWndParent; + m_x = windowRect.left; + m_y = windowRect.top; + m_nWidth = windowRect.right - windowRect.left; + m_nHeight = windowRect.bottom - windowRect.top; + } + + void SetAsPopup(HWND hWndParent, LPCTSTR windowName) + { + m_dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + m_hWndParent = hWndParent; + m_x = CW_USEDEFAULT; + m_y = CW_USEDEFAULT; + m_nWidth = CW_USEDEFAULT; + m_nHeight = CW_USEDEFAULT; + m_windowName = windowName; + } + + // Standard parameters required by CreateWindowEx() + DWORD m_dwExStyle; + std::wstring m_windowName; + DWORD m_dwStyle; + int m_x; + int m_y; + int m_nWidth; + int m_nHeight; + HWND m_hWndParent; + HMENU m_hMenu; + + // Handle for the new browser window. + HWND m_hWnd; + + // A parameter that can be used to store client-specific information. + CefRefPtr m_ClientInfo; +}; + +// Class representing print context information. +class CefPrintInfo +{ +public: + CefPrintInfo() + { + m_hDC = NULL; + m_Rect.left = m_Rect.right = m_Rect.top = m_Rect.bottom = 0; + m_Scale = 0; + } + ~CefPrintInfo() + { + } + + CefPrintInfo(const CefPrintInfo& r) + { + *this = r; + } + + CefPrintInfo& operator=(const CefPrintInfo& r) + { + m_hDC = r.m_hDC; + m_Rect.left = r.m_Rect.left; + m_Rect.right = r.m_Rect.right; + m_Rect.top = r.m_Rect.top; + m_Rect.bottom = r.m_Rect.bottom; + m_Scale = r.m_Scale; + return *this; + } + + HDC m_hDC; + RECT m_Rect; + double m_Scale; +}; + +// Window handle. +#define CefWindowHandle HWND +#endif // _WIN32 + +#endif // _CEF_WIN_H diff --git a/libcef/browser_drag_delegate.cc b/libcef/browser_drag_delegate.cc new file mode 100644 index 000000000..0c68313d4 --- /dev/null +++ b/libcef/browser_drag_delegate.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "browser_drag_delegate.h" + +#include + +#include "webkit/glue/webview.h" + +namespace { + +void GetCursorPositions(HWND hwnd, CPoint* client, CPoint* screen) { + // GetCursorPos will fail if the input desktop isn't the current desktop. + // See http://b/1173534. (0,0) is wrong, but better than uninitialized. + if (!GetCursorPos(screen)) + screen->SetPoint(0, 0); + + *client = *screen; + ScreenToClient(hwnd, client); +} + +} // anonymous namespace + +void BrowserDragDelegate::OnDragSourceCancel() { + OnDragSourceDrop(); +} + +void BrowserDragDelegate::OnDragSourceDrop() { + CPoint client; + CPoint screen; + GetCursorPositions(source_hwnd_, &client, &screen); + webview_->DragSourceEndedAt(client.x, client.y, screen.x, screen.y); +} + +void BrowserDragDelegate::OnDragSourceMove() { + CPoint client; + CPoint screen; + GetCursorPositions(source_hwnd_, &client, &screen); + webview_->DragSourceMovedTo(client.x, client.y, screen.x, screen.y); +} diff --git a/libcef/browser_drag_delegate.h b/libcef/browser_drag_delegate.h new file mode 100644 index 000000000..3a5fa0ae7 --- /dev/null +++ b/libcef/browser_drag_delegate.h @@ -0,0 +1,37 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A class that implements BaseDragSource for the test shell webview delegate. + +#ifndef _BROWSER_DRAG_DELEGATE_H +#define _BROWSER_DRAG_DELEGATE_H + +#include "base/base_drag_source.h" + +class WebView; + +class BrowserDragDelegate : public BaseDragSource { + public: + BrowserDragDelegate(HWND source_hwnd, WebView* webview) + : BaseDragSource(), + source_hwnd_(source_hwnd), + webview_(webview) { } + + protected: + // BaseDragSource + virtual void OnDragSourceCancel(); + virtual void OnDragSourceDrop(); + virtual void OnDragSourceMove(); + + private: + WebView* webview_; + + // A HWND for the source we are associated with, used for translating + // mouse coordinates from screen to client coordinates. + HWND source_hwnd_; +}; + +#endif // _BROWSER_DRAG_DELEGATE_H + diff --git a/libcef/browser_drop_delegate.cc b/libcef/browser_drop_delegate.cc new file mode 100644 index 000000000..778b92f17 --- /dev/null +++ b/libcef/browser_drop_delegate.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "browser_drop_delegate.h" + +#include "webkit/glue/webdropdata.h" +#include "webkit/glue/webview.h" + +// BaseDropTarget methods ---------------------------------------------------- +DWORD BrowserDropDelegate::OnDragEnter(IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect) { + WebDropData drop_data; + WebDropData::PopulateWebDropData(data_object, &drop_data); + + POINT client_pt = cursor_position; + ScreenToClient(GetHWND(), &client_pt); + bool valid = webview_->DragTargetDragEnter(drop_data, client_pt.x, + client_pt.y, cursor_position.x, cursor_position.y); + return valid ? DROPEFFECT_COPY : DROPEFFECT_NONE; +} + +DWORD BrowserDropDelegate::OnDragOver(IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect) { + POINT client_pt = cursor_position; + ScreenToClient(GetHWND(), &client_pt); + bool valid = webview_->DragTargetDragOver(client_pt.x, + client_pt.y, cursor_position.x, cursor_position.y); + return valid ? DROPEFFECT_COPY : DROPEFFECT_NONE; +} + +void BrowserDropDelegate::OnDragLeave(IDataObject* data_object) { + webview_->DragTargetDragLeave(); +} + +DWORD BrowserDropDelegate::OnDrop(IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect) { + POINT client_pt = cursor_position; + ScreenToClient(GetHWND(), &client_pt); + webview_->DragTargetDrop(client_pt.x, client_pt.y, + cursor_position.x, cursor_position.y); + + // webkit win port always returns DROPEFFECT_NONE + return DROPEFFECT_NONE; +} + diff --git a/libcef/browser_drop_delegate.h b/libcef/browser_drop_delegate.h new file mode 100644 index 000000000..3d5dc7471 --- /dev/null +++ b/libcef/browser_drop_delegate.h @@ -0,0 +1,43 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A class that implements BaseDropTarget for the test shell webview delegate. + +#ifndef _BROWSER_DROP_DELEGATE_H +#define _BROWSER_DROP_DELEGATE_H + +#include "base/base_drop_target.h" + +class WebView; + +class BrowserDropDelegate : public BaseDropTarget { + public: + BrowserDropDelegate(HWND source_hwnd, WebView* webview) + : BaseDropTarget(source_hwnd), + webview_(webview) { } + + protected: + // BaseDropTarget methods + virtual DWORD OnDragEnter(IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect); + virtual DWORD OnDragOver(IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect); + virtual void OnDragLeave(IDataObject* data_object); + virtual DWORD OnDrop(IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect); + + + private: + WebView* webview_; +}; + +#endif // _BROWSER_DROP_DELEGATE_H + diff --git a/libcef/browser_impl.cc b/libcef/browser_impl.cc new file mode 100644 index 000000000..07829dc2c --- /dev/null +++ b/libcef/browser_impl.cc @@ -0,0 +1,482 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "context.h" +#include "browser_impl.h" +#include "request_impl.h" + +#include "base/string_util.h" +#include "webkit/glue/webframe.h" + + +CefBrowserImpl::CefBrowserImpl(CefWindowInfo& windowInfo, bool popup, + CefRefPtr handler, + const std::wstring& url) + : window_info_(windowInfo), is_popup_(popup), is_modal_(false), + handler_(handler), webviewhost_(NULL), popuphost_(NULL), url_(url) +{ + delegate_ = new BrowserWebViewDelegate(this); + nav_controller_.reset(new BrowserNavigationController(this)); + +#if defined(OS_WIN) + webview_bitmap_size_.cx = webview_bitmap_size_.cy = 0; + webview_bitmap_ = NULL; +#endif +} + +CefBrowserImpl::~CefBrowserImpl() +{ +#if defined(OS_WIN) + if(webview_bitmap_ != NULL) + DeleteObject(webview_bitmap_); +#endif +} + +void CefBrowserImpl::GoBack() +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, CefHandler::ID_NAV_BACK, TF_MAIN)); +} + +void CefBrowserImpl::GoForward() +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_NAV_FORWARD, TF_MAIN)); +} + +void CefBrowserImpl::Reload() +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_NAV_RELOAD, TF_MAIN)); +} + +void CefBrowserImpl::StopLoad() +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_NAV_STOP, TF_MAIN)); +} + +void CefBrowserImpl::Undo(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_UNDO, targetFrame)); +} + +void CefBrowserImpl::Redo(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_REDO, targetFrame)); +} + +void CefBrowserImpl::Cut(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_CUT, targetFrame)); +} + +void CefBrowserImpl::Copy(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_COPY, targetFrame)); +} + +void CefBrowserImpl::Paste(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_PASTE, targetFrame)); +} + +void CefBrowserImpl::Delete(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_DELETE, targetFrame)); +} + +void CefBrowserImpl::SelectAll(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_SELECTALL, targetFrame)); +} + +void CefBrowserImpl::Print(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_PRINT, targetFrame)); +} + +void CefBrowserImpl::ViewSource(TargetFrame targetFrame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_HandleAction, + CefHandler::ID_VIEWSOURCE, targetFrame)); +} +void CefBrowserImpl::LoadRequest(CefRefPtr request) +{ + DCHECK(request.get() != NULL); + request->AddRef(); + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_LoadURLForRequestRef, request.get())); +} + +void CefBrowserImpl::LoadURL(const std::wstring& url, const std::wstring& frame) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_LoadURLForFrame, url, frame)); +} + +void CefBrowserImpl::LoadString(const std::wstring& string, + const std::wstring& url) +{ + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_LoadHTML, string, url)); +} + +void CefBrowserImpl::LoadStream(CefRefPtr stream, + const std::wstring& url) +{ + DCHECK(stream.get() != NULL); + stream->AddRef(); + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_LoadHTMLForStreamRef, stream.get(), url)); +} + +bool CefBrowserImpl::AddJSHandler(const std::wstring& classname, + CefRefPtr handler) +{ + bool rv = false; + + Lock(); + if(!HasJSHandler(classname)) { + CefRefPtr jscon(new CefJSContainer(this, handler)); + jscontainers_.insert(std::make_pair(classname, jscon)); + rv = true; + } + Unlock(); + + return rv; +} + +bool CefBrowserImpl::HasJSHandler(const std::wstring& classname) +{ + Lock(); + bool rv = (jscontainers_.find(classname) != jscontainers_.end()); + Unlock(); + + return rv; +} + +CefRefPtr CefBrowserImpl::GetJSHandler(const std::wstring& classname) +{ + CefRefPtr handler; + + Lock(); + JSContainerMap::const_iterator it = jscontainers_.find(classname); + if(it != jscontainers_.end()) + handler = it->second->GetHandler(); + Unlock(); + + return handler; +} + +bool CefBrowserImpl::RemoveJSHandler(const std::wstring& classname) +{ + bool rv = false; + + Lock(); + JSContainerMap::iterator it = jscontainers_.find(classname); + if(it != jscontainers_.end()) { + jscontainers_.erase(it); + rv = true; + } + Unlock(); + + return rv; +} + +void CefBrowserImpl::RemoveAllJSHandlers() +{ + Lock(); + jscontainers_.clear(); + Unlock(); +} + +bool CefBrowserImpl::IsPopup() +{ + Lock(); + bool popup = is_popup_; + Unlock(); + return popup; +} + +CefRefPtr CefBrowserImpl::GetHandler() +{ + return handler_; +} + +std::wstring CefBrowserImpl::GetURL() +{ + Lock(); + std::wstring url = url_; + Unlock(); + return url; +} + +void CefBrowserImpl::SetURL(const std::wstring& url) +{ + Lock(); + url_ = url; + Unlock(); +} + +bool CefBrowser::CreateBrowser(CefWindowInfo& windowInfo, bool popup, + CefRefPtr handler, + const std::wstring& url) +{ + if(!_Context.get()) + return false; + + std::wstring newUrl = url; + + if(handler.get()) + { + // Give the handler an opportunity to modify window attributes, handler, + // or cancel the window creation. + CefHandler::RetVal rv = + handler->HandleBeforeCreated(NULL, windowInfo, popup, handler, newUrl); + if(rv == CefHandler::RV_HANDLED) + return false; + } + + CefRefPtr browser( + new CefBrowserImpl(windowInfo, popup, handler, newUrl)); + PostTask(FROM_HERE, NewRunnableMethod(browser.get(), + &CefBrowserImpl::UIT_CreateBrowser)); + return true; +} + +void CefBrowserImpl::UIT_LoadURL(const std::wstring& url) +{ + REQUIRE_UIT(); + UIT_LoadURLForRequest(url, std::wstring(), std::wstring(), NULL, + WebRequest::HeaderMap()); +} + +void CefBrowserImpl::UIT_LoadURLForFrame(const std::wstring& url, + const std::wstring& frame_name) +{ + REQUIRE_UIT(); + UIT_LoadURLForRequest(url, frame_name, std::wstring(), NULL, + WebRequest::HeaderMap()); +} + +void CefBrowserImpl::UIT_LoadURLForRequestRef(CefRequest* request) +{ + REQUIRE_UIT(); + + std::wstring url = request->GetURL(); + std::wstring frame_name = request->GetFrame(); + std::wstring method = request->GetMethod(); + + CefRequestImpl *impl = static_cast(request); + + scoped_refptr upload_data; + CefRefPtr postdata = impl->GetPostData(); + if(postdata.get()) + { + upload_data = new net::UploadData(); + static_cast(postdata.get())->Get(*upload_data.get()); + } + + WebRequest::HeaderMap headers; + impl->GetHeaderMap(headers); + + UIT_LoadURLForRequest(url, frame_name, method, upload_data.get(), + headers); + + request->Release(); +} + +void CefBrowserImpl::UIT_GoBackOrForward(int offset) +{ + REQUIRE_UIT(); + nav_controller_->GoToOffset(offset); +} + +void CefBrowserImpl::UIT_Reload() +{ + REQUIRE_UIT(); + nav_controller_->Reload(); +} + +bool CefBrowserImpl::UIT_Navigate(const BrowserNavigationEntry& entry, + bool reload) +{ + REQUIRE_UIT(); + + WebRequestCachePolicy cache_policy; + if (reload) { + cache_policy = WebRequestReloadIgnoringCacheData; + } else if (entry.GetPageID() != -1) { + cache_policy = WebRequestReturnCacheDataElseLoad; + } else { + cache_policy = WebRequestUseProtocolCachePolicy; + } + + scoped_ptr request(WebRequest::Create(entry.GetURL())); + request->SetCachePolicy(cache_policy); + // If we are reloading, then WebKit will use the state of the current page. + // Otherwise, we give it the state to navigate to. + if (!reload) + request->SetHistoryState(entry.GetContentState()); + + request->SetExtraData( + new BrowserExtraRequestData(entry.GetPageID())); + + if(entry.GetMethod().size() > 0) + request->SetHttpMethod(WideToUTF8(entry.GetMethod())); + + if(entry.GetHeaders().size() > 0) + request->SetHttpHeaders(entry.GetHeaders()); + + if(entry.GetUploadData()) + { + if(request->GetHttpMethod() == "GET" || request->GetHttpMethod() == "HEAD") + request->SetHttpMethod("POST"); + if(request->GetHttpHeaderValue("Content-Type").size() == 0) { + request->SetHttpHeaderValue( + "Content-Type", "application/x-www-form-urlencoded"); + } + request->SetUploadData(*entry.GetUploadData()); + } + + // Get the right target frame for the entry. + WebFrame* frame = UIT_GetWebView()->GetMainFrame(); + if (!entry.GetTargetFrame().empty()) + frame = UIT_GetWebView()->GetFrameWithName(entry.GetTargetFrame()); + // TODO(mpcomplete): should we clear the target frame, or should + // back/forward navigations maintain the target frame? + + frame->LoadRequest(request.get()); + // Restore focus to the main frame prior to loading new request. + // This makes sure that we don't have a focused iframe. Otherwise, that + // iframe would keep focus when the SetFocus called immediately after + // LoadRequest, thus making some tests fail (see http://b/issue?id=845337 + // for more details). + UIT_GetWebView()->SetFocusedFrame(frame); + UIT_SetFocus(UIT_GetWebViewHost(), true); + + return true; +} + +void CefBrowserImpl::UIT_BindJSObjectsToWindow(WebFrame* frame) +{ + REQUIRE_UIT(); + + Lock(); + JSContainerMap::const_iterator it = jscontainers_.begin(); + for(; it != jscontainers_.end(); ++it) + it->second->BindToJavascript(frame, it->first); + Unlock(); +} + +CefRefPtr CefBrowserImpl::UIT_CreatePopupWindow(const std::wstring& url) +{ + REQUIRE_UIT(); + + CefWindowInfo info; + info.SetAsPopup(UIT_GetMainWndHandle(), url.c_str()); + CefRefPtr handler = handler_; + std::wstring newUrl = url; + + if(handler_.get()) + { + // Give the handler an opportunity to modify window attributes, handler, + // or cancel the window creation. + CefHandler::RetVal rv = + handler_->HandleBeforeCreated(this, info, true, handler, newUrl); + if(rv == CefHandler::RV_HANDLED) + return NULL; + } + + CefRefPtr browser( + new CefBrowserImpl(info, true, handler, newUrl)); + browser->UIT_CreateBrowser(); + + return browser; +} + +void CefBrowserImpl::UIT_Show(WebView* webview, + WindowOpenDisposition disposition) +{ + REQUIRE_UIT(); + delegate_->Show(webview, disposition); +} + +void CefBrowserImpl::UIT_HandleAction(CefHandler::MenuId menuId, + TargetFrame target) +{ + REQUIRE_UIT(); + + WebFrame* frame; + if(target == TF_FOCUSED) + frame = UIT_GetWebView()->GetFocusedFrame(); + else + frame = UIT_GetWebView()->GetMainFrame(); + + switch(menuId) + { + case CefHandler::ID_NAV_BACK: + UIT_GoBackOrForward(-1); + break; + case CefHandler::ID_NAV_FORWARD: + UIT_GoBackOrForward(1); + break; + case CefHandler::ID_NAV_RELOAD: + UIT_Reload(); + break; + case CefHandler::ID_NAV_STOP: + UIT_GetWebView()->StopLoading(); + break; + case CefHandler::ID_UNDO: + frame->Undo(); + break; + case CefHandler::ID_REDO: + frame->Redo(); + break; + case CefHandler::ID_CUT: + frame->Cut(); + break; + case CefHandler::ID_COPY: + frame->Copy(); + break; + case CefHandler::ID_PASTE: + frame->Paste(); + break; + case CefHandler::ID_DELETE: + frame->Delete(); + break; + case CefHandler::ID_SELECTALL: + frame->SelectAll(); + break; + case CefHandler::ID_PRINT: + UIT_PrintPages(frame); + break; + case CefHandler::ID_VIEWSOURCE: + UIT_ViewDocumentString(frame); + break; + } +} diff --git a/libcef/browser_impl.h b/libcef/browser_impl.h new file mode 100644 index 000000000..dc9342da9 --- /dev/null +++ b/libcef/browser_impl.h @@ -0,0 +1,229 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 _BROWSER_IMPL_H +#define _BROWSER_IMPL_H + +#include "../include/cef.h" +#include "jscontainer.h" +#include "context.h" + +#include "webview_host.h" +#include "browser_webview_delegate.h" +#include "browser_navigation_controller.h" +#if defined(OS_WIN) +#include "printing/win_printing_context.h" +#endif + +#include "webkit/glue/webview.h" + + +// Implementation of CefBrowser. +class CefBrowserImpl : public CefThreadSafeBase +{ +public: + CefBrowserImpl(CefWindowInfo& windowInfo, bool popup, + CefRefPtr handler, const std::wstring& url); + virtual ~CefBrowserImpl(); + +#if defined(OS_WIN) + static LPCTSTR GetWndClass(); + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam); +#endif + + // CefBrowser methods + virtual bool CanGoBack(); + virtual void GoBack(); + virtual bool CanGoForward(); + virtual void GoForward(); + virtual void Reload(); + virtual void StopLoad(); + virtual void Undo(TargetFrame targetFrame); + virtual void Redo(TargetFrame targetFrame); + virtual void Cut(TargetFrame targetFrame); + virtual void Copy(TargetFrame targetFrame); + virtual void Paste(TargetFrame targetFrame); + virtual void Delete(TargetFrame targetFrame); + virtual void SelectAll(TargetFrame targetFrame); + virtual void Print(TargetFrame targetFrame); + virtual void ViewSource(TargetFrame targetFrame); + virtual std::wstring GetSource(TargetFrame targetFrame); + virtual std::wstring GetText(TargetFrame targetFrame); + virtual void LoadRequest(CefRefPtr request); + virtual void LoadURL(const std::wstring& url, const std::wstring& frame); + virtual void LoadString(const std::wstring& string, + const std::wstring& url); + virtual void LoadStream(CefRefPtr stream, + const std::wstring& url); + virtual bool AddJSHandler(const std::wstring& classname, + CefRefPtr handler); + virtual bool HasJSHandler(const std::wstring& classname); + virtual CefRefPtr GetJSHandler(const std::wstring& classname); + virtual bool RemoveJSHandler(const std::wstring& classname); + virtual void RemoveAllJSHandlers(); + virtual CefWindowHandle GetWindowHandle(); + virtual bool IsPopup(); + virtual CefRefPtr GetHandler(); + virtual std::wstring GetURL(); + + void SetURL(const std::wstring& url); + + //////////////////////////////////////////////////////////// + // ALL UIT_* METHODS MUST ONLY BE CALLED ON THE UI THREAD // + //////////////////////////////////////////////////////////// + + WebView* UIT_GetWebView() const { + REQUIRE_UIT(); + return webviewhost_.get() ? webviewhost_->webview() : NULL; + } + WebViewHost* UIT_GetWebViewHost() const { + REQUIRE_UIT(); + return webviewhost_.get(); + } + HWND UIT_GetWebViewWndHandle() const { + REQUIRE_UIT(); + return webviewhost_->window_handle(); + } + WebWidget* UIT_GetPopup() const { + REQUIRE_UIT(); + return popuphost_ ? popuphost_->webwidget() : NULL; + } + WebWidgetHost* UIT_GetPopupHost() const { + REQUIRE_UIT(); + return popuphost_; + } + HWND UIT_GetPopupWndHandle() const { + REQUIRE_UIT(); + return popuphost_->window_handle(); + } + HWND UIT_GetMainWndHandle() const { + REQUIRE_UIT(); + return window_info_.m_hWnd; + } + BrowserNavigationController* UIT_GetNavigationController() { + REQUIRE_UIT(); + return nav_controller_.get(); + } + + // Return true to allow user editing such as entering text in form elements + bool UIT_AllowEditing() { return true; } + + bool UIT_IsModal() { + REQUIRE_UIT(); + return is_modal_; + } + void UIT_SetIsModal(bool val) { + REQUIRE_UIT(); + is_modal_ = val; + } + + void UIT_SetTitle(const std::wstring& title) { + REQUIRE_UIT(); + title_ = title; + } + std::wstring UIT_GetTitle() { + REQUIRE_UIT(); + return title_; + } + + // UIThread functions must be executed from the UI thread. + void UIT_CreateBrowser(); + void UIT_LoadURL(const std::wstring& url); + void UIT_LoadURLForFrame(const std::wstring& url, + const std::wstring& frame_name); + void UIT_LoadURLForRequest(const std::wstring& url, + const std::wstring& frame_name, + const std::wstring& method, + net::UploadData *upload_data, + const WebRequest::HeaderMap& headers); + void UIT_LoadURLForRequestRef(CefRequest* request); + void UIT_LoadHTML(const std::wstring& html, + const std::wstring& url); + void UIT_LoadHTMLForStreamRef(CefStreamReader* stream, + const std::wstring& url); + void UIT_GoBackOrForward(int offset); + void UIT_Reload(); + bool UIT_Navigate(const BrowserNavigationEntry& entry, bool reload); + void UIT_SetFocus(WebWidgetHost* host, bool enable); + + // Called by the WebView delegate WindowObjectCleared() method, this + // binds the C++ controller classes to window JavaScript objects. + void UIT_BindJSObjectsToWindow(WebFrame* frame); + + CefRefPtr UIT_CreatePopupWindow(const std::wstring& url); + WebWidget* UIT_CreatePopupWidget(WebView* webview); + void UIT_ClosePopupWidget(); + + void UIT_Show(WebView* webview, WindowOpenDisposition disposition); + + // Handles most simple browser actions + void UIT_HandleAction(CefHandler::MenuId menuId, TargetFrame target); + + // Save the document HTML to a temporary file and open in the default viewing + // application + bool UIT_ViewDocumentString(WebFrame *frame); +#if defined(OS_WIN) + void UIT_GetDocumentStringNotify(TargetFrame targetFrame, + CefStreamWriter* writer, HANDLE hEvent); + void UIT_GetDocumentTextNotify(TargetFrame targetFrame, + CefStreamWriter* writer, HANDLE hEvent); + void UIT_CanGoBackNotify(bool *retVal, HANDLE hEvent); + void UIT_CanGoForwardNotify(bool *retVal, HANDLE hEvent); +#endif + + bool UIT_CanGoBack() { return !nav_controller_->IsAtStart(); } + bool UIT_CanGoForward() { return !nav_controller_->IsAtEnd(); } + + // Printing support + void UIT_PrintPages(WebFrame* frame); + void UIT_PrintPage(int page_number, WebFrame* frame, int total_pages); + void UIT_SwitchFrameToDisplayMediaType(WebFrame* frame); + int UIT_SwitchFrameToPrintMediaType(WebFrame* frame); + int UIT_GetPagesCount(WebFrame* frame); + +#if defined(OS_WIN) + void UIT_DisableWebView(bool val); + bool UIT_IsWebViewDisabled() { return (webview_bitmap_ != NULL); } + + void UIT_CaptureWebViewBitmap(HBITMAP &bitmap, SIZE &size); + void UIT_SetWebViewBitmap(HBITMAP bitmap, SIZE size); + void UIT_GetWebViewBitmap(HBITMAP &bitmap, SIZE &size) + { + bitmap = webview_bitmap_; + size.cx = webview_bitmap_size_.cx; + size.cy = webview_bitmap_size_.cy; + } +#endif + +protected: + CefWindowInfo window_info_; + bool is_popup_; + bool is_modal_; + std::wstring url_; + CefRefPtr handler_; + scoped_ptr webviewhost_; + WebWidgetHost* popuphost_; + scoped_refptr delegate_; + scoped_ptr nav_controller_; + + std::wstring title_; + + // Backup the view size before printing since it needs to be overriden. This + // value is set to restore the view size when printing is done. + gfx::Size printing_view_size_; + // Context object used to manage printing. + printing::PrintingContext print_context_; + + typedef std::map > JSContainerMap; + JSContainerMap jscontainers_; + +#if defined(OS_WIN) + HBITMAP webview_bitmap_; + SIZE webview_bitmap_size_; +#endif +}; + +#endif // _BROWSER_IMPL_H diff --git a/libcef/browser_impl_win.cc b/libcef/browser_impl_win.cc new file mode 100644 index 000000000..02eb49b5b --- /dev/null +++ b/libcef/browser_impl_win.cc @@ -0,0 +1,824 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "context.h" +#include "browser_impl.h" +#include "browser_webkit_glue.h" +#include "stream_impl.h" + +#include "base/string_util.h" +#include "base/win_util.h" +#include "skia/ext/vector_canvas.h" +#include "webkit/glue/webframe.h" +#include "webkit/glue/webkit_glue.h" + +#include +#include +#include +#include + +#define BUFFER_SIZE 32768 + + +LPCTSTR CefBrowserImpl::GetWndClass() +{ + return L"CefBrowserWindow"; +} + +LRESULT CALLBACK CefBrowserImpl::WndProc(HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + CefBrowserImpl* browser = + static_cast(win_util::GetWindowUserData(hwnd)); + + switch (message) { + case WM_COMMAND: + { + int wmId = LOWORD(wParam); + int wmEvent = HIWORD(wParam); + + + } + break; + + case WM_DESTROY: + { + // Remove the browser from the list maintained by the context + _Context->RemoveBrowser(browser); + } + return 0; + + case WM_SIZE: + if (browser && browser->UIT_GetWebView()) { + // resize the web view window to the full size of the browser window + RECT rc; + GetClientRect(browser->UIT_GetMainWndHandle(), &rc); + MoveWindow(browser->UIT_GetWebViewWndHandle(), 0, 0, rc.right, rc.bottom, + TRUE); + + if(browser->UIT_IsWebViewDisabled()) { + // recreate the capture bitmap at the correct size + HBITMAP bitmap; + SIZE size; + browser->UIT_CaptureWebViewBitmap(bitmap, size); + browser->UIT_SetWebViewBitmap(bitmap, size); + } + } + return 0; + + case WM_PAINT: + if(browser->UIT_IsWebViewDisabled()) { + // when web view is disabled draw the capture bitmap + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + HBITMAP bitmap; + SIZE size; + browser->UIT_GetWebViewBitmap(bitmap, size); + + HDC hMemDC = CreateCompatibleDC(hdc); + HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, bitmap); + BitBlt(hdc, 0, 0, size.cx, size.cy, hMemDC, 0, 0, SRCCOPY); + + SelectObject(hMemDC, hOldBmp); + DeleteDC(hMemDC); + + EndPaint(hwnd, &ps); + return 0; + } + break; + + case WM_SETFOCUS: + if (browser && browser->UIT_GetWebView()) + browser->UIT_GetWebView()->SetFocus(true); + return 0; + + case WM_KILLFOCUS: + if (browser && browser->UIT_GetWebView()) + browser->UIT_GetWebView()->SetFocus(false); + return 0; + + case WM_ERASEBKGND: + return 0; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + +CefWindowHandle CefBrowserImpl::GetWindowHandle() +{ + Lock(); + CefWindowHandle handle = window_info_.m_hWnd; + Unlock(); + return handle; +} + +std::wstring CefBrowserImpl::GetSource(TargetFrame targetFrame) +{ + if(!_Context->RunningOnUIThread()) + { + // We need to send the request to the UI thread and wait for the result + + // Event that will be used to signal that data is available. Start + // in non-signaled mode so that the event will block. + HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + DCHECK(hEvent != NULL); + + CefRefPtr stream(new CefBytesWriter(BUFFER_SIZE)); + + // Request the data from the UI thread + stream->AddRef(); + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_GetDocumentStringNotify, targetFrame, stream.get(), + hEvent)); + + // Wait for the UI thread callback to tell us that the data is available + WaitForSingleObject(hEvent, INFINITE); + CloseHandle(hEvent); + + return UTF8ToWide( + static_cast(stream.get())->GetDataString()); + } + else + { + // Retrieve the frame contents directly + WebFrame* frame; + if(targetFrame == TF_FOCUSED) + frame = UIT_GetWebView()->GetFocusedFrame(); + else + frame = UIT_GetWebView()->GetMainFrame(); + + // Retrieve the document string + return UTF8ToWide(webkit_glue::GetDocumentString(frame)); + } +} + +std::wstring CefBrowserImpl::GetText(TargetFrame targetFrame) +{ + if(!_Context->RunningOnUIThread()) + { + // We need to send the request to the UI thread and wait for the result + + // Event that will be used to signal that data is available. Start + // in non-signaled mode so that the event will block. + HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + DCHECK(hEvent != NULL); + + CefRefPtr stream(new CefBytesWriter(BUFFER_SIZE)); + + // Request the data from the UI thread + stream->AddRef(); + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_GetDocumentTextNotify, targetFrame, stream.get(), + hEvent)); + + // Wait for the UI thread callback to tell us that the data is available + WaitForSingleObject(hEvent, INFINITE); + CloseHandle(hEvent); + + return UTF8ToWide( + static_cast(stream.get())->GetDataString()); + } + else + { + // Retrieve the frame contents directly + WebFrame* frame; + if(targetFrame == TF_FOCUSED) + frame = UIT_GetWebView()->GetFocusedFrame(); + else + frame = UIT_GetWebView()->GetMainFrame(); + + // Retrieve the document string + return webkit_glue::DumpDocumentText(frame); + } +} + +bool CefBrowserImpl::CanGoBack() +{ + if(!_Context->RunningOnUIThread()) + { + // We need to send the request to the UI thread and wait for the result + + // Event that will be used to signal that data is available. Start + // in non-signaled mode so that the event will block. + HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + DCHECK(hEvent != NULL); + + bool retVal = true; + + // Request the data from the UI thread + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_CanGoBackNotify, &retVal, hEvent)); + + // Wait for the UI thread callback to tell us that the data is available + WaitForSingleObject(hEvent, INFINITE); + CloseHandle(hEvent); + + return retVal; + } + else + { + // Call the method directly + return UIT_CanGoBack(); + } +} + +bool CefBrowserImpl::CanGoForward() +{ + if(!_Context->RunningOnUIThread()) + { + // We need to send the request to the UI thread and wait for the result + + // Event that will be used to signal that data is available. Start + // in non-signaled mode so that the event will block. + HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + DCHECK(hEvent != NULL); + + bool retVal = true; + + // Request the data from the UI thread + PostTask(FROM_HERE, NewRunnableMethod(this, + &CefBrowserImpl::UIT_CanGoForwardNotify, &retVal, hEvent)); + + // Wait for the UI thread callback to tell us that the data is available + WaitForSingleObject(hEvent, INFINITE); + CloseHandle(hEvent); + + return retVal; + } + else + { + // Call the method directly + return UIT_CanGoForward(); + } +} + +void CefBrowserImpl::UIT_CreateBrowser() +{ + REQUIRE_UIT(); + + // Create the new browser window + window_info_.m_hWnd = CreateWindowEx(window_info_.m_dwExStyle, GetWndClass(), + window_info_.m_windowName.c_str(), window_info_.m_dwStyle, + window_info_.m_x, window_info_.m_y, window_info_.m_nWidth, + window_info_.m_nHeight, window_info_.m_hWndParent, window_info_.m_hMenu, + _Context->GetInstanceHandle(), NULL); + DCHECK(window_info_.m_hWnd != NULL); + + // Set window user data to this object for future reference from the window + // procedure + win_util::SetWindowUserData(window_info_.m_hWnd, this); + + // Add the new browser to the list maintained by the context + _Context->AddBrowser(this); + + // Create the webview host object + webviewhost_.reset( + WebViewHost::Create(window_info_.m_hWnd, delegate_.get(), + *_Context->GetWebPreferences())); + UIT_GetWebView()->SetUseEditorDelegate(true); + delegate_->RegisterDragDrop(); + + // Size the web view window to the browser window + RECT cr; + GetClientRect(window_info_.m_hWnd, &cr); + SetWindowPos(UIT_GetWebViewWndHandle(), NULL, cr.left, cr.top, cr.right, + cr.bottom, SWP_NOZORDER | SWP_SHOWWINDOW); + + if(handler_.get()) { + // Notify the handler that we're done creating the new window + handler_->HandleAfterCreated(this); + } + + if(url_.size() > 0) + UIT_LoadURL(url_.c_str()); + else + UIT_LoadURL(L"about:blank"); +} + +void CefBrowserImpl::UIT_LoadURLForRequest(const std::wstring& url, + const std::wstring& frame_name, + const std::wstring& method, + net::UploadData *upload_data, + const WebRequest::HeaderMap& headers) +{ + REQUIRE_UIT(); + + if (url.empty()) + return; + + std::wstring urlString(url); + if (PathFileExists(url.c_str()) || PathIsUNC(url.c_str())) { + TCHAR fileURL[INTERNET_MAX_URL_LENGTH]; + DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]); + if (SUCCEEDED(UrlCreateFromPath(url.c_str(), fileURL, &fileURLLength, 0))) + urlString.assign(fileURL); + } + + nav_controller_->LoadEntry(new BrowserNavigationEntry( + -1, GURL(urlString), std::wstring(), frame_name, method, upload_data, + headers)); +} + +void CefBrowserImpl::UIT_LoadHTML(const std::wstring& html, + const std::wstring& url) +{ + REQUIRE_UIT(); + + std::wstring urlString(url); + if (PathFileExists(url.c_str()) || PathIsUNC(url.c_str())) { + TCHAR fileURL[INTERNET_MAX_URL_LENGTH]; + DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]); + if (SUCCEEDED(UrlCreateFromPath(url.c_str(), fileURL, &fileURLLength, 0))) + urlString.assign(fileURL); + } + + UIT_GetWebView()->GetMainFrame()->LoadHTMLString( + WideToUTF8(html), GURL(urlString)); +} + +void CefBrowserImpl::UIT_LoadHTMLForStreamRef(CefStreamReader* stream, + const std::wstring& url) +{ + REQUIRE_UIT(); + + std::wstring urlString(url); + if (PathFileExists(url.c_str()) || PathIsUNC(url.c_str())) { + TCHAR fileURL[INTERNET_MAX_URL_LENGTH]; + DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]); + if (SUCCEEDED(UrlCreateFromPath(url.c_str(), fileURL, &fileURLLength, 0))) + urlString.assign(fileURL); + } + + // read all of the stream data into a std::string. + std::stringstream ss; + char buff[BUFFER_SIZE]; + size_t read; + do { + read = stream->Read(buff, sizeof(char), BUFFER_SIZE-1); + if(read > 0) { + buff[read] = 0; + ss << buff; + } + } + while(read > 0); + + UIT_GetWebView()->GetMainFrame()->LoadHTMLString(ss.str(), GURL(urlString)); + + stream->Release(); +} + +void CefBrowserImpl::UIT_SetFocus(WebWidgetHost* host, bool enable) +{ + REQUIRE_UIT(); + + if (enable) + ::SetFocus(host->window_handle()); + else if (::GetFocus() == host->window_handle()) + ::SetFocus(NULL); +} + +WebWidget* CefBrowserImpl::UIT_CreatePopupWidget(WebView* webview) +{ + REQUIRE_UIT(); + + DCHECK(!popuphost_); + popuphost_ = WebWidgetHost::Create(NULL, delegate_.get()); + ShowWindow(UIT_GetPopupWndHandle(), SW_SHOW); + + return popuphost_->webwidget(); +} + +void CefBrowserImpl::UIT_ClosePopupWidget() +{ + REQUIRE_UIT(); + + PostMessage(UIT_GetPopupWndHandle(), WM_CLOSE, 0, 0); + popuphost_ = NULL; +} + + +static void WriteTextToFile(const std::string& data, + const std::wstring& file_path) +{ + FILE* fp; + errno_t err = _wfopen_s(&fp, file_path.c_str(), L"wt"); + if (err) + return; + fwrite(data.c_str(), 1, data.size(), fp); + fclose(fp); +} + +bool CefBrowserImpl::UIT_ViewDocumentString(WebFrame *frame) +{ + REQUIRE_UIT(); + + DWORD dwRetVal; + DWORD dwBufSize = 512; + TCHAR lpPathBuffer[512]; + UINT uRetVal; + TCHAR szTempName[512]; + + dwRetVal = GetTempPath(dwBufSize, // length of the buffer + lpPathBuffer); // buffer for path + if (dwRetVal > dwBufSize || (dwRetVal == 0)) + return false; + + // Create a temporary file. + uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files + TEXT("src"), // temp file name prefix + 0, // create unique name + szTempName); // buffer for name + if (uRetVal == 0) + return false; + + size_t len = wcslen(szTempName); + wcscpy(szTempName + len - 3, L"txt"); + WriteTextToFile(webkit_glue::GetDocumentString(frame), szTempName); + + int errorCode = (int)ShellExecute(UIT_GetMainWndHandle(), L"open", szTempName, + NULL, NULL, SW_SHOWNORMAL); + if(errorCode <= 32) + return false; + + return true; +} + +void CefBrowserImpl::UIT_GetDocumentStringNotify(TargetFrame targetFrame, + CefStreamWriter* writer, + HANDLE hEvent) +{ + REQUIRE_UIT(); + + WebFrame* frame; + if(targetFrame == TF_FOCUSED) + frame = UIT_GetWebView()->GetFocusedFrame(); + else + frame = UIT_GetWebView()->GetMainFrame(); + + // Retrieve the document string + std::string str = webkit_glue::GetDocumentString(frame); + // Write the document string to the stream + writer->Write(str.c_str(), str.size(), 1); + + // Notify the calling thread that the data is now available + SetEvent(hEvent); + + writer->Release(); +} + +void CefBrowserImpl::UIT_GetDocumentTextNotify(TargetFrame targetFrame, + CefStreamWriter* writer, + HANDLE hEvent) +{ + REQUIRE_UIT(); + + WebFrame* frame; + if(targetFrame == TF_FOCUSED) + frame = UIT_GetWebView()->GetFocusedFrame(); + else + frame = UIT_GetWebView()->GetMainFrame(); + + // Retrieve the document string + std::wstring str = webkit_glue::DumpDocumentText(frame); + std::string cstr = WideToUTF8(str); + // Write the document string to the stream + writer->Write(cstr.c_str(), cstr.size(), 1); + + // Notify the calling thread that the data is now available + SetEvent(hEvent); + + writer->Release(); +} + +void CefBrowserImpl::UIT_CanGoBackNotify(bool *retVal, HANDLE hEvent) +{ + REQUIRE_UIT(); + + *retVal = UIT_CanGoBack(); + + // Notify the calling thread that the data is now available + SetEvent(hEvent); +} + +void CefBrowserImpl::UIT_CanGoForwardNotify(bool *retVal, HANDLE hEvent) +{ + REQUIRE_UIT(); + + *retVal = UIT_CanGoForward(); + + // Notify the calling thread that the data is now available + SetEvent(hEvent); +} + +int CefBrowserImpl::UIT_SwitchFrameToPrintMediaType(WebFrame* frame) { + REQUIRE_UIT(); + + printing::PrintParams params; + print_context_.settings().RenderParams(¶ms); + + float ratio = static_cast(params.desired_dpi / params.dpi); + float paper_width = params.printable_size.width() * ratio; + float paper_height = params.printable_size.height() * ratio; + float minLayoutWidth = static_cast(paper_width * params.min_shrink); + float maxLayoutWidth = static_cast(paper_width * params.max_shrink); + + // Safari uses: 765 & 1224. Margins aren't exactly the same either. + // Scale = 2.222 for MDI printer. + int pages; + int width; + if (!frame->SetPrintingMode(true, + minLayoutWidth, + maxLayoutWidth, + &width)) { + NOTREACHED(); + pages = 0; + } else { + // Force to recalculate the height, otherwise it reuse the current window + // height as the default. + float effective_shrink = static_cast(width) / paper_width; + gfx::Size page_size(width, + static_cast(paper_height * effective_shrink) - 1); + WebView* view = frame->GetView(); + if (view) { + // Hack around an issue where if the current view height is higher than + // the page height, empty pages will be printed even if the bottom of the + // web page is empty. + printing_view_size_ = view->GetSize(); + view->Resize(page_size); + view->Layout(); + } + pages = frame->ComputePageRects(params.printable_size); + DCHECK(pages); + } + return pages; +} + +void CefBrowserImpl::UIT_SwitchFrameToDisplayMediaType(WebFrame* frame) { + REQUIRE_UIT(); + + // TODO(cef): Figure out how to make the frame redraw properly after printing + // to PDF file (currently leaves a white rectangle behind the save as dialog). + + // Set the layout back to "normal" document; i.e. CSS media type = "screen". + frame->SetPrintingMode(false, 0, 0, NULL); + WebView* view = frame->GetView(); + if (view) { + // Restore from the hack described at SwitchFrameToPrintMediaType(). + view->Resize(printing_view_size_); + view->Layout(); + printing_view_size_.SetSize(0, 0); + } +} + +void CefBrowserImpl::UIT_PrintPage(int page_number, WebFrame* frame, + int total_pages) { + REQUIRE_UIT(); + + if (printing_view_size_.width() < 0) { + NOTREACHED(); + return; + } + + printing::PrintParams params; + const printing::PrintSettings &settings = print_context_.settings(); + settings.RenderParams(¶ms); + + gfx::Size src_size = frame->GetView()->GetSize(); + double src_size_x = src_size.width(); + double src_size_y = src_size.height(); + double src_margin = .1 * src_size_x; + + double dest_size_x = settings.page_setup_pixels().physical_size().width(); + double dest_size_y = settings.page_setup_pixels().physical_size().height(); + double dest_margin = .1 * dest_size_x; + + print_context_.NewPage(); + + HDC hDC = print_context_.context(); + BOOL res; + + // Save the state to make sure the context this function call does not modify + // the device context. + int saved_state = SaveDC(hDC); + DCHECK_NE(saved_state, 0); + + // 100% GDI based. + gfx::VectorCanvas canvas(hDC, (int)ceil(dest_size_x), (int)ceil(dest_size_y)); + canvas.translate(SkDoubleToScalar(dest_margin), + SkDoubleToScalar(dest_margin)); + canvas.scale(SkDoubleToScalar((dest_size_x - dest_margin * 2) / src_size_x), + SkDoubleToScalar((dest_size_y - dest_margin * 2) / src_size_y)); + + // Set the clipping region to be sure to not overflow. + SkRect clip_rect; + clip_rect.set(0, 0, SkDoubleToScalar(src_size_x), + SkDoubleToScalar(src_size_y)); + canvas.clipRect(clip_rect); + + if (!frame->SpoolPage(page_number-1, &canvas)) { + NOTREACHED() << "Printing page " << page_number << " failed."; + return; + } + + res = RestoreDC(hDC, saved_state); + DCHECK_NE(res, 0); + + if(handler_.get()) { + saved_state = SaveDC(hDC); + DCHECK_NE(saved_state, 0); + + // Gather print header state information + RECT rect; + rect.left = (int)floor(dest_margin / 2); + rect.top = rect.left; + rect.right = (int)ceil(dest_size_x - dest_margin / 2); + rect.bottom = (int)ceil(dest_size_y - dest_margin / 2); + + double scale = (double)settings.dpi() / (double)settings.desired_dpi; + + CefPrintInfo printInfo; + + printInfo.m_hDC = hDC; + printInfo.m_Rect = rect; + printInfo.m_Scale = scale; + + std::wstring url = UTF8ToWide(frame->GetURL().spec()); + std::wstring title = title_; + + std::wstring topLeft, topCenter, topRight; + std::wstring bottomLeft, bottomCenter, bottomRight; + + // allow the handler to format print header and/or footer + CefHandler::RetVal rv = handler_->HandlePrintHeaderFooter(this, printInfo, + url, title, page_number, total_pages, topLeft, topCenter, topRight, + bottomLeft, bottomCenter, bottomRight); + + if(rv != CefHandler::RV_HANDLED) { + // Draw handler-defined headers and/or footers. + LOGFONT lf; + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = (int)ceil(10. * scale); + lf.lfPitchAndFamily = FF_SWISS; + HFONT hFont = CreateFontIndirect(&lf); + + HFONT hOldFont = (HFONT)SelectObject(hDC, hFont); + COLORREF hOldColor = SetTextColor(hDC, RGB(0,0,0)); + int hOldBkMode = SetBkMode(hDC, TRANSPARENT); + + // TODO(cef): Keep the header strings inside a reasonable bounding box + // so that they don't overlap each other. + if(topLeft.size() > 0) { + DrawText(hDC, topLeft.c_str(), topLeft.size(), &rect, + DT_LEFT | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS + | DT_EXPANDTABS | DT_NOPREFIX); + } + if(topCenter.size() > 0) { + DrawText(hDC, topCenter.c_str(), topCenter.size(), &rect, + DT_CENTER | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS + | DT_EXPANDTABS | DT_NOPREFIX); + } + if(topRight.size() > 0) { + DrawText(hDC, topRight.c_str(), topRight.size(), &rect, + DT_RIGHT | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS + | DT_EXPANDTABS | DT_NOPREFIX); + } + if(bottomLeft.size() > 0) { + DrawText(hDC, bottomLeft.c_str(), bottomLeft.size(), &rect, + DT_LEFT | DT_BOTTOM | DT_SINGLELINE | DT_END_ELLIPSIS + | DT_EXPANDTABS | DT_NOPREFIX); + } + if(bottomCenter.size() > 0) { + DrawText(hDC, bottomCenter.c_str(), bottomCenter.size(), &rect, + DT_CENTER | DT_BOTTOM | DT_SINGLELINE | DT_END_ELLIPSIS + | DT_EXPANDTABS | DT_NOPREFIX); + } + if(bottomRight.size() > 0) { + DrawText(hDC, bottomRight.c_str(), bottomRight.size(), &rect, + DT_RIGHT | DT_BOTTOM | DT_SINGLELINE | DT_END_ELLIPSIS + | DT_EXPANDTABS | DT_NOPREFIX); + } + + SetTextColor(hDC, hOldColor); + SelectObject(hDC, hOldFont); + DeleteObject(hFont); + SetBkMode(hDC, hOldBkMode); + } + + res = RestoreDC(hDC, saved_state); + DCHECK_NE(res, 0); + } + + print_context_.PageDone(); +} + +void CefBrowserImpl::UIT_PrintPages(WebFrame* frame) { + + REQUIRE_UIT(); + + TCHAR printername[512]; + DWORD size = sizeof(printername)-1; + if(GetDefaultPrinter(printername, &size)) { + printing::PrintSettings settings; + settings.set_device_name(printername); + // Initialize it. + print_context_.InitWithSettings(settings); + } + + if(print_context_.AskUserForSettings( + UIT_GetMainWndHandle(), UIT_GetPagesCount(frame)) + != printing::PrintingContext::OK) + return; + + printing::PrintParams params; + const printing::PrintSettings &settings = print_context_.settings(); + + settings.RenderParams(¶ms); + + // disable the web view so we don't see printing related layout changes on + // the screen + UIT_DisableWebView(true); + + int pages = UIT_SwitchFrameToPrintMediaType(frame); + if (pages) { + bool old_state = MessageLoop::current()->NestableTasksAllowed(); + MessageLoop::current()->SetNestableTasksAllowed(false); + + // TODO(cef): Use the page title as the document name + print_context_.NewDocument(L"New Document"); + if(settings.ranges.size() > 0) { + for (unsigned i = 0; i < settings.ranges.size(); ++i) { + const printing::PageRange& range = settings.ranges[i]; + for(int i = range.from; i <= range.to; ++i) + UIT_PrintPage(i, frame, pages); + } + } else { + for(int i = 1; i <= pages; ++i) + UIT_PrintPage(i, frame, pages); + } + print_context_.DocumentDone(); + + MessageLoop::current()->SetNestableTasksAllowed(old_state); + } + UIT_SwitchFrameToDisplayMediaType(frame); + + // re-enable web view + UIT_DisableWebView(false); +} + +int CefBrowserImpl::UIT_GetPagesCount(WebFrame* frame) +{ + REQUIRE_UIT(); + + int pages = UIT_SwitchFrameToPrintMediaType(frame); + UIT_SwitchFrameToDisplayMediaType(frame); + return pages; +} + +void CefBrowserImpl::UIT_CaptureWebViewBitmap(HBITMAP &bitmap, SIZE &size) +{ + REQUIRE_UIT(); + + webkit_glue::CaptureWebViewBitmap(UIT_GetMainWndHandle(), UIT_GetWebView(), + bitmap, size); +} + +void CefBrowserImpl::UIT_SetWebViewBitmap(HBITMAP bitmap, SIZE size) +{ + REQUIRE_UIT(); + + if(webview_bitmap_) + DeleteObject(webview_bitmap_); + webview_bitmap_ = bitmap; + webview_bitmap_size_ = size; +} + +void CefBrowserImpl::UIT_DisableWebView(bool val) +{ + REQUIRE_UIT(); + + if(val) { + // disable the web view window + if(webview_bitmap_ != NULL) + return; + + HBITMAP bitmap; + SIZE size; + UIT_CaptureWebViewBitmap(bitmap, size); + UIT_SetWebViewBitmap(bitmap, size); + + DWORD dwStyle = GetWindowLong(UIT_GetWebViewWndHandle(), GWL_STYLE); + SetWindowLong(UIT_GetWebViewWndHandle(), GWL_STYLE, dwStyle & ~WS_VISIBLE); + RedrawWindow(UIT_GetMainWndHandle(), NULL, NULL, RDW_INVALIDATE); + } else if(webview_bitmap_) { + // enable the web view window + SIZE size = {0,0}; + UIT_SetWebViewBitmap(NULL, size); + + DWORD dwStyle = GetWindowLong(UIT_GetWebViewWndHandle(), GWL_STYLE); + SetWindowLong(UIT_GetWebViewWndHandle(), GWL_STYLE, dwStyle | WS_VISIBLE); + RedrawWindow(UIT_GetMainWndHandle(), NULL, NULL, RDW_INVALIDATE); + } +} diff --git a/libcef/browser_navigation_controller.cc b/libcef/browser_navigation_controller.cc new file mode 100644 index 000000000..ac86502a6 --- /dev/null +++ b/libcef/browser_navigation_controller.cc @@ -0,0 +1,258 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "browser_navigation_controller.h" +#include "browser_impl.h" + +#include "base/logging.h" +#include "net/base/upload_data.h" +#include "webkit/glue/webhistoryitem.h" + +// ---------------------------------------------------------------------------- +// BrowserNavigationEntry + +BrowserNavigationEntry::BrowserNavigationEntry() + : page_id_(-1) { +} + +BrowserNavigationEntry::BrowserNavigationEntry(int page_id, + const GURL& url, + const std::wstring& title, + const std::wstring& target_frame, + const std::wstring& method, + net::UploadData *upload, + const WebRequest::HeaderMap& headers) + : page_id_(page_id), + url_(url), + title_(title), + target_frame_(target_frame), + method_(method), + upload_(upload), + headers_(headers) { +} + +BrowserNavigationEntry::~BrowserNavigationEntry() { +} + +void BrowserNavigationEntry::SetContentState(const std::string& state) { + cached_history_item_ = NULL; // invalidate our cached item + state_ = state; +} + +WebHistoryItem* BrowserNavigationEntry::GetHistoryItem() const { + // TODO(port): temporary hack to get a basic test shell executable going. +#if !defined(OS_LINUX) + if (!cached_history_item_) { + BrowserExtraRequestData* extra_data = + new BrowserExtraRequestData(GetPageID()); + cached_history_item_ = + WebHistoryItem::Create(GetURL(), GetTitle(), GetContentState(), + extra_data); + } +#endif + return cached_history_item_; +} + +// ---------------------------------------------------------------------------- +// BrowserNavigationController + +BrowserNavigationController::BrowserNavigationController(CefBrowserImpl* shell) + : pending_entry_(NULL), + last_committed_entry_index_(-1), + pending_entry_index_(-1), + browser_(shell), + max_page_id_(-1) { +} + +BrowserNavigationController::~BrowserNavigationController() { + DiscardPendingEntry(); +} + +void BrowserNavigationController::Reset() { + entries_.clear(); + DiscardPendingEntry(); + + last_committed_entry_index_ = -1; +} + +void BrowserNavigationController::Reload() { + // Base the navigation on where we are now... + int current_index = GetCurrentEntryIndex(); + + // If we are no where, then we can't reload. TODO(darin): We should add a + // CanReload method. + if (current_index == -1) + return; + + DiscardPendingEntry(); + + pending_entry_index_ = current_index; + NavigateToPendingEntry(true); +} + +void BrowserNavigationController::GoToOffset(int offset) { + int index = last_committed_entry_index_ + offset; + if (index < 0 || index >= GetEntryCount()) + return; + + GoToIndex(index); +} + +void BrowserNavigationController::GoToIndex(int index) { + DCHECK(index >= 0); + DCHECK(index < static_cast(entries_.size())); + + DiscardPendingEntry(); + + pending_entry_index_ = index; + NavigateToPendingEntry(false); +} + +void BrowserNavigationController::LoadEntry(BrowserNavigationEntry* entry) { + // When navigating to a new page, we don't know for sure if we will actually + // end up leaving the current page. The new page load could for example + // result in a download or a 'no content' response (e.g., a mailto: URL). + DiscardPendingEntry(); + pending_entry_ = entry; + NavigateToPendingEntry(false); +} + + +BrowserNavigationEntry* BrowserNavigationController::GetLastCommittedEntry() const { + if (last_committed_entry_index_ == -1) + return NULL; + return entries_[last_committed_entry_index_].get(); +} + +BrowserNavigationEntry* BrowserNavigationController::GetActiveEntry() const { + BrowserNavigationEntry* entry = pending_entry_; + if (!entry) + entry = GetLastCommittedEntry(); + return entry; +} + +int BrowserNavigationController::GetCurrentEntryIndex() const { + if (pending_entry_index_ != -1) + return pending_entry_index_; + return last_committed_entry_index_; +} + + +BrowserNavigationEntry* BrowserNavigationController::GetEntryAtOffset( + int offset) const { + int index = last_committed_entry_index_ + offset; + if (index < 0 || index >= GetEntryCount()) + return NULL; + + return entries_[index].get(); +} + +BrowserNavigationEntry* BrowserNavigationController::GetEntryWithPageID( + int32 page_id) const { + int index = GetEntryIndexWithPageID(page_id); + return (index != -1) ? entries_[index].get() : NULL; +} + +void BrowserNavigationController::DidNavigateToEntry(BrowserNavigationEntry* entry) { + // If the entry is that of a page with PageID larger than any this Tab has + // seen before, then consider it a new navigation. + if (entry->GetPageID() > GetMaxPageID()) { + InsertEntry(entry); + return; + } + + // Otherwise, we just need to update an existing entry with matching PageID. + // If the existing entry corresponds to the entry which is pending, then we + // must update the current entry index accordingly. When navigating to the + // same URL, a new PageID is not created. + + int existing_entry_index = GetEntryIndexWithPageID(entry->GetPageID()); + BrowserNavigationEntry* existing_entry = (existing_entry_index != -1) ? + entries_[existing_entry_index].get() : NULL; + if (!existing_entry) { + // No existing entry, then simply ignore this navigation! + DLOG(WARNING) << "ignoring navigation for page: " << entry->GetPageID(); + } else if (existing_entry == pending_entry_) { + // The given entry might provide a new URL... e.g., navigating back to a + // page in session history could have resulted in a new client redirect. + existing_entry->SetURL(entry->GetURL()); + existing_entry->SetContentState(entry->GetContentState()); + last_committed_entry_index_ = pending_entry_index_; + pending_entry_index_ = -1; + pending_entry_ = NULL; + } else if (pending_entry_ && pending_entry_->GetPageID() == -1 && + pending_entry_->GetURL() == existing_entry->GetURL()) { + // Not a new navigation + DiscardPendingEntry(); + } else { + // The given entry might provide a new URL... e.g., navigating to a page + // might result in a client redirect, which should override the URL of the + // existing entry. + existing_entry->SetURL(entry->GetURL()); + existing_entry->SetContentState(entry->GetContentState()); + + // The navigation could have been issued by the renderer, so be sure that + // we update our current index. + last_committed_entry_index_ = existing_entry_index; + } + + delete entry; + UpdateMaxPageID(); +} + +void BrowserNavigationController::DiscardPendingEntry() { + if (pending_entry_index_ == -1) + delete pending_entry_; + pending_entry_ = NULL; + pending_entry_index_ = -1; +} + +void BrowserNavigationController::InsertEntry(BrowserNavigationEntry* entry) { + DiscardPendingEntry(); + + // Prune any entry which are in front of the current entry + int current_size = static_cast(entries_.size()); + if (current_size > 0) { + while (last_committed_entry_index_ < (current_size - 1)) { + entries_.pop_back(); + current_size--; + } + } + + entries_.push_back(linked_ptr(entry)); + last_committed_entry_index_ = static_cast(entries_.size()) - 1; + UpdateMaxPageID(); +} + +int BrowserNavigationController::GetEntryIndexWithPageID(int32 page_id) const { + for (int i = static_cast(entries_.size())-1; i >= 0; --i) { + if (entries_[i]->GetPageID() == page_id) + return i; + } + return -1; +} + +void BrowserNavigationController::NavigateToPendingEntry(bool reload) { + // For session history navigations only the pending_entry_index_ is set. + if (!pending_entry_) { + DCHECK(pending_entry_index_ != -1); + pending_entry_ = entries_[pending_entry_index_].get(); + } + + if (browser_->UIT_Navigate(*pending_entry_, reload)) { + // Note: this is redundant if navigation completed synchronously because + // DidNavigateToEntry call this as well. + UpdateMaxPageID(); + } else { + DiscardPendingEntry(); + } +} + +void BrowserNavigationController::UpdateMaxPageID() { + BrowserNavigationEntry* entry = GetActiveEntry(); + if (entry) + max_page_id_ = std::max(max_page_id_, entry->GetPageID()); +} diff --git a/libcef/browser_navigation_controller.h b/libcef/browser_navigation_controller.h new file mode 100644 index 000000000..2fc69f1e3 --- /dev/null +++ b/libcef/browser_navigation_controller.h @@ -0,0 +1,220 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 _BROWSER_NAVIGATION_CONTROLLER_H +#define _BROWSER_NAVIGATION_CONTROLLER_H + +#include +#include + +#include "base/basictypes.h" +#include "base/linked_ptr.h" +#include "base/ref_counted.h" +#include "googleurl/src/gurl.h" +#include "webkit/glue/weburlrequest.h" + +namespace net { +class UploadData; +} + +class GURL; +class CefBrowserImpl; +class WebHistoryItem; + +// Associated with browser-initated navigations to hold tracking data. +class BrowserExtraRequestData : public WebRequest::ExtraData { + public: + BrowserExtraRequestData(int32 pending_page_id) + : WebRequest::ExtraData(), + pending_page_id(pending_page_id), + request_committed(false) { + } + + // Contains the page_id for this navigation or -1 if there is none yet. + int32 pending_page_id; + + // True if we have already processed the "DidCommitLoad" event for this + // request. Used by session history. + bool request_committed; +}; + +// Stores one back/forward navigation state for the test shell. +class BrowserNavigationEntry { + public: + BrowserNavigationEntry(); + BrowserNavigationEntry(int page_id, + const GURL& url, + const std::wstring& title, + const std::wstring& target_frame, + const std::wstring& method, + net::UploadData *upload, + const WebRequest::HeaderMap& headers); + + // Virtual to allow test_shell to extend the class. + ~BrowserNavigationEntry(); + + // Set / Get the URI + void SetURL(const GURL& url) { url_ = url; } + const GURL& GetURL() const { return url_; } + + // Set / Get the title + void SetTitle(const std::wstring& a_title) { title_ = a_title; } + const std::wstring& GetTitle() const { return title_; } + + // Set / Get opaque state. + // WARNING: This state is saved to the database and used to restore previous + // states. If you use write a custom TabContents and provide your own + // state make sure you have the ability to modify the format in the future + // while being able to deal with older versions. + void SetContentState(const std::string& state); + const std::string& GetContentState() const { return state_; } + + // Get the page id corresponding to the tab's state. + void SetPageID(int page_id) { page_id_ = page_id; } + int32 GetPageID() const { return page_id_; } + + WebHistoryItem* GetHistoryItem() const; + const std::wstring& GetTargetFrame() const { return target_frame_; } + + const std::wstring& GetMethod() const { return method_; } + net::UploadData* GetUploadData() const { return upload_.get(); } + const WebRequest::HeaderMap& GetHeaders() const { return headers_; } + +private: + // Describes the current page that the tab represents. This is not relevant + // for all tab contents types. + int32 page_id_; + + GURL url_; + std::wstring title_; + std::string state_; + std::wstring method_; + scoped_refptr upload_; + WebRequest::HeaderMap headers_; + + mutable scoped_refptr cached_history_item_; + + std::wstring target_frame_; + + DISALLOW_COPY_AND_ASSIGN(BrowserNavigationEntry); +}; + +// Browser's NavigationController. The goal is to be as close to the Chrome +// version as possible. +class BrowserNavigationController { + public: + BrowserNavigationController(CefBrowserImpl* shell); + ~BrowserNavigationController(); + + void Reset(); + + // Causes the controller to reload the current (or pending) entry. + void Reload(); + + // Causes the controller to go to the specified offset from current. Does + // nothing if out of bounds. + void GoToOffset(int offset); + + // Causes the controller to go to the specified index. + void GoToIndex(int index); + + // Causes the controller to load the specified entry. The controller + // assumes ownership of the entry. + // NOTE: Do not pass an entry that the controller already owns! + void LoadEntry(BrowserNavigationEntry* entry); + + // Returns the last committed entry, which may be null if there are no + // committed entries. + BrowserNavigationEntry* GetLastCommittedEntry() const; + + // Returns the number of entries in the NavigationControllerBase, excluding + // the pending entry if there is one. + int GetEntryCount() const { + return static_cast(entries_.size()); + } + + // Returns the active entry, which is the pending entry if a navigation is in + // progress or the last committed entry otherwise. NOTE: This can be NULL!! + // + // If you are trying to get the current state of the NavigationControllerBase, + // this is the method you will typically want to call. + BrowserNavigationEntry* GetActiveEntry() const; + + // Returns the index from which we would go back/forward or reload. This is + // the last_committed_entry_index_ if pending_entry_index_ is -1. Otherwise, + // it is the pending_entry_index_. + int GetCurrentEntryIndex() const; + + // Returns the entry at the specified offset from current. Returns NULL + // if out of bounds. + BrowserNavigationEntry* GetEntryAtOffset(int offset) const; + + // Return the entry with the corresponding type and page_id, or NULL if + // not found. + BrowserNavigationEntry* GetEntryWithPageID(int32 page_id) const; + + // Returns the index of the last committed entry. + int GetLastCommittedEntryIndex() const { + return last_committed_entry_index_; + } + + // Returns true if there are no entries before the last committed entry. + bool IsAtStart() const { + return (GetLastCommittedEntryIndex() == 0); + } + + // Returns true if there are no entries after the last committed entry. + bool IsAtEnd() const { + return (GetLastCommittedEntryIndex() == GetEntryCount()-1); + } + + // Used to inform us of a navigation being committed for a tab. We will take + // ownership of the entry. Any entry located forward to the current entry will + // be deleted. The new entry becomes the current entry. + void DidNavigateToEntry(BrowserNavigationEntry* entry); + + // Used to inform us to discard its pending entry. + void DiscardPendingEntry(); + + private: + // Inserts an entry after the current position, removing all entries after it. + // The new entry will become the active one. + void InsertEntry(BrowserNavigationEntry* entry); + + int GetMaxPageID() const { return max_page_id_; } + void NavigateToPendingEntry(bool reload); + + // Return the index of the entry with the corresponding type and page_id, + // or -1 if not found. + int GetEntryIndexWithPageID(int32 page_id) const; + + // Updates the max page ID with that of the given entry, if is larger. + void UpdateMaxPageID(); + + // List of NavigationEntry for this tab + typedef std::vector< linked_ptr > NavigationEntryList; + typedef NavigationEntryList::iterator NavigationEntryListIterator; + NavigationEntryList entries_; + + // An entry we haven't gotten a response for yet. This will be discarded + // when we navigate again. It's used only so we know what the currently + // displayed tab is. + BrowserNavigationEntry* pending_entry_; + + // currently visible entry + int last_committed_entry_index_; + + // index of pending entry if it is in entries_, or -1 if pending_entry_ is a + // new entry (created by LoadURL). + int pending_entry_index_; + + CefBrowserImpl* browser_; + int max_page_id_; + + DISALLOW_EVIL_CONSTRUCTORS(BrowserNavigationController); +}; + +#endif // _BROWSER_NAVIGATION_CONTROLLER_H + diff --git a/libcef/browser_request_context.cc b/libcef/browser_request_context.cc new file mode 100644 index 000000000..3f8b90bae --- /dev/null +++ b/libcef/browser_request_context.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "browser_request_context.h" + +#include "net/base/cookie_monster.h" +#include "webkit/glue/webkit_glue.h" + +BrowserRequestContext::BrowserRequestContext() { + Init(std::wstring(), net::HttpCache::NORMAL); +} + +BrowserRequestContext::BrowserRequestContext( + const std::wstring& cache_path, + net::HttpCache::Mode cache_mode) { + Init(cache_path, cache_mode); +} + +void BrowserRequestContext::Init( + const std::wstring& cache_path, + net::HttpCache::Mode cache_mode) { + cookie_store_ = new net::CookieMonster(); + + user_agent_ = webkit_glue::GetUserAgent(); + + // hard-code A-L and A-C for test shells + accept_language_ = "en-us,en"; + accept_charset_ = "iso-8859-1,*,utf-8"; + + net::HttpCache *cache; + if (cache_path.empty()) { + cache = new net::HttpCache(NULL, 0); + } else { + cache = new net::HttpCache(NULL, cache_path, 0); + } + cache->set_mode(cache_mode); + http_transaction_factory_ = cache; +} + +BrowserRequestContext::~BrowserRequestContext() { + delete cookie_store_; + delete http_transaction_factory_; +} + diff --git a/libcef/browser_request_context.h b/libcef/browser_request_context.h new file mode 100644 index 000000000..a1a3c85d4 --- /dev/null +++ b/libcef/browser_request_context.h @@ -0,0 +1,30 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 _BROWSER_REQUEST_CONTEXT_H +#define _BROWSER_REQUEST_CONTEXT_H + +#include "net/http/http_cache.h" +#include "net/url_request/url_request_context.h" + +// A basic URLRequestContext that only provides an in-memory cookie store. +class BrowserRequestContext : public URLRequestContext { + public: + // Use an in-memory cache + BrowserRequestContext(); + + // Use an on-disk cache at the specified location. Optionally, use the cache + // in playback or record mode. + BrowserRequestContext(const std::wstring& cache_path, + net::HttpCache::Mode cache_mode); + + ~BrowserRequestContext(); + + private: + void Init(const std::wstring& cache_path, net::HttpCache::Mode cache_mode); +}; + +#endif // _BROWSER_REQUEST_CONTEXT_H + diff --git a/libcef/browser_resource_loader_bridge.cc b/libcef/browser_resource_loader_bridge.cc new file mode 100644 index 000000000..aa12ceae0 --- /dev/null +++ b/libcef/browser_resource_loader_bridge.cc @@ -0,0 +1,656 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file contains an implementation of the ResourceLoaderBridge class. +// The class is implemented using URLRequest, meaning it is a "simple" version +// that directly issues requests. The more complicated one used in the +// browser uses IPC. +// +// Because URLRequest only provides an asynchronous resource loading API, this +// file makes use of URLRequest from a background IO thread. Requests for +// cookies and synchronously loaded resources result in the main thread of the +// application blocking until the IO thread completes the operation. (See +// GetCookies and SyncLoad) +// +// Main thread IO thread +// ----------- --------- +// ResourceLoaderBridge <---o---------> RequestProxy (normal case) +// \ -> URLRequest +// o-------> SyncRequestProxy (synchronous case) +// -> URLRequest +// SetCookie <------------------------> CookieSetter +// -> net_util::SetCookie +// GetCookies <-----------------------> CookieGetter +// -> net_util::GetCookies +// +// NOTE: The implementation in this file may be used to have WebKit fetch +// resources in-process. For example, it is handy for building a single- +// process WebKit embedding (e.g., test_shell) that can use URLRequest to +// perform URL loads. See renderer/resource_dispatcher.h for details on an +// alternate implementation that defers fetching to another process. + +#include "precompiled_libcef.h" +#include "browser_resource_loader_bridge.h" +#include "browser_request_context.h" +#include "browser_impl.h" +#include "request_impl.h" + +#include "base/message_loop.h" +#include "base/ref_counted.h" +#include "base/string_util.h" +#include "base/thread.h" +#include "base/waitable_event.h" +#include "net/base/cookie_monster.h" +#include "net/base/net_util.h" +#include "net/base/upload_data.h" +#include "net/url_request/url_request.h" +#include "webkit/glue/resource_loader_bridge.h" +#include "webkit/glue/webframe.h" +#include "webkit/glue/webview.h" + +using webkit_glue::ResourceLoaderBridge; +using net::HttpResponseHeaders; + +namespace { + +//----------------------------------------------------------------------------- + +URLRequestContext* request_context = NULL; +base::Thread* io_thread = NULL; + +class IOThread : public base::Thread { + public: + IOThread() : base::Thread("IOThread") { + } + + ~IOThread() { + // We cannot rely on our base class to stop the thread since we want our + // CleanUp function to run. + Stop(); + } + + virtual void CleanUp() { + if (request_context) { + request_context->Release(); + request_context = NULL; + } + } +}; + +bool EnsureIOThread() { + if (io_thread) + return true; + + if (!request_context) + BrowserResourceLoaderBridge::Init(NULL); + + io_thread = new IOThread(); + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + return io_thread->StartWithOptions(options); +} + +//----------------------------------------------------------------------------- + +struct RequestParams { + std::string method; + GURL url; + GURL policy_url; + GURL referrer; + std::string headers; + int load_flags; + scoped_refptr upload; +}; + +// The RequestProxy does most of its work on the IO thread. The Start and +// Cancel methods are proxied over to the IO thread, where an URLRequest object +// is instantiated. +class RequestProxy : public URLRequest::Delegate, + public base::RefCountedThreadSafe { + public: + // Takes ownership of the params. + RequestProxy(CefRefPtr browser) + : browser_(browser) + { + } + + virtual ~RequestProxy() { + // If we have a request, then we'd better be on the io thread! + DCHECK(!request_.get() || + MessageLoop::current() == io_thread->message_loop()); + } + + void DropPeer() { + peer_ = NULL; + } + + void Start(ResourceLoaderBridge::Peer* peer, RequestParams* params) { + peer_ = peer; + owner_loop_ = MessageLoop::current(); + + // proxy over to the io thread + io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RequestProxy::AsyncStart, params)); + } + + void Cancel() { + // proxy over to the io thread + io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RequestProxy::AsyncCancel)); + } + + protected: + // -------------------------------------------------------------------------- + // The following methods are called on the owner's thread in response to + // various URLRequest callbacks. The event hooks, defined below, trigger + // these methods asynchronously. + + void NotifyReceivedRedirect(const GURL& new_url) { + if (peer_) + peer_->OnReceivedRedirect(new_url); + } + + void NotifyReceivedResponse(const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { + if (peer_) + peer_->OnReceivedResponse(info, content_filtered); + } + + void NotifyReceivedData(int bytes_read) { + if (!peer_) + return; + + // Make a local copy of buf_, since AsyncReadData reuses it. + scoped_array buf_copy(new char[bytes_read]); + memcpy(buf_copy.get(), buf_, bytes_read); + + // Continue reading more data into buf_ + // Note: Doing this before notifying our peer ensures our load events get + // dispatched in a manner consistent with DumpRenderTree (and also avoids a + // race condition). If the order of the next 2 functions were reversed, the + // peer could generate new requests in reponse to the received data, which + // when run on the io thread, could race against this function in doing + // another InvokeLater. See bug 769249. + io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RequestProxy::AsyncReadData)); + + peer_->OnReceivedData(buf_copy.get(), bytes_read); + } + + void NotifyCompletedRequest(const URLRequestStatus& status) { + if (peer_) { + peer_->OnCompletedRequest(status); + DropPeer(); // ensure no further notifications + } + } + + // -------------------------------------------------------------------------- + // The following methods are called on the io thread. They correspond to + // actions performed on the owner's thread. + + void AsyncStart(RequestParams* params) { + bool handled = false; + + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) + { + // Build the request object for passing to the handler + CefRefPtr request(new CefRequestImpl()); + CefRequestImpl* requestimpl = static_cast(request.get()); + + requestimpl->SetURL(UTF8ToWide(params->url.spec())); + requestimpl->SetMethod(UTF8ToWide(params->method)); + + // TODO(cef): Parse the extra header values from params->headers and + // add to the header map. + CefRequest::HeaderMap headerMap; + headerMap.insert( + std::make_pair(L"Referrer", UTF8ToWide(params->referrer.spec()))); + + requestimpl->SetHeaderMap(headerMap); + + scoped_refptr upload = params->upload; + CefRefPtr postdata; + if(upload.get()) { + postdata = new CefPostDataImpl(); + static_cast(postdata.get())->Set(*upload.get()); + requestimpl->SetPostData(postdata); + } + + int loadFlags = params->load_flags; + + // Handler output will be returned in these variables + std::wstring redirectUrl; + CefRefPtr resourceStream; + std::wstring mimeType; + + CefHandler::RetVal rv = handler->HandleBeforeResourceLoad( + browser_, request, redirectUrl, resourceStream, mimeType, loadFlags); + if(rv == CefHandler::RV_HANDLED) { + // cancel the resource load + handled = true; + OnCompletedRequest(URLRequestStatus(URLRequestStatus::CANCELED, 0)); + } else if(!redirectUrl.empty()) { + // redirect to the specified URL + params->url = GURL(WideToUTF8(redirectUrl)); + OnReceivedRedirect(params->url); + } else if(resourceStream.get()) { + // load from the provided resource stream + handled = true; + + long offset = resourceStream->Seek(0, SEEK_END); + resourceStream->Seek(0, SEEK_SET); + + resource_stream_ = resourceStream; + + ResourceLoaderBridge::ResponseInfo info; + info.content_length = static_cast(offset); + if(!mimeType.empty()) + info.mime_type = WideToUTF8(mimeType); + OnReceivedResponse(info, false); + AsyncReadData(); + } + } + + if(!handled) + { + request_.reset(new URLRequest(params->url, this)); + request_->set_method(params->method); + request_->set_policy_url(params->policy_url); + request_->set_referrer(params->referrer.spec()); + request_->SetExtraRequestHeaders(params->headers); + request_->set_load_flags(params->load_flags); + request_->set_upload(params->upload.get()); + request_->set_context(request_context); + request_->Start(); + } + + delete params; + } + + void AsyncCancel() { + // This can be null in cases where the request is already done. + if (!resource_stream_.get() && !request_.get()) + return; + + request_->Cancel(); + Done(); + } + + void AsyncReadData() { + if(resource_stream_.get()) { + // Read from the handler-provided resource stream + int bytes_read = resource_stream_->Read(buf_, 1, sizeof(buf_)); + if(bytes_read > 0) { + OnReceivedData(bytes_read); + } else { + Done(); + } + return; + } + + // This can be null in cases where the request is already done. + if (!request_.get()) + return; + + if (request_->status().is_success()) { + int bytes_read; + if (request_->Read(buf_, sizeof(buf_), &bytes_read) && bytes_read) { + OnReceivedData(bytes_read); + } else if (!request_->status().is_io_pending()) { + Done(); + } // else wait for OnReadCompleted + } else { + Done(); + } + } + + // -------------------------------------------------------------------------- + // The following methods are event hooks (corresponding to URLRequest + // callbacks) that run on the IO thread. They are designed to be overridden + // by the SyncRequestProxy subclass. + + virtual void OnReceivedRedirect(const GURL& new_url) { + owner_loop_->PostTask(FROM_HERE, NewRunnableMethod( + this, &RequestProxy::NotifyReceivedRedirect, new_url)); + } + + virtual void OnReceivedResponse( + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { + owner_loop_->PostTask(FROM_HERE, NewRunnableMethod( + this, &RequestProxy::NotifyReceivedResponse, info, content_filtered)); + } + + virtual void OnReceivedData(int bytes_read) { + owner_loop_->PostTask(FROM_HERE, NewRunnableMethod( + this, &RequestProxy::NotifyReceivedData, bytes_read)); + } + + virtual void OnCompletedRequest(const URLRequestStatus& status) { + owner_loop_->PostTask(FROM_HERE, NewRunnableMethod( + this, &RequestProxy::NotifyCompletedRequest, status)); + } + + // -------------------------------------------------------------------------- + // URLRequest::Delegate implementation: + + virtual void OnReceivedRedirect(URLRequest* request, + const GURL& new_url) { + DCHECK(request->status().is_success()); + OnReceivedRedirect(new_url); + } + + virtual void OnResponseStarted(URLRequest* request) { + if (request->status().is_success()) { + ResourceLoaderBridge::ResponseInfo info; + info.request_time = request->request_time(); + info.response_time = request->response_time(); + info.headers = request->response_headers(); + request->GetMimeType(&info.mime_type); + request->GetCharset(&info.charset); + OnReceivedResponse(info, false); + AsyncReadData(); // start reading + } else { + Done(); + } + } + + virtual void OnReadCompleted(URLRequest* request, int bytes_read) { + if (request->status().is_success() && bytes_read > 0) { + OnReceivedData(bytes_read); + } else { + Done(); + } + } + + // -------------------------------------------------------------------------- + // Helpers and data: + + void Done() { + if(resource_stream_.get()) { + // Resource stream reads always complete successfully + OnCompletedRequest(URLRequestStatus(URLRequestStatus::SUCCESS, 0)); + resource_stream_ = NULL; + } else { + DCHECK(request_.get()); + OnCompletedRequest(request_->status()); + request_.reset(); // destroy on the io thread + } + } + + scoped_ptr request_; + CefRefPtr resource_stream_; + + // Size of our async IO data buffers + static const int kDataSize = 16*1024; + + // read buffer for async IO + char buf_[kDataSize]; + + CefRefPtr browser_; + + MessageLoop* owner_loop_; + + // This is our peer in WebKit (implemented as ResourceHandleInternal). We do + // not manage its lifetime, and we may only access it from the owner's + // message loop (owner_loop_). + ResourceLoaderBridge::Peer* peer_; +}; + +//----------------------------------------------------------------------------- + +class SyncRequestProxy : public RequestProxy { + public: + explicit SyncRequestProxy(CefRefPtr browser, + ResourceLoaderBridge::SyncLoadResponse* result) + : RequestProxy(browser), result_(result), event_(true, false) { + } + + void WaitForCompletion() { + if (!event_.Wait()) + NOTREACHED(); + } + + // -------------------------------------------------------------------------- + // Event hooks that run on the IO thread: + + virtual void OnReceivedRedirect(const GURL& new_url) { + result_->url = new_url; + } + + virtual void OnReceivedResponse( + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { + *static_cast(result_) = info; + } + + virtual void OnReceivedData(int bytes_read) { + result_->data.append(buf_, bytes_read); + AsyncReadData(); // read more (may recurse) + } + + virtual void OnCompletedRequest(const URLRequestStatus& status) { + result_->status = status; + event_.Signal(); + } + + private: + ResourceLoaderBridge::SyncLoadResponse* result_; + base::WaitableEvent event_; +}; + +//----------------------------------------------------------------------------- + +class ResourceLoaderBridgeImpl : public ResourceLoaderBridge { + public: + ResourceLoaderBridgeImpl(CefRefPtr browser, + const std::string& method, + const GURL& url, + const GURL& policy_url, + const GURL& referrer, + const std::string& headers, + int load_flags) + : browser_(browser), + params_(new RequestParams), + proxy_(NULL) { + params_->method = method; + params_->url = url; + params_->policy_url = policy_url; + params_->referrer = referrer; + params_->headers = headers; + params_->load_flags = load_flags; + } + + virtual ~ResourceLoaderBridgeImpl() { + if (proxy_) { + proxy_->DropPeer(); + // Let the proxy die on the IO thread + io_thread->message_loop()->ReleaseSoon(FROM_HERE, proxy_); + } + } + + // -------------------------------------------------------------------------- + // ResourceLoaderBridge implementation: + + virtual void AppendDataToUpload(const char* data, int data_len) { + DCHECK(params_.get()); + if (!params_->upload) + params_->upload = new net::UploadData(); + params_->upload->AppendBytes(data, data_len); + } + + virtual void AppendFileRangeToUpload(const std::wstring& file_path, + uint64 offset, uint64 length) { + DCHECK(params_.get()); + if (!params_->upload) + params_->upload = new net::UploadData(); + params_->upload->AppendFileRange(file_path, offset, length); + } + + virtual bool Start(Peer* peer) { + DCHECK(!proxy_); + + if (!EnsureIOThread()) + return false; + + proxy_ = new RequestProxy(browser_); + proxy_->AddRef(); + + proxy_->Start(peer, params_.release()); + + return true; // Any errors will be reported asynchronously. + } + + virtual void Cancel() { + DCHECK(proxy_); + proxy_->Cancel(); + } + + virtual void SetDefersLoading(bool value) { + // TODO(darin): implement me + } + + virtual void SyncLoad(SyncLoadResponse* response) { + DCHECK(!proxy_); + + if (!EnsureIOThread()) + return; + + // this may change as the result of a redirect + response->url = params_->url; + + proxy_ = new SyncRequestProxy(browser_, response); + proxy_->AddRef(); + + proxy_->Start(NULL, params_.release()); + + static_cast(proxy_)->WaitForCompletion(); + } + + private: + CefRefPtr browser_; + + // Ownership of params_ is transfered to the proxy when the proxy is created. + scoped_ptr params_; + + // The request proxy is allocated when we start the request, and then it + // sticks around until this ResourceLoaderBridge is destroyed. + RequestProxy* proxy_; +}; + +//----------------------------------------------------------------------------- + +class CookieSetter : public base::RefCountedThreadSafe { + public: + void Set(const GURL& url, const std::string& cookie) { + DCHECK(MessageLoop::current() == io_thread->message_loop()); + request_context->cookie_store()->SetCookie(url, cookie); + } +}; + +class CookieGetter : public base::RefCountedThreadSafe { + public: + CookieGetter() : event_(false, false) { + } + + void Get(const GURL& url) { + result_ = request_context->cookie_store()->GetCookies(url); + event_.Signal(); + } + + std::string GetResult() { + if (!event_.Wait()) + NOTREACHED(); + return result_; + } + + private: + base::WaitableEvent event_; + std::string result_; +}; + +} // anonymous namespace + +//----------------------------------------------------------------------------- + +namespace webkit_glue { + +// factory function +ResourceLoaderBridge* ResourceLoaderBridge::Create( + WebFrame* webframe, + const std::string& method, + const GURL& url, + const GURL& policy_url, + const GURL& referrer, + const std::string& headers, + int load_flags, + int origin_pid, + ResourceType::Type request_type, + bool mixed_contents) { + return new ResourceLoaderBridgeImpl( + (webframe->GetView()->GetDelegate() ? + static_cast( + webframe->GetView()->GetDelegate())->GetBrowser() : NULL), + method, url, policy_url, referrer, headers, load_flags); +} + +void SetCookie(const GURL& url, const GURL& policy_url, + const std::string& cookie) { + // Proxy to IO thread to synchronize w/ network loading. + + if (!EnsureIOThread()) { + NOTREACHED(); + return; + } + + scoped_refptr cookie_setter = new CookieSetter(); + io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + cookie_setter.get(), &CookieSetter::Set, url, cookie)); +} + +std::string GetCookies(const GURL& url, const GURL& policy_url) { + // Proxy to IO thread to synchronize w/ network loading + + if (!EnsureIOThread()) { + NOTREACHED(); + return std::string(); + } + + scoped_refptr getter = new CookieGetter(); + + io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + getter.get(), &CookieGetter::Get, url)); + + return getter->GetResult(); +} + +} // namespace webkit_glue + +//----------------------------------------------------------------------------- + +// static +void BrowserResourceLoaderBridge::Init(URLRequestContext* context) { + // Make sure to stop any existing IO thread since it may be using the + // current request context. + Shutdown(); + + if (context) { + request_context = context; + } else { + request_context = new BrowserRequestContext(); + } + request_context->AddRef(); +} + +// static +void BrowserResourceLoaderBridge::Shutdown() { + if (io_thread) { + delete io_thread; + io_thread = NULL; + + DCHECK(!request_context) << "should have been nulled by thread dtor"; + } +} diff --git a/libcef/browser_resource_loader_bridge.h b/libcef/browser_resource_loader_bridge.h new file mode 100644 index 000000000..71d90c217 --- /dev/null +++ b/libcef/browser_resource_loader_bridge.h @@ -0,0 +1,32 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 _BROWSER_RESOURCE_LOADER_BRIDGE_H +#define _BROWSER_RESOURCE_LOADER_BRIDGE_H + +#include "base/ref_counted.h" + +class URLRequestContext; + +class BrowserResourceLoaderBridge { + public: + // Call this function to initialize the simple resource loader bridge. If + // the given context is null, then a default BrowserRequestContext will be + // instantiated. Otherwise, a reference is taken to the given request + // context, which will be released when Shutdown is called. The caller + // should not hold another reference to the request context! It is safe to + // call this function multiple times. + // + // NOTE: If this function is not called, then a default request context will + // be initialized lazily. + // + static void Init(URLRequestContext* context); + + // Call this function to shutdown the simple resource loader bridge. + static void Shutdown(); +}; + +#endif // _BROWSER_RESOURCE_LOADER_BRIDGE_H + diff --git a/libcef/browser_webkit_glue.cc b/libcef/browser_webkit_glue.cc new file mode 100644 index 000000000..cc022a11d --- /dev/null +++ b/libcef/browser_webkit_glue.cc @@ -0,0 +1,153 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "browser_webkit_glue.h" + +#include "base/compiler_specific.h" + +#include "config.h" +#include "webkit_version.h" +MSVC_PUSH_WARNING_LEVEL(0); +#include "Markup.h" +#include "webkit/glue/webframe_impl.h" +MSVC_POP_WARNING(); + +#undef LOG +#include "base/path_service.h" +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "base/win_util.h" +#include "net/base/mime_util.h" +#include "webkit/glue/glue_util.h" +#include "webkit/glue/webframe.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/webkit_resources.h" + + +namespace webkit_glue { + +void PrefetchDns(const std::string& hostname) {} + +void PrecacheUrl(const char16* url, int url_length) {} + +void AppendToLog(const char* file, int line, const char* msg) { + logging::LogMessage(file, line).stream() << msg; +} + +bool GetMimeTypeFromExtension(const std::wstring &ext, std::string *mime_type) { + return net::GetMimeTypeFromExtension(ext, mime_type); +} + +bool GetMimeTypeFromFile(const std::wstring &file_path, + std::string *mime_type) { + return net::GetMimeTypeFromFile(file_path, mime_type); +} + +bool GetPreferredExtensionForMimeType(const std::string& mime_type, + std::wstring* ext) { + return net::GetPreferredExtensionForMimeType(mime_type, ext); +} + +std::string GetDataResource(int resource_id) { + if (resource_id == IDR_BROKENIMAGE) { + // Use webkit's broken image icon (16x16) + static unsigned char broken_image_data[] = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x10, 0x00, 0x10, 0x00, 0xD5, 0x00, + 0x00, 0x20, 0x68, 0xB0, 0x70, 0x98, 0xC0, 0x28, 0x78, 0xB8, 0x20, 0x70, + 0xB8, 0x88, 0xB8, 0xD8, 0x78, 0x98, 0xC8, 0x28, 0x80, 0xC0, 0xF8, 0xF8, + 0xF8, 0xF0, 0xF0, 0xF8, 0xE0, 0xE8, 0xF0, 0xD0, 0xE0, 0xF0, 0xB8, 0xD0, + 0xE8, 0xC0, 0xD8, 0xE8, 0x98, 0xC0, 0xE0, 0x68, 0x90, 0xC0, 0x70, 0x90, + 0xC0, 0x30, 0x80, 0xC0, 0x28, 0x88, 0xC0, 0x30, 0x78, 0xB8, 0x88, 0xB8, + 0xE0, 0x78, 0xA0, 0xC8, 0x20, 0x70, 0xB0, 0x90, 0xA8, 0xD0, 0x88, 0xA8, + 0xD0, 0x70, 0x98, 0xC8, 0x90, 0xB0, 0xD0, 0x80, 0xA0, 0xC8, 0x28, 0x88, + 0xC8, 0x20, 0x78, 0xB8, 0x40, 0x90, 0xC8, 0x50, 0x98, 0xC8, 0x28, 0x78, + 0xC0, 0x50, 0x90, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x06, + 0x8F, 0xC0, 0x8C, 0x70, 0x48, 0x2C, 0x66, 0x2C, 0x87, 0xA4, 0x72, 0xB9, + 0xB4, 0x20, 0x37, 0xD0, 0xA8, 0x14, 0x7A, 0xB0, 0x5C, 0x0E, 0x51, 0x83, + 0x76, 0x1B, 0x3D, 0x5C, 0xAE, 0x91, 0x88, 0x76, 0x32, 0x59, 0x34, 0x3A, + 0x86, 0xB0, 0x57, 0x73, 0xD8, 0x12, 0x12, 0x86, 0xCE, 0x21, 0xF1, 0xD1, + 0x1E, 0x34, 0xEC, 0xAD, 0x87, 0x20, 0x80, 0x1C, 0x10, 0x02, 0x76, 0x78, + 0x6D, 0x06, 0x1F, 0x02, 0x87, 0x0D, 0x0C, 0x20, 0x1C, 0x82, 0x14, 0x07, + 0x87, 0x87, 0x1C, 0x20, 0x04, 0x1C, 0x95, 0x87, 0x07, 0x14, 0x05, 0x07, + 0x95, 0x95, 0x03, 0x12, 0x12, 0x03, 0x9C, 0x1C, 0x07, 0x05, 0x18, 0x07, + 0x03, 0xA8, 0x03, 0x15, 0x0A, 0x0A, 0x15, 0xA9, 0x03, 0x07, 0x18, 0x01, + 0xA7, 0xA9, 0xAB, 0xAD, 0xAF, 0x07, 0x01, 0x0F, 0x07, 0x15, 0xBD, 0x15, + 0x00, 0xC0, 0x00, 0xBE, 0x15, 0x07, 0x0F, 0x0E, 0xBC, 0xC3, 0xC9, 0xBD, + 0x07, 0x0E, 0xC7, 0x4C, 0xCF, 0x49, 0xCD, 0xD2, 0xD3, 0xD4, 0xD2, 0x41, + 0x00, 0x3B + }; + return reinterpret_cast(broken_image_data); + } else if (resource_id == IDR_FEED_PREVIEW) { + // It is necessary to return a feed preview template that contains + // a {{URL}} substring where the feed URL should go; see the code + // that computes feed previews in feed_preview.cc:MakeFeedPreview. + // This fixes issue #932714. + return std::string("Feed preview for {{URL}}"); + } else { + return std::string(); + } +} + +GlueBitmap GetBitmapResource(int resource_id) { + return NULL; +} + +bool GetApplicationDirectory(std::wstring *path) { + return PathService::Get(base::DIR_EXE, path); +} + +GURL GetInspectorURL() { + return GURL("cef-resource://inspector/inspector.html"); +} + +std::string GetUIResourceProtocol() { + return "cef-resource"; +} + +bool GetExeDirectory(std::wstring *path) { + return PathService::Get(base::DIR_EXE, path); +} + +bool SpellCheckWord(const wchar_t* word, int word_len, + int* misspelling_start, int* misspelling_len) { + // Report all words being correctly spelled. + *misspelling_start = 0; + *misspelling_len = 0; + return true; +} + +bool IsPluginRunningInRendererProcess() { + return true; +} + +bool GetPluginFinderURL(std::string* plugin_finder_url) { + return false; +} + +bool IsDefaultPluginEnabled() { + return false; +} + +std::wstring GetWebKitLocale() { + return L"en-US"; +} + +std::string GetDocumentString(WebFrame* frame) { + WebFrameImpl* webFrameImpl = static_cast(frame); + WebCore::Frame* core_frame = webFrameImpl->frame(); + + return StringToStdString(WebCore::createMarkup(core_frame->document())); +} + +} // namespace webkit_glue diff --git a/libcef/browser_webkit_glue.h b/libcef/browser_webkit_glue.h new file mode 100644 index 000000000..5a2254f2c --- /dev/null +++ b/libcef/browser_webkit_glue.h @@ -0,0 +1,24 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 + +class WebFrame; +class WebView; + +namespace webkit_glue { + +// Return the HTML contents of a web frame as a string +std::string GetDocumentString(WebFrame* frame); + +#if defined(OS_WIN) +// Capture a bitmap of the web view. +void CaptureWebViewBitmap(HWND mainWnd, WebView* webview, HBITMAP& bitmap, + SIZE& size); + +// Save a bitmap image to file, providing optional alternative data in |lpBits| +BOOL SaveBitmapToFile(HBITMAP hBmp, HDC hDC, LPCTSTR file, LPBYTE lpBits); +#endif + +} // namespace webkit_glue diff --git a/libcef/browser_webkit_glue_win.cc b/libcef/browser_webkit_glue_win.cc new file mode 100644 index 000000000..6705434ee --- /dev/null +++ b/libcef/browser_webkit_glue_win.cc @@ -0,0 +1,291 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "browser_webkit_glue.h" + +#include +#include +#include + +#include "base/compiler_specific.h" + +#include "config.h" +#include "webkit_version.h" +MSVC_PUSH_WARNING_LEVEL(0); +#include "PlatformContextSkia.h" +MSVC_POP_WARNING(); + +#undef LOG +#include "base/gfx/gdi_util.h" +#include "base/logging.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/webview.h" +#include "webkit/glue/plugins/plugin_list.h" + + +namespace webkit_glue { + +std::wstring GetLocalizedString(int message_id) { + const ATLSTRINGRESOURCEIMAGE* image = + AtlGetStringResourceImage(_AtlBaseModule.GetModuleInstance(), + message_id); + // TODO(cef): Need to provide strings for common resources. + if (!image) { + NOTREACHED(); + return L"No string for this identifier!"; + } + return std::wstring(image->achString, image->nLength); +} + +HCURSOR LoadCursor(int cursor_id) { + return NULL; +} + +bool GetPlugins(bool refresh, std::vector* plugins) { + return NPAPI::PluginList::Singleton()->GetPlugins(refresh, plugins); +} + +bool EnsureFontLoaded(HFONT font) { + return true; +} + +bool DownloadUrl(const std::string& url, HWND caller_window) { + return false; +} + +ScreenInfo GetScreenInfo(gfx::ViewHandle window) { + return GetScreenInfoHelper(window); +} + +void CaptureWebViewBitmap(HWND mainWnd, WebView* webview, HBITMAP& bitmap, SIZE& size) +{ + gfx::Size webSize = webview->GetSize(); + size.cx = webSize.width(); + size.cy = webSize.height(); + + gfx::PlatformCanvasWin canvas(size.cx, size.cy, true); + canvas.drawARGB(255, 255, 255, 255, SkPorterDuff::kSrc_Mode); + PlatformContextSkia context(&canvas); + gfx::Rect rect(size.cx, size.cy); + webview->Layout(); + webview->Paint(&canvas, rect); + + HDC hRefDC = GetDC(mainWnd); + HDC hDC = CreateCompatibleDC(hRefDC); + bitmap = CreateCompatibleBitmap(hRefDC, size.cx, size.cy); + DCHECK(bitmap != NULL); + HBITMAP hOldBmp = (HBITMAP)SelectObject(hDC, bitmap); + + // Create a BMP v4 header that we can serialize. + BITMAPV4HEADER bitmap_header; + gfx::CreateBitmapV4Header(size.cx, size.cy, &bitmap_header); + const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true); + SkAutoLockPixels src_lock(src_bmp); + int retval = StretchDIBits(hDC, + 0, + 0, + size.cx, size.cy, + 0, 0, + size.cx, size.cy, + src_bmp.getPixels(), + reinterpret_cast(&bitmap_header), + DIB_RGB_COLORS, + SRCCOPY); + DCHECK(retval != GDI_ERROR); + + SelectObject(hDC, hOldBmp); + DeleteDC(hDC); + ReleaseDC(mainWnd, hRefDC); +} + + +static PBITMAPINFO BmpCreateInfo(HBITMAP hBmp) +{ + BITMAP bmp; + PBITMAPINFO pbmi; + WORD cClrBits; + + // Retrieve the bitmap color format, width, and height. + if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) { + NOTREACHED(); + return NULL; + } + + // Convert the color format to a count of bits. + cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); + if (cClrBits == 1) { + cClrBits = 1; + } else if (cClrBits <= 4) { + cClrBits = 4; + } else if (cClrBits <= 8) { + cClrBits = 8; + } else if (cClrBits <= 16) { + cClrBits = 16; + } else if (cClrBits <= 24) { + cClrBits = 24; + } else { + cClrBits = 32; + } + + // Allocate memory for the BITMAPINFO structure. (This structure + // contains a BITMAPINFOHEADER structure and an array of RGBQUAD + // data structures.) + if (cClrBits != 24) { + pbmi = (PBITMAPINFO) LocalAlloc(LPTR, + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits)); + } else { // There is no RGBQUAD array for the 24-bit-per-pixel format. + pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)); + } + + // Initialize the fields in the BITMAPINFO structure. + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = bmp.bmWidth; + pbmi->bmiHeader.biHeight = bmp.bmHeight; + pbmi->bmiHeader.biPlanes = bmp.bmPlanes; + pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; + if (cClrBits < 24) { + pbmi->bmiHeader.biClrUsed = (1<bmiHeader.biCompression = BI_RGB; + + // Compute the number of bytes in the array of color + // indices and store the result in biSizeImage. + // For Windows NT, the width must be DWORD aligned unless + // the bitmap is RLE compressed. This example shows this. + // For Windows 95/98/Me, the width must be WORD aligned unless the + // bitmap is RLE compressed. + pbmi->bmiHeader.biSizeImage = + ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 + * pbmi->bmiHeader.biHeight; + + // Set biClrImportant to 0, indicating that all of the + // device colors are important. + pbmi->bmiHeader.biClrImportant = 0; + return pbmi; +} + +static BOOL BmpSaveFile(LPCTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, + HDC hDC, LPBYTE lpBits = NULL) +{ + HANDLE hf = INVALID_HANDLE_VALUE; // file handle + BITMAPFILEHEADER hdr; // bitmap file-header + PBITMAPINFOHEADER pbih; // bitmap info-header + DWORD dwTotal; // total count of bytes + DWORD cb; // incremental count of bytes + BYTE *hp; // byte pointer + DWORD dwTmp; + BOOL ret = FALSE; + BOOL bitsAlloc = FALSE; + + pbih = (PBITMAPINFOHEADER) pbi; + + if(!lpBits) { + // The bits have not been provided, so retrieve from the bitmap file + lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); + if (!lpBits) { + // Memory could not be allocated + NOTREACHED(); + return FALSE; + } + + bitsAlloc = TRUE; + + // Retrieve the color table (RGBQUAD array) and the bits + // (array of palette indices) from the DIB. + if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, + DIB_RGB_COLORS)) { + NOTREACHED(); + goto end; + } + } + + // Create the bitmap file. + hf = CreateFile(pszFile, + GENERIC_READ | GENERIC_WRITE, + (DWORD) 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + (HANDLE) NULL); + if (hf == INVALID_HANDLE_VALUE) { + // Could not create the bitmap file + NOTREACHED(); + goto end; + } + + hdr.bfType = 0x4d42; // 0x42 = "B", 0x4d = "M" + + // Compute the size of the entire file. + hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + + pbih->biSize + pbih->biClrUsed + * sizeof(RGBQUAD) + pbih->biSizeImage); + hdr.bfReserved1 = 0; + hdr.bfReserved2 = 0; + + // Compute the offset to the array of color indices. + hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + + pbih->biSize + pbih->biClrUsed + * sizeof (RGBQUAD); + + // Copy the BITMAPFILEHEADER into the bitmap file. + if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), + (LPDWORD) &dwTmp, NULL)) { + // Could not write bitmap file header to file + NOTREACHED(); + goto end; + } + + // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. + if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) + + pbih->biClrUsed * sizeof (RGBQUAD), + (LPDWORD) &dwTmp, NULL)) { + // Could not write bitmap info header to file + NOTREACHED(); + goto end; + } + + // Copy the array of color indices into the .BMP file. + dwTotal = cb = pbih->biSizeImage; + hp = lpBits; + if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL)) { + // Could not write bitmap data to file + NOTREACHED(); + goto end; + } + + ret = TRUE; + +end: + // Close the bitmap file. + if(hf != INVALID_HANDLE_VALUE) { + CloseHandle(hf); + if(!ret) + DeleteFile(pszFile); + } + + if(bitsAlloc) + { + // Free memory. + GlobalFree((HGLOBAL)lpBits); + } + + return ret; +} + +BOOL SaveBitmapToFile(HBITMAP hBmp, HDC hDC, LPCTSTR file, LPBYTE lpBits) +{ + PBITMAPINFO pbmi = BmpCreateInfo(hBmp); + BOOL ret = FALSE; + if(pbmi) { + ret = BmpSaveFile(file, pbmi, hBmp, hDC, lpBits); + LocalFree(pbmi); + } + return ret; +} + +} // namespace webkit_glue diff --git a/libcef/browser_webview_delegate.cc b/libcef/browser_webview_delegate.cc new file mode 100644 index 000000000..de6ed0b5f --- /dev/null +++ b/libcef/browser_webview_delegate.cc @@ -0,0 +1,653 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains the implementation of BrowserWebViewDelegate, which serves +// as the WebViewDelegate for the BrowserWebHost. The host is expected to +// have initialized a MessageLoop before these methods are called. + +#include "precompiled_libcef.h" +#include "browser_webview_delegate.h" +#include "browser_impl.h" +#include "browser_navigation_controller.h" +#include "context.h" +#include "request_impl.h" + +#include "base/file_util.h" +#include "base/gfx/point.h" +#include "base/message_loop.h" +#include "base/string_util.h" +#include "base/trace_event.h" +#include "net/base/net_errors.h" +#include "webkit/glue/webdatasource.h" +#include "webkit/glue/webdropdata.h" +#include "webkit/glue/weberror.h" +#include "webkit/glue/webframe.h" +#include "webkit/glue/webpreferences.h" +#include "webkit/glue/weburlrequest.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/webview.h" +#include "webkit/glue/plugins/plugin_list.h" +#include "webkit/glue/window_open_disposition.h" + +#if defined(OS_WIN) +// TODO(port): make these files work everywhere. +#include "webkit/glue/plugins/webplugin_delegate_impl.h" +#include "browser_drag_delegate.h" +#include "browser_drop_delegate.h" +#endif + +namespace { + +int next_page_id_ = 1; + +} // namespace + +// WebViewDelegate ----------------------------------------------------------- + +WebView* BrowserWebViewDelegate::CreateWebView(WebView* webview, + bool user_gesture) { + CefRefPtr browser = + browser_->UIT_CreatePopupWindow(std::wstring()); + return browser.get() ? browser->UIT_GetWebView() : NULL; +} + +WebWidget* BrowserWebViewDelegate::CreatePopupWidget(WebView* webview, + bool focus_on_show) { + return browser_->UIT_CreatePopupWidget(webview); +} + +void BrowserWebViewDelegate::OpenURL(WebView* webview, const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition) { + DCHECK_NE(disposition, CURRENT_TAB); // No code for this + if (disposition == SUPPRESS_OPEN) + return; + + CefRefPtr browser = + browser_->UIT_CreatePopupWindow(UTF8ToWide(url.spec())); + + if(browser.get()) + browser->UIT_Show(browser->UIT_GetWebView(), disposition); +} + +void BrowserWebViewDelegate::DidStartLoading(WebView* webview) { + // clear the title so we can tell if it wasn't provided by the page + browser_->UIT_SetTitle(std::wstring()); + + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + // Notify the handler that loading has started + handler->HandleLoadStart(browser_); + } +} + +void BrowserWebViewDelegate::DidStopLoading(WebView* webview) { + if(browser_->UIT_GetTitle().empty()) { + // no title was provided by the page, so send a blank string to the client + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + // Notify the handler of a page title change + handler->HandleTitleChange(browser_, browser_->UIT_GetTitle()); + } + } + + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + // Notify the handler that loading has ended + handler->HandleLoadEnd(browser_); + } +} + +void BrowserWebViewDelegate::WindowObjectCleared(WebFrame* webframe) { + browser_->UIT_BindJSObjectsToWindow(webframe); +} + +WindowOpenDisposition BrowserWebViewDelegate::DispositionForNavigationAction( + WebView* webview, + WebFrame* frame, + const WebRequest* request, + WebNavigationType type, + WindowOpenDisposition disposition, + bool is_redirect) { + + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + // Gather browse request information + CefRefPtr req(CefRequest::CreateRequest()); + + req->SetURL(UTF8ToWide(request->GetURL().spec())); + req->SetMethod(UTF8ToWide(request->GetHttpMethod())); + + if(request->HasUploadData()) { + scoped_refptr data(new net::UploadData()); + request->GetUploadData(data.get()); + + CefRefPtr postdata(CefPostData::CreatePostData()); + static_cast(postdata.get())->Set(*data.get()); + req->SetPostData(postdata); + } + + WebRequest::HeaderMap map; + request->GetHttpHeaders(&map); + if(map.size() > 0) + static_cast(req.get())->SetHeaderMap(map); + + // Notify the handler of a browse request + CefHandler::RetVal rv = handler->HandleBeforeBrowse(browser_, req, + (CefHandler::NavType)type, is_redirect); + if(rv == CefHandler::RV_HANDLED) + return IGNORE_ACTION; + } + + if (is_custom_policy_delegate_) { + std::wstring frame_name = frame->GetName(); + printf("Policy delegate: attempt to load %s\n", + request->GetURL().spec().c_str()); + return IGNORE_ACTION; + } else { + return WebViewDelegate::DispositionForNavigationAction( + webview, frame, request, type, disposition, is_redirect); + } +} + +void BrowserWebViewDelegate::SetCustomPolicyDelegate(bool isCustom) { + is_custom_policy_delegate_ = isCustom; +} + +void BrowserWebViewDelegate::AssignIdentifierToRequest(WebView* webview, + uint32 identifier, + const WebRequest& request) { +} + +void BrowserWebViewDelegate::WillSendRequest(WebView* webview, + uint32 identifier, + WebRequest* request) { +} + +void BrowserWebViewDelegate::DidFinishLoading(WebView* webview, + uint32 identifier) { + +} + +void BrowserWebViewDelegate::DidFailLoadingWithError(WebView* webview, + uint32 identifier, + const WebError& error) { + +} + +void BrowserWebViewDelegate::DidStartProvisionalLoadForFrame( + WebView* webview, + WebFrame* frame, + NavigationGesture gesture) { + if (!top_loading_frame_) { + top_loading_frame_ = frame; + } + UpdateAddressBar(webview); +} + +void BrowserWebViewDelegate::DidReceiveServerRedirectForProvisionalLoadForFrame( + WebView* webview, + WebFrame* frame) { + UpdateAddressBar(webview); +} + +void BrowserWebViewDelegate::DidFailProvisionalLoadWithError( + WebView* webview, + const WebError& error, + WebFrame* frame) { + LocationChangeDone(frame->GetProvisionalDataSource()); + + // error codes are defined in net\base\net_error_list.h + + // Don't display an error page if this is simply a cancelled load. Aside + // from being dumb, WebCore doesn't expect it and it will cause a crash. + if (error.GetErrorCode() == net::ERR_ABORTED) + return; + + const WebRequest& failed_request = + frame->GetProvisionalDataSource()->GetRequest(); + BrowserExtraRequestData* extra_data = + static_cast(failed_request.GetExtraData()); + bool replace = extra_data && extra_data->pending_page_id != -1; + + scoped_ptr request(failed_request.Clone()); + request->SetURL(GURL("cef-error:")); + + std::string error_text; + + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + // give the handler an opportunity to generate a custom error message + std::wstring error_str; + CefHandler::RetVal rv = handler->HandleLoadError(browser_, + static_cast(error.GetErrorCode()), + UTF8ToWide(error.GetFailedURL().spec()), error_str); + if(rv == CefHandler::RV_HANDLED && !error_str.empty()) + error_text = WideToUTF8(error_str); + } else { + error_text = StringPrintf("Error loading url: %d", error.GetErrorCode()); + } + + frame->LoadAlternateHTMLString(request.get(), error_text, + error.GetFailedURL(), replace); +} + +void BrowserWebViewDelegate::DidCommitLoadForFrame(WebView* webview, + WebFrame* frame, + bool is_new_navigation) { + UpdateForCommittedLoad(frame, is_new_navigation); +} + +void BrowserWebViewDelegate::DidReceiveTitle(WebView* webview, + const std::wstring& title, + WebFrame* frame) { + browser_->UIT_SetTitle(title); + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + // Notify the handler of a page title change + handler->HandleTitleChange(browser_, title); + } +} + +void BrowserWebViewDelegate::DidFinishLoadForFrame(WebView* webview, + WebFrame* frame) { + UpdateAddressBar(webview); + LocationChangeDone(frame->GetDataSource()); +} + +void BrowserWebViewDelegate::DidFailLoadWithError(WebView* webview, + const WebError& error, + WebFrame* frame) { + LocationChangeDone(frame->GetDataSource()); +} + +void BrowserWebViewDelegate::DidFinishDocumentLoadForFrame(WebView* webview, + WebFrame* frame) { + +} + +void BrowserWebViewDelegate::DidHandleOnloadEventsForFrame(WebView* webview, + WebFrame* frame) { + +} + +void BrowserWebViewDelegate::DidChangeLocationWithinPageForFrame( + WebView* webview, WebFrame* frame, bool is_new_navigation) { + UpdateForCommittedLoad(frame, is_new_navigation); +} + +void BrowserWebViewDelegate::DidReceiveIconForFrame(WebView* webview, + WebFrame* frame) { + +} + +void BrowserWebViewDelegate::WillPerformClientRedirect(WebView* webview, + WebFrame* frame, + const std::wstring& dest_url, + unsigned int delay_seconds, + unsigned int fire_date) { + +} + +void BrowserWebViewDelegate::DidCancelClientRedirect(WebView* webview, + WebFrame* frame) { + +} + +void BrowserWebViewDelegate::AddMessageToConsole(WebView* webview, + const std::wstring& message, + unsigned int line_no, + const std::wstring& source_id) { + logging::LogMessage("CONSOLE", 0).stream() << "\"" + << message.c_str() + << ",\" source: " + << source_id.c_str() + << "(" + << line_no + << ")"; +} + +void BrowserWebViewDelegate::RunJavaScriptAlert(WebView* webview, + const std::wstring& message) { + CefHandler::RetVal rv = CefHandler::RV_CONTINUE; + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) + rv = handler->HandleJSAlert(browser_, message); + if(rv != CefHandler::RV_HANDLED) + ShowJavaScriptAlert(webview, message); +} + +bool BrowserWebViewDelegate::RunJavaScriptConfirm(WebView* webview, + const std::wstring& message) { + CefHandler::RetVal rv = CefHandler::RV_CONTINUE; + bool retval = false; + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) + rv = handler->HandleJSConfirm(browser_, message, retval); + if(rv != CefHandler::RV_HANDLED) + retval = ShowJavaScriptConfirm(webview, message); + return retval; +} + +bool BrowserWebViewDelegate::RunJavaScriptPrompt(WebView* webview, + const std::wstring& message, const std::wstring& default_value, + std::wstring* result) { + CefHandler::RetVal rv = CefHandler::RV_CONTINUE; + bool retval = false; + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + rv = handler->HandleJSPrompt(browser_, message, default_value, + retval, *result); + } + if(rv != CefHandler::RV_HANDLED) + retval = ShowJavaScriptPrompt(webview, message, default_value, result); + return retval; +} + +void BrowserWebViewDelegate::StartDragging(WebView* webview, + const WebDropData& drop_data) { +#if defined(OS_WIN) + // TODO(port): make this work on all platforms. + if (!drag_delegate_) { + drag_delegate_ = new BrowserDragDelegate( + browser_->UIT_GetWebViewWndHandle(), + browser_->UIT_GetWebView()); + } + // TODO(tc): Drag and drop is disabled in the test shell because we need + // to be able to convert from WebDragData to an IDataObject. + //const DWORD ok_effect = DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE; + //DWORD effect; + //HRESULT res = DoDragDrop(drop_data.data_object, drag_delegate_.get(), + // ok_effect, &effect); + //DCHECK(DRAGDROP_S_DROP == res || DRAGDROP_S_CANCEL == res); + webview->DragSourceSystemDragEnded(); +#endif +} + +// The output from these methods in non-interactive mode should match that +// expected by the layout tests. See EditingDelegate.m in DumpRenderTree. +bool BrowserWebViewDelegate::ShouldBeginEditing(WebView* webview, + std::wstring range) { + return browser_->UIT_AllowEditing(); +} + +bool BrowserWebViewDelegate::ShouldEndEditing(WebView* webview, + std::wstring range) { + return browser_->UIT_AllowEditing(); +} + +bool BrowserWebViewDelegate::ShouldInsertNode(WebView* webview, + std::wstring node, + std::wstring range, + std::wstring action) { + return browser_->UIT_AllowEditing(); +} + +bool BrowserWebViewDelegate::ShouldInsertText(WebView* webview, + std::wstring text, + std::wstring range, + std::wstring action) { + return browser_->UIT_AllowEditing(); +} + +bool BrowserWebViewDelegate::ShouldChangeSelectedRange(WebView* webview, + std::wstring fromRange, + std::wstring toRange, + std::wstring affinity, + bool stillSelecting) { + return browser_->UIT_AllowEditing(); +} + +bool BrowserWebViewDelegate::ShouldDeleteRange(WebView* webview, + std::wstring range) { + return browser_->UIT_AllowEditing(); +} + +bool BrowserWebViewDelegate::ShouldApplyStyle(WebView* webview, + std::wstring style, + std::wstring range) { + return browser_->UIT_AllowEditing(); +} + +bool BrowserWebViewDelegate::SmartInsertDeleteEnabled() { + return true; +} + +void BrowserWebViewDelegate::DidBeginEditing() { + +} + +void BrowserWebViewDelegate::DidChangeSelection() { + +} + +void BrowserWebViewDelegate::DidChangeContents() { + +} + +void BrowserWebViewDelegate::DidEndEditing() { + +} + +WebHistoryItem* BrowserWebViewDelegate::GetHistoryEntryAtOffset(int offset) { + BrowserNavigationEntry* entry = static_cast( + browser_->UIT_GetNavigationController()->GetEntryAtOffset(offset)); + if (!entry) + return NULL; + + return entry->GetHistoryItem(); +} + +int BrowserWebViewDelegate::GetHistoryBackListCount() { + int current_index = + browser_->UIT_GetNavigationController()->GetLastCommittedEntryIndex(); + return current_index; +} + +int BrowserWebViewDelegate::GetHistoryForwardListCount() { + int current_index = + browser_->UIT_GetNavigationController()->GetLastCommittedEntryIndex(); + return browser_->UIT_GetNavigationController()->GetEntryCount() + - current_index - 1; +} + +void BrowserWebViewDelegate::SetUserStyleSheetEnabled(bool is_enabled) { + WebPreferences* prefs = _Context->GetWebPreferences(); + prefs->user_style_sheet_enabled = is_enabled; + browser_->UIT_GetWebView()->SetPreferences(*prefs); +} + +void BrowserWebViewDelegate::SetUserStyleSheetLocation(const GURL& location) { + WebPreferences* prefs = _Context->GetWebPreferences(); + prefs->user_style_sheet_enabled = true; + prefs->user_style_sheet_location = location; + browser_->UIT_GetWebView()->SetPreferences(*prefs); +} + +// WebWidgetDelegate --------------------------------------------------------- + +gfx::ViewHandle BrowserWebViewDelegate::GetContainingWindow(WebWidget* webwidget) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + return host->window_handle(); + + return NULL; +} + +void BrowserWebViewDelegate::DidInvalidateRect(WebWidget* webwidget, + const gfx::Rect& rect) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + host->DidInvalidateRect(rect); +} + +void BrowserWebViewDelegate::DidScrollRect(WebWidget* webwidget, int dx, int dy, + const gfx::Rect& clip_rect) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + host->DidScrollRect(dx, dy, clip_rect); +} + +void BrowserWebViewDelegate::Focus(WebWidget* webwidget) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + browser_->UIT_SetFocus(host, true); +} + +void BrowserWebViewDelegate::Blur(WebWidget* webwidget) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) + browser_->UIT_SetFocus(host, false); +} + + +void BrowserWebViewDelegate::DidMove(WebWidget* webwidget, + const WebPluginGeometry& move) { +#if defined(OS_WIN) + // TODO(port): add me once plugins work. + WebPluginDelegateImpl::MoveWindow( + move.window, move.window_rect, move.clip_rect, move.cutout_rects, + move.visible); +#endif +} + +bool BrowserWebViewDelegate::IsHidden() { + return false; +} + +void BrowserWebViewDelegate::RegisterDragDrop() { +#if defined(OS_WIN) + // TODO(port): add me once drag and drop works. + DCHECK(!drop_delegate_); + drop_delegate_ = new BrowserDropDelegate(browser_->UIT_GetWebViewWndHandle(), + browser_->UIT_GetWebView()); +#endif +} + +// Private methods ----------------------------------------------------------- + +void BrowserWebViewDelegate::UpdateAddressBar(WebView* webView) { +/* + WebFrame* mainFrame = webView->UIT_GetMainFrame(); + WebDataSource* dataSource = mainFrame->GetDataSource(); + if (!dataSource) + dataSource = mainFrame->GetProvisionalDataSource(); + if (!dataSource) + return; + + GURL gUrl = dataSource->GetRequest().GetMainDocumentURL(); +*/ +} + +void BrowserWebViewDelegate::LocationChangeDone(WebDataSource* data_source) { + if (data_source->GetWebFrame() == top_loading_frame_) + top_loading_frame_ = NULL; +} + +WebWidgetHost* BrowserWebViewDelegate::GetHostForWidget(WebWidget* webwidget) { + if (webwidget == browser_->UIT_GetWebView()) + return browser_->UIT_GetWebViewHost(); + if (webwidget == browser_->UIT_GetPopup()) + return browser_->UIT_GetPopupHost(); + return NULL; +} + +void BrowserWebViewDelegate::UpdateForCommittedLoad(WebFrame* frame, + bool is_new_navigation) { + WebView* webview = browser_->UIT_GetWebView(); + + // Code duplicated from RenderView::DidCommitLoadForFrame. + const WebRequest& request = + webview->GetMainFrame()->GetDataSource()->GetRequest(); + BrowserExtraRequestData* extra_data = + static_cast(request.GetExtraData()); + + if (is_new_navigation) { + // New navigation. + UpdateSessionHistory(frame); + page_id_ = next_page_id_++; + } else if (extra_data && extra_data->pending_page_id != -1 && + !extra_data->request_committed) { + // This is a successful session history navigation! + UpdateSessionHistory(frame); + page_id_ = extra_data->pending_page_id; + } + + // Don't update session history multiple times. + if (extra_data) + extra_data->request_committed = true; + + UpdateURL(frame); +} + +void BrowserWebViewDelegate::UpdateURL(WebFrame* frame) { + WebDataSource* ds = frame->GetDataSource(); + DCHECK(ds); + + const WebRequest& request = ds->GetRequest(); + + // Type is unused. + scoped_ptr entry(new BrowserNavigationEntry); + + // Bug 654101: the referrer will be empty on https->http transitions. It + // would be nice if we could get the real referrer from somewhere. + entry->SetPageID(page_id_); + if (ds->HasUnreachableURL()) { + entry->SetURL(GURL(ds->GetUnreachableURL())); + } else { + entry->SetURL(GURL(request.GetURL())); + } + + std::wstring url = UTF8ToWide(entry->GetURL().spec().c_str()); + browser_->SetURL(url); + + if(frame->GetView()->GetMainFrame() == frame) { + // only send address changes that originate from the main frame + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + // Notify the handler of an address change + handler->HandleAddressChange(browser_, url); + } + } + + browser_->UIT_GetNavigationController()->DidNavigateToEntry(entry.release()); + + last_page_id_updated_ = std::max(last_page_id_updated_, page_id_); +} + +void BrowserWebViewDelegate::UpdateSessionHistory(WebFrame* frame) { + // If we have a valid page ID at this point, then it corresponds to the page + // we are navigating away from. Otherwise, this is the first navigation, so + // there is no past session history to record. + if (page_id_ == -1) + return; + + BrowserNavigationEntry* entry = static_cast( + browser_->UIT_GetNavigationController()->GetEntryWithPageID(page_id_)); + if (!entry) + return; + + GURL url; + std::wstring title; + std::string state; + if (!browser_->UIT_GetWebView()->GetMainFrame()-> + GetPreviousState(&url, &title, &state)) + return; + + entry->SetURL(url); + entry->SetTitle(title); + entry->SetContentState(state); +} + +std::wstring BrowserWebViewDelegate::GetFrameDescription(WebFrame* webframe) { + std::wstring name = webframe->GetName(); + + if (webframe == browser_->UIT_GetWebView()->GetMainFrame()) { + if (name.length()) + return L"main frame \"" + name + L"\""; + else + return L"main frame"; + } else { + if (name.length()) + return L"frame \"" + name + L"\""; + else + return L"frame (anonymous)"; + } +} diff --git a/libcef/browser_webview_delegate.h b/libcef/browser_webview_delegate.h new file mode 100644 index 000000000..c22145e17 --- /dev/null +++ b/libcef/browser_webview_delegate.h @@ -0,0 +1,280 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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. + +// BrowserWebViewDelegate class: +// This class implements the WebViewDelegate methods for the test shell. One +// instance is owned by each CefBrowser. + +#ifndef _BROWSER_WEBVIEW_DELEGATE_H +#define _BROWSER_WEBVIEW_DELEGATE_H + +#include "build/build_config.h" + +#include + +#if defined(OS_LINUX) +#include +#endif + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "webkit/glue/webview_delegate.h" +#include "webkit/glue/webwidget_delegate.h" +#if defined(OS_WIN) +#include "browser_drag_delegate.h" +#include "browser_drop_delegate.h" +#endif + +class CefBrowserImpl; +struct WebPreferences; +class GURL; +class WebDataSource; +class WebWidgetHost; + +class BrowserWebViewDelegate : public base::RefCounted, + public WebViewDelegate { + public: + BrowserWebViewDelegate(CefBrowserImpl* shell) + : is_custom_policy_delegate_(false), + browser_(shell), + top_loading_frame_(NULL), + page_id_(-1), + last_page_id_updated_(-1) +#if defined(OS_WIN) + , custom_cursor_(NULL) +#elif defined(OS_LINUX) + , cursor_type_(GDK_X_CURSOR) +#endif + { + } + virtual ~BrowserWebViewDelegate(); + + // WebViewDelegate + virtual WebView* CreateWebView(WebView* webview, bool user_gesture); + virtual WebWidget* CreatePopupWidget(WebView* webview, bool focus_on_show); + virtual WebPluginDelegate* CreatePluginDelegate( + WebView* webview, + const GURL& url, + const std::string& mime_type, + const std::string& clsid, + std::string* actual_mime_type); + virtual void OpenURL(WebView* webview, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition); + virtual void RunJavaScriptAlert(WebView* webview, + const std::wstring& message); + virtual bool RunJavaScriptConfirm(WebView* webview, + const std::wstring& message); + virtual bool RunJavaScriptPrompt(WebView* webview, + const std::wstring& message, + const std::wstring& default_value, + std::wstring* result); + virtual void AddMessageToConsole(WebView* webview, + const std::wstring& message, + unsigned int line_no, + const std::wstring& source_id); + virtual void StartDragging(WebView* webview, + const WebDropData& drop_data); + virtual void ShowContextMenu(WebView* webview, + ContextNode::Type type, + int x, + int y, + const GURL& link_url, + const GURL& image_url, + const GURL& page_url, + const GURL& frame_url, + const std::wstring& selection_text, + const std::wstring& misspelled_word, + int edit_flags, + const std::string& security_info); + virtual void DidStartProvisionalLoadForFrame( + WebView* webview, + WebFrame* frame, + NavigationGesture gesture); + virtual void DidReceiveServerRedirectForProvisionalLoadForFrame( + WebView* webview, WebFrame* frame); + virtual void DidFailProvisionalLoadWithError(WebView* webview, + const WebError& error, + WebFrame* frame); + virtual void DidCommitLoadForFrame(WebView* webview, WebFrame* frame, + bool is_new_navigation); + virtual void DidReceiveTitle(WebView* webview, + const std::wstring& title, + WebFrame* frame); + virtual void DidFinishDocumentLoadForFrame(WebView* webview, + WebFrame* frame); + virtual void DidHandleOnloadEventsForFrame(WebView* webview, + WebFrame* frame); + virtual void DidChangeLocationWithinPageForFrame(WebView* webview, + WebFrame* frame, + bool is_new_navigation); + virtual void DidReceiveIconForFrame(WebView* webview, WebFrame* frame); + + virtual void WillPerformClientRedirect(WebView* webview, + WebFrame* frame, + const std::wstring& dest_url, + unsigned int delay_seconds, + unsigned int fire_date); + virtual void DidCancelClientRedirect(WebView* webview, + WebFrame* frame); + + virtual void DidFinishLoadForFrame(WebView* webview, WebFrame* frame); + virtual void DidFailLoadWithError(WebView* webview, + const WebError& error, + WebFrame* forFrame); + + virtual void AssignIdentifierToRequest(WebView* webview, + uint32 identifier, + const WebRequest& request); + virtual void WillSendRequest(WebView* webview, + uint32 identifier, + WebRequest* request); + virtual void DidFinishLoading(WebView* webview, uint32 identifier); + virtual void DidFailLoadingWithError(WebView* webview, + uint32 identifier, + const WebError& error); + + virtual bool ShouldBeginEditing(WebView* webview, std::wstring range); + virtual bool ShouldEndEditing(WebView* webview, std::wstring range); + virtual bool ShouldInsertNode(WebView* webview, + std::wstring node, + std::wstring range, + std::wstring action); + virtual bool ShouldInsertText(WebView* webview, + std::wstring text, + std::wstring range, + std::wstring action); + virtual bool ShouldChangeSelectedRange(WebView* webview, + std::wstring fromRange, + std::wstring toRange, + std::wstring affinity, + bool stillSelecting); + virtual bool ShouldDeleteRange(WebView* webview, std::wstring range); + virtual bool ShouldApplyStyle(WebView* webview, + std::wstring style, + std::wstring range); + virtual bool SmartInsertDeleteEnabled(); + virtual void DidBeginEditing(); + virtual void DidChangeSelection(); + virtual void DidChangeContents(); + virtual void DidEndEditing(); + + virtual void DidStartLoading(WebView* webview); + virtual void DidStopLoading(WebView* webview); + + virtual void WindowObjectCleared(WebFrame* webframe); + virtual WindowOpenDisposition DispositionForNavigationAction( + WebView* webview, + WebFrame* frame, + const WebRequest* request, + WebNavigationType type, + WindowOpenDisposition disposition, + bool is_redirect); + void SetCustomPolicyDelegate(bool isCustom); + virtual WebHistoryItem* GetHistoryEntryAtOffset(int offset); + virtual int GetHistoryBackListCount(); + virtual int GetHistoryForwardListCount(); + + // WebWidgetDelegate + virtual gfx::ViewHandle GetContainingWindow(WebWidget* webwidget); + virtual void DidInvalidateRect(WebWidget* webwidget, const gfx::Rect& rect); + virtual void DidScrollRect(WebWidget* webwidget, int dx, int dy, + const gfx::Rect& clip_rect); + virtual void Show(WebWidget* webview, WindowOpenDisposition disposition); + virtual void CloseWidgetSoon(WebWidget* webwidget); + virtual void Focus(WebWidget* webwidget); + virtual void Blur(WebWidget* webwidget); + virtual void SetCursor(WebWidget* webwidget, + const WebCursor& cursor); + virtual void GetWindowRect(WebWidget* webwidget, gfx::Rect* rect); + virtual void SetWindowRect(WebWidget* webwidget, const gfx::Rect& rect); + virtual void GetRootWindowRect(WebWidget *,gfx::Rect *); + virtual void GetRootWindowResizerRect(WebWidget* webwidget, gfx::Rect* rect); + virtual void DidMove(WebWidget* webwidget, const WebPluginGeometry& move); + virtual void RunModal(WebWidget* webwidget); + virtual bool IsHidden(); + virtual void AddRef() { + base::RefCounted::AddRef(); + } + virtual void Release() { + base::RefCounted::Release(); + } + + // Additional accessors + WebFrame* top_loading_frame() { return top_loading_frame_; } +#if defined(OS_WIN) + IDropTarget* drop_delegate() { return drop_delegate_.get(); } + IDropSource* drag_delegate() { return drag_delegate_.get(); } +#endif + + // Methods for modifying WebPreferences + void SetUserStyleSheetEnabled(bool is_enabled); + void SetUserStyleSheetLocation(const GURL& location); + + // Sets the webview as a drop target. + void RegisterDragDrop(); + + CefBrowserImpl* GetBrowser() { return browser_; } + + protected: + // Called when the URL of the page changes. + void UpdateAddressBar(WebView* webView); + + // Default handling of JavaScript messages. + void ShowJavaScriptAlert(WebView* webview, const std::wstring& message); + bool ShowJavaScriptConfirm(WebView* webview, const std::wstring& message); + bool ShowJavaScriptPrompt(WebView* webview, const std::wstring& message, + const std::wstring& default_value, std::wstring* result); + + // In the Mac code, this is called to trigger the end of a test after the + // page has finished loading. From here, we can generate the dump for the + // test. + void LocationChangeDone(WebDataSource* data_source); + + WebWidgetHost* GetHostForWidget(WebWidget* webwidget); + + void UpdateForCommittedLoad(WebFrame* webframe, bool is_new_navigation); + void UpdateURL(WebFrame* frame); + void UpdateSessionHistory(WebFrame* frame); + + // Get a string suitable for dumping a frame to the console. + std::wstring GetFrameDescription(WebFrame* webframe); + + private: + // Causes navigation actions just printout the intended navigation instead + // of taking you to the page. This is used for cases like mailto, where you + // don't actually want to open the mail program. + bool is_custom_policy_delegate_; + + // Non-owning pointer. The delegate is owned by the host. + CefBrowserImpl* browser_; + + // This is non-NULL IFF a load is in progress. + WebFrame* top_loading_frame_; + + // For tracking session history. See RenderView. + int page_id_; + int last_page_id_updated_; + +#if defined(OS_WIN) + HCURSOR custom_cursor_; + + // Classes needed by drag and drop. + scoped_refptr drag_delegate_; + scoped_refptr drop_delegate_; +#endif + +#if defined(OS_LINUX) + // The type of cursor the window is currently using. + // Used for judging whether a new SetCursor call is actually changing the + // cursor. + GdkCursorType cursor_type_; +#endif + + DISALLOW_EVIL_CONSTRUCTORS(BrowserWebViewDelegate); +}; + +#endif // _BROWSER_WEBVIEW_DELEGATE_H diff --git a/libcef/browser_webview_delegate_win.cc b/libcef/browser_webview_delegate_win.cc new file mode 100644 index 000000000..b1c09d245 --- /dev/null +++ b/libcef/browser_webview_delegate_win.cc @@ -0,0 +1,354 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains the implementation of BrowserWebViewDelegate, which serves +// as the WebViewDelegate for the BrowserWebHost. The host is expected to +// have initialized a MessageLoop before these methods are called. + +#include "precompiled_libcef.h" +#include "browser_webview_delegate.h" +#include "browser_drag_delegate.h" +#include "browser_drop_delegate.h" +#include "browser_navigation_controller.h" +#include "browser_impl.h" +#include "context.h" + +#include +#include +#include + +#include "base/gfx/point.h" +#include "base/message_loop.h" +#include "base/string_util.h" +#include "base/trace_event.h" +#include "net/base/net_errors.h" +#include "webkit/glue/webdatasource.h" +#include "webkit/glue/webdropdata.h" +#include "webkit/glue/weberror.h" +#include "webkit/glue/webframe.h" +#include "webkit/glue/webpreferences.h" +#include "webkit/glue/weburlrequest.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/webview.h" +#include "webkit/glue/plugins/plugin_list.h" +#include "webkit/glue/plugins/webplugin_delegate_impl.h" +#include "webkit/glue/window_open_disposition.h" + +// WebViewDelegate ----------------------------------------------------------- + +BrowserWebViewDelegate::~BrowserWebViewDelegate() { + if (custom_cursor_) + DestroyIcon(custom_cursor_); + RevokeDragDrop(browser_->UIT_GetWebViewWndHandle()); +} + +WebPluginDelegate* BrowserWebViewDelegate::CreatePluginDelegate( + WebView* webview, + const GURL& url, + const std::string& mime_type, + const std::string& clsid, + std::string* actual_mime_type) { + HWND hwnd = GetContainingWindow(webview); + if (!hwnd) + return NULL; + + bool allow_wildcard = true; + WebPluginInfo info; + if (!NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, clsid, + allow_wildcard, &info, + actual_mime_type)) + return NULL; + + if (actual_mime_type && !actual_mime_type->empty()) + return WebPluginDelegateImpl::Create(info.file, *actual_mime_type, hwnd); + else + return WebPluginDelegateImpl::Create(info.file, mime_type, hwnd); +} + +void BrowserWebViewDelegate::Show(WebWidget* webwidget, WindowOpenDisposition) { + if (webwidget == browser_->UIT_GetWebView()) { + ShowWindow(browser_->UIT_GetMainWndHandle(), SW_SHOW); + UpdateWindow(browser_->UIT_GetMainWndHandle()); + } else if (webwidget == browser_->UIT_GetPopup()) { + ShowWindow(browser_->UIT_GetPopupWndHandle(), SW_SHOW); + UpdateWindow(browser_->UIT_GetPopupWndHandle()); + } +} + +void BrowserWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) { + if (webwidget == browser_->UIT_GetWebView()) { + PostMessage(browser_->UIT_GetMainWndHandle(), WM_CLOSE, 0, 0); + } else if (webwidget == browser_->UIT_GetPopup()) { + browser_->UIT_ClosePopupWidget(); + } +} + +void BrowserWebViewDelegate::SetCursor(WebWidget* webwidget, + const WebCursor& cursor) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) { + if (custom_cursor_) { + DestroyIcon(custom_cursor_); + custom_cursor_ = NULL; + } + if (cursor.IsCustom()) { + custom_cursor_ = cursor.GetCustomCursor(); + host->SetCursor(custom_cursor_); + } else { + HINSTANCE mod_handle = GetModuleHandle(NULL); + host->SetCursor(cursor.GetCursor(mod_handle)); + } + } +} + +void BrowserWebViewDelegate::GetWindowRect(WebWidget* webwidget, + gfx::Rect* out_rect) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) { + RECT rect; + ::GetWindowRect(host->window_handle(), &rect); + *out_rect = gfx::Rect(rect); + } +} + +void BrowserWebViewDelegate::SetWindowRect(WebWidget* webwidget, + const gfx::Rect& rect) { + if (webwidget == browser_->UIT_GetWebView()) { + // ignored + } else if (webwidget == browser_->UIT_GetPopup()) { + MoveWindow(browser_->UIT_GetPopupWndHandle(), + rect.x(), rect.y(), rect.width(), rect.height(), FALSE); + } +} + +void BrowserWebViewDelegate::GetRootWindowRect(WebWidget* webwidget, + gfx::Rect* out_rect) { + if (WebWidgetHost* host = GetHostForWidget(webwidget)) { + RECT rect; + HWND root_window = ::GetAncestor(host->window_handle(), GA_ROOT); + ::GetWindowRect(root_window, &rect); + *out_rect = gfx::Rect(rect); + } +} + +void BrowserWebViewDelegate::GetRootWindowResizerRect(WebWidget* webwidget, + gfx::Rect* out_rect) { + // Not necessary on Windows. + *out_rect = gfx::Rect(); +} + +void BrowserWebViewDelegate::RunModal(WebWidget* webwidget) { + Show(webwidget, NEW_WINDOW); + + CefContext::BrowserList *list; + CefContext::BrowserList::const_iterator i; + + _Context->Lock(); + list = _Context->GetBrowserList(); + i = list->begin(); + for (; i != list->end(); ++i) { + if (i->get()->IsPopup()) + EnableWindow(i->get()->UIT_GetMainWndHandle(), FALSE); + } + _Context->Unlock(); + + browser_->UIT_SetIsModal(true); + MessageLoop::current()->Run(); + + _Context->Lock(); + list = _Context->GetBrowserList(); + i = list->begin(); + for (; i != list->end(); ++i) + EnableWindow(i->get()->UIT_GetMainWndHandle(), TRUE); + _Context->Unlock(); +} + +static void AddMenuItem(CefRefPtr browser, HMENU menu, int index, + CefHandler::MenuId id, const wchar_t* label, + bool enabled, std::list& label_list) +{ + std::wstring actual_label = label; + CefRefPtr handler = browser->GetHandler(); + if(handler.get()) { + // Let the handler change the label if desired + handler->HandleGetMenuLabel(browser, id, actual_label); + } + + // store the label in a list to simplify memory management + label_list.push_back(actual_label); + + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; + mii.fType = MFT_STRING; + if(!enabled) { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_GRAYED; + } + mii.wID = id; + mii.dwTypeData = const_cast(label_list.back().c_str()); + + InsertMenuItem(menu, index, TRUE, &mii); +} + +static void AddMenuSeparator(HMENU menu, int index) +{ + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE; + mii.fType = MFT_SEPARATOR; + + InsertMenuItem(menu, index, TRUE, &mii); +} + +void BrowserWebViewDelegate::ShowContextMenu(WebView* webview, + ContextNode::Type type, + int x, + int y, + const GURL& link_url, + const GURL& image_url, + const GURL& page_url, + const GURL& frame_url, + const std::wstring& selection_text, + const std::wstring& misspelled_word, + int edit_flags, + const std::string& security_info) { + + POINT screen_pt = { x, y }; + MapWindowPoints(browser_->UIT_GetMainWndHandle(), HWND_DESKTOP, + &screen_pt, 1); + + HMENU menu = NULL; + std::list label_list; + + // Enable recursive tasks on the message loop so we can get updates while + // the context menu is being displayed. + bool old_state = MessageLoop::current()->NestableTasksAllowed(); + MessageLoop::current()->SetNestableTasksAllowed(true); + + if(browser_->UIT_CanGoBack()) + edit_flags |= CefHandler::CAN_GO_BACK; + if(browser_->UIT_CanGoForward()) + edit_flags |= CefHandler::CAN_GO_FORWARD; + + CefRefPtr handler = browser_->GetHandler(); + if(handler.get()) { + // Gather menu information + CefHandler::MenuInfo menuInfo; + menuInfo.menuType = static_cast(type); + menuInfo.x = screen_pt.x; + menuInfo.y = screen_pt.y; + menuInfo.linkUrl = UTF8ToWide(link_url.spec().c_str()).c_str(); + menuInfo.imageUrl = UTF8ToWide(image_url.spec().c_str()).c_str(); + menuInfo.pageUrl = UTF8ToWide(page_url.spec().c_str()).c_str(); + menuInfo.frameUrl = UTF8ToWide(frame_url.spec().c_str()).c_str(); + menuInfo.selectionText = selection_text; + menuInfo.misspelledWord = misspelled_word; + menuInfo.editFlags = edit_flags; + menuInfo.securityInfo = security_info; + + // Notify the handler that a context menu is requested + CefHandler::RetVal rv = handler->HandleBeforeMenu(browser_, menuInfo); + if(rv == CefHandler::RV_HANDLED) + goto end; + } + + // Build the correct default context menu + switch(type) { + case ContextNode::EDITABLE: + menu = CreatePopupMenu(); + AddMenuItem(browser_, menu, -1, CefHandler::ID_UNDO, L"Undo", + !!(edit_flags & ContextNode::CAN_UNDO), label_list); + AddMenuItem(browser_, menu, -1, CefHandler::ID_REDO, L"Redo", + !!(edit_flags & ContextNode::CAN_REDO), label_list); + AddMenuSeparator(menu, -1); + AddMenuItem(browser_, menu, -1, CefHandler::ID_CUT, L"Cut", + !!(edit_flags & ContextNode::CAN_CUT), label_list); + AddMenuItem(browser_, menu, -1, CefHandler::ID_COPY, L"Copy", + !!(edit_flags & ContextNode::CAN_COPY), label_list); + AddMenuItem(browser_, menu, -1, CefHandler::ID_PASTE, L"Paste", + !!(edit_flags & ContextNode::CAN_PASTE), label_list); + AddMenuItem(browser_, menu, -1, CefHandler::ID_DELETE, L"Delete", + !!(edit_flags & ContextNode::CAN_DELETE), label_list); + AddMenuSeparator(menu, -1); + AddMenuItem(browser_, menu, -1, CefHandler::ID_SELECTALL, L"Select All", + !!(edit_flags & ContextNode::CAN_SELECT_ALL), label_list); + break; + case ContextNode::SELECTION: + menu = CreatePopupMenu(); + AddMenuItem(browser_, menu, -1, CefHandler::ID_COPY, L"Copy", + !!(edit_flags & ContextNode::CAN_COPY), label_list); + break; + case ContextNode::PAGE: + case ContextNode::FRAME: + menu = CreatePopupMenu(); + AddMenuItem(browser_, menu, -1, CefHandler::ID_NAV_BACK, L"Back", + browser_->UIT_CanGoBack(), label_list); + AddMenuItem(browser_, menu, -1, CefHandler::ID_NAV_FORWARD, L"Forward", + browser_->UIT_CanGoForward(), label_list); + AddMenuSeparator(menu, -1); + AddMenuItem(browser_, menu, -1, CefHandler::ID_PRINT, L"Print", + true, label_list); + AddMenuItem(browser_, menu, -1, CefHandler::ID_VIEWSOURCE, L"View Source", + true, label_list); + break; + } + + if(menu) { + // show the context menu + int selected_id = TrackPopupMenu(menu, + TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_RECURSE, + screen_pt.x, screen_pt.y, 0, browser_->UIT_GetMainWndHandle(), NULL); + + if(selected_id != 0) { + // An action was chosen + CefHandler::MenuId menuId = static_cast(selected_id); + bool handled = false; + if(handler.get()) { + // Ask the handler if it wants to handle the action + CefHandler::RetVal rv = handler->HandleMenuAction(browser_, menuId); + handled = (rv == CefHandler::RV_HANDLED); + } + + if(!handled) { + // Execute the action + browser_->UIT_HandleAction(menuId, CefBrowser::TF_FOCUSED); + } + } + } + + DestroyMenu(menu); + +end: + MessageLoop::current()->SetNestableTasksAllowed(old_state); +} + + +// Private methods ----------------------------------------------------------- + +void BrowserWebViewDelegate::ShowJavaScriptAlert(WebView* webview, + const std::wstring& message) +{ + // TODO(cef): Think about what we should be showing as the prompt caption + MessageBox(browser_->UIT_GetMainWndHandle(), message.c_str(), + browser_->UIT_GetTitle().c_str(), MB_OK | MB_ICONWARNING); +} + +bool BrowserWebViewDelegate::ShowJavaScriptConfirm(WebView* webview, + const std::wstring& message) +{ + // TODO(cef): Think about what we should be showing as the prompt caption + int rv = MessageBox(browser_->UIT_GetMainWndHandle(), message.c_str(), + browser_->UIT_GetTitle().c_str(), + MB_YESNO | MB_ICONQUESTION); + return (rv == IDYES); +} + +bool BrowserWebViewDelegate::ShowJavaScriptPrompt(WebView* webview, + const std::wstring& message, + const std::wstring& default_value, + std::wstring* result) +{ + // TODO(cef): Implement a default prompt dialog + return false; +} diff --git a/libcef/context.cc b/libcef/context.cc new file mode 100644 index 000000000..2b87fcbc5 --- /dev/null +++ b/libcef/context.cc @@ -0,0 +1,393 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "context.h" +#include "browser_impl.h" +#include "browser_resource_loader_bridge.h" +#include "browser_request_context.h" + +#include "base/at_exit.h" +#include "base/icu_util.h" +#include "base/path_service.h" +#include "base/rand_util.h" +#include "base/resource_util.h" +#include "base/stats_table.h" +#include "base/string_util.h" +#include "net/base/net_module.h" + +#include + + +// Global CefContext pointer +CefRefPtr _Context; + +static const char* kStatsFilePrefix = "libcef_"; +static int kStatsFileThreads = 20; +static int kStatsFileCounters = 200; + +bool CefInitialize() +{ + // Return true if the context is already initialized + if(_Context.get()) + return true; + + // Create the new global context object + _Context = new CefContext(); + // Initialize the glboal context + return _Context->Initialize(); +} + +void CefShutdown() +{ + // Verify that the context is already initialized + if(!_Context.get()) + return; + + // Shut down the global context + _Context->Shutdown(); + // Delete the global context object + _Context = NULL; +} + + +StringPiece GetRawDataResource(HMODULE module, int resource_id) { + void* data_ptr; + size_t data_size; + return base::GetDataResourceFromModule(module, resource_id, &data_ptr, + &data_size) ? + StringPiece(static_cast(data_ptr), data_size) : StringPiece(); +} + +// This is called indirectly by the network layer to access resources. +StringPiece NetResourceProvider(int key) { + return GetRawDataResource(::GetModuleHandle(NULL), key); +} + +DWORD WINAPI ThreadHandlerUI(LPVOID lpParam) +{ + CefContext *pContext = static_cast(lpParam); + + HRESULT res; + + // Initialize common controls + res = CoInitialize(NULL); + DCHECK(SUCCEEDED(res)); + INITCOMMONCONTROLSEX InitCtrlEx; + InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX); + InitCtrlEx.dwICC = ICC_STANDARD_CLASSES; + InitCommonControlsEx(&InitCtrlEx); + + // Start COM stuff + res = OleInitialize(NULL); + DCHECK(SUCCEEDED(res)); + + // Instantiate the AtExitManager to avoid asserts and possible memory leaks. + base::AtExitManager at_exit_manager; + + // Instantiate the message loop for this thread. + MessageLoopForUI main_message_loop; + pContext->SetMessageLoopForUI(&main_message_loop); + + // Initializing with a default context, which means no on-disk cookie DB, + // and no support for directory listings. + // TODO(cef): Either disable caching or send the cache files to a reasonable + // temporary directory + std::wstring cache_path; + PathService::Get(base::DIR_EXE, &cache_path); + BrowserResourceLoaderBridge::Init( + new BrowserRequestContext(cache_path, net::HttpCache::NORMAL)); + + // Load ICU data tables. + bool ret = icu_util::Initialize(); + if(!ret) { + MessageBox(NULL, L"Failed to load the required icudt38 library", + L"CEF Initialization Error", MB_ICONERROR | MB_OK); + return 1; + } + + // Config the network module so it has access to a limited set of resources. + net::NetModule::SetResourceProvider(NetResourceProvider); + + // Load and initialize the stats table. Attempt to construct a somewhat + // unique name to isolate separate instances from each other. + StatsTable *table = new StatsTable( + kStatsFilePrefix + Uint64ToString(base::RandUint64()), + kStatsFileThreads, + kStatsFileCounters); + StatsTable::set_current(table); + + // Notify the context that initialization is complete so that the + // Initialize() function can return. + pContext->NotifyEvent(); + + // Execute the message loop that will run until a quit task is received. + MessageLoop::current()->Run(); + + // Flush any remaining messages. This ensures that any accumulated + // Task objects get destroyed before we exit, which avoids noise in + // purify leak-test results. + MessageLoop::current()->RunAllPending(); + + BrowserResourceLoaderBridge::Shutdown(); + + // Tear down shared StatsTable; prevents unit_tests from leaking it. + StatsTable::set_current(NULL); + delete table; + + // Uninitialize COM stuff + OleUninitialize(); + + // Uninitialize common controls + CoUninitialize(); + + return 0; +} + +CefContext::CefContext() +{ + hthreadui_ = NULL; + idthreadui_ = 0; + heventui_ = NULL; + messageloopui_ = NULL; + in_transition_ = false; + webprefs_ = NULL; + hinstance_ = ::GetModuleHandle(NULL); +} + +CefContext::~CefContext() +{ + // Just in case CefShutdown() isn't called + Shutdown(); +} + +bool CefContext::Initialize() +{ + bool initialized = false, intransition = false; + + Lock(); + + // We only need to initialize if the UI thread is not currently running + if(!hthreadui_) { + // Only start the initialization if we're not currently in a transitional + // state + intransition = in_transition_; + if(!intransition) { + // We are now in a transitional state + in_transition_ = true; + + // Register the window class + WNDCLASSEX wcex = { + /* cbSize = */ sizeof(WNDCLASSEX), + /* style = */ CS_HREDRAW | CS_VREDRAW, + /* lpfnWndProc = */ CefBrowserImpl::WndProc, + /* cbClsExtra = */ 0, + /* cbWndExtra = */ 0, + /* hInstance = */ hinstance_, + /* hIcon = */ NULL, + /* hCursor = */ LoadCursor(NULL, IDC_ARROW), + /* hbrBackground = */ 0, + /* lpszMenuName = */ NULL, + /* lpszClassName = */ CefBrowserImpl::GetWndClass(), + /* hIconSm = */ NULL, + }; + RegisterClassEx(&wcex); + + // Initialize web preferences + webprefs_ = new WebPreferences; + *webprefs_ = WebPreferences(); + webprefs_->standard_font_family = L"Times"; + webprefs_->fixed_font_family = L"Courier"; + webprefs_->serif_font_family = L"Times"; + webprefs_->sans_serif_font_family = L"Helvetica"; + // These two fonts are picked from the intersection of + // Win XP font list and Vista font list : + // http://www.microsoft.com/typography/fonts/winxp.htm + // http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx + // Some of them are installed only with CJK and complex script + // support enabled on Windows XP and are out of consideration here. + // (although we enabled both on our buildbots.) + // They (especially Impact for fantasy) are not typical cursive + // and fantasy fonts, but it should not matter for layout tests + // as long as they're available. +#if defined(OS_MACOSX) + webprefs_->cursive_font_family = L"Apple Chancery"; + webprefs_->fantasy_font_family = L"Papyrus"; +#else + webprefs_->cursive_font_family = L"Comic Sans MS"; + webprefs_->fantasy_font_family = L"Impact"; +#endif + webprefs_->default_encoding = L"ISO-8859-1"; + webprefs_->default_font_size = 16; + webprefs_->default_fixed_font_size = 13; + webprefs_->minimum_font_size = 1; + webprefs_->minimum_logical_font_size = 9; + webprefs_->javascript_can_open_windows_automatically = true; + webprefs_->dom_paste_enabled = true; + webprefs_->developer_extras_enabled = true; + webprefs_->shrinks_standalone_images_to_fit = false; + webprefs_->uses_universal_detector = false; + webprefs_->text_areas_are_resizable = false; + webprefs_->java_enabled = true; + webprefs_->allow_scripts_to_close_windows = false; + + // Event that will be used to signal thread setup completion. Start + // in non-signaled mode so that the event will block. + heventui_ = CreateEvent(NULL, TRUE, FALSE, NULL); + DCHECK(heventui_ != NULL); + + // Thread that hosts the UI loop + hthreadui_ = CreateThread( + NULL, 0, ThreadHandlerUI, this, 0, &idthreadui_); + DCHECK(hthreadui_ != NULL); + + initialized = true; + } + } + + Unlock(); + + if(initialized) { + // Wait for initial UI thread setup to complete + WaitForSingleObject(heventui_, INFINITE); + + Lock(); + + // We have exited the transitional state + in_transition_ = false; + + Unlock(); + } + + return intransition ? false : true; +} + +void CefContext::Shutdown() +{ + bool shutdown = false, intransition = false; + + Lock(); + + // We only need to shut down if the UI thread is currently running + if(hthreadui_) { + // Only start the shutdown if we're not currently in a transitional state + intransition = in_transition_; + if(!intransition) { + DCHECK(messageloopui_ != NULL); + + // We are now in a transitional state + in_transition_ = true; + + if(browserlist_.size() > 0) + browserlist_.clear(); + + if(webprefs_) { + delete webprefs_; + webprefs_ = NULL; + } + + // Post the quit message to the UI message loop + messageloopui_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + + shutdown = true; + } + } + + Unlock(); + + if(shutdown) { + // Wait for the UI thread to exit + WaitForSingleObject(hthreadui_, INFINITE); + + Lock(); + + // Unregister the window class + UnregisterClass(CefBrowserImpl::GetWndClass(), hinstance_); + + // Clean up thread and event handles + CloseHandle(hthreadui_); + CloseHandle(heventui_); + + hthreadui_ = NULL; + idthreadui_ = 0; + heventui_ = NULL; + messageloopui_ = NULL; + + // We have exited the transitional state + in_transition_ = false; + + Unlock(); + } +} + +bool CefContext::AddBrowser(CefRefPtr browser) +{ + bool found = false; + + Lock(); + + // check that the browser isn't already in the list before adding + BrowserList::const_iterator it = browserlist_.begin(); + for(; it != browserlist_.end(); ++it) { + if(it->get() == browser.get()) { + found = true; + break; + } + } + + if(!found) + browserlist_.push_back(browser); + + Unlock(); + return !found; +} + +bool CefContext::RemoveBrowser(CefRefPtr browser) +{ + bool deleted = false; + + Lock(); + + BrowserList::iterator it = browserlist_.begin(); + for(; it != browserlist_.end(); ++it) { + if(it->get() == browser.get()) { + browserlist_.erase(it); + deleted = true; + break; + } + } + + Unlock(); + + return deleted; +} + +void CefContext::SetMessageLoopForUI(MessageLoopForUI* loop) +{ + Lock(); + messageloopui_ = loop; + Unlock(); +} + +void CefContext::NotifyEvent() +{ + Lock(); + // Set the event state to signaled so that the waiting thread will be + // released. + if(heventui_) + SetEvent(heventui_); + Unlock(); +} + +void PostTask(const tracked_objects::Location& from_here, Task* task) +{ + if(_Context.get()) { + _Context->Lock(); + MessageLoopForUI *pMsgLoop = _Context->GetMessageLoopForUI(); + if(pMsgLoop) + pMsgLoop->PostTask(from_here, task); + _Context->Unlock(); + } +} \ No newline at end of file diff --git a/libcef/context.h b/libcef/context.h new file mode 100644 index 000000000..510a0e02e --- /dev/null +++ b/libcef/context.h @@ -0,0 +1,67 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 _CONTEXT_H +#define _CONTEXT_H + +#include "../include/cef.h" +#include "base/message_loop.h" +#include "base/gfx/native_widget_types.h" +#include "webkit/glue/webpreferences.h" + +class CefBrowserImpl; + +class CefContext : public CefThreadSafeBase +{ +public: + typedef std::list > BrowserList; + + CefContext(); + ~CefContext(); + + bool Initialize(); + void Shutdown(); + + MessageLoopForUI* GetMessageLoopForUI() { return messageloopui_; } + + HMODULE GetInstanceHandle() { return hinstance_; } + HANDLE GetUIThreadHandle() { return hthreadui_; } + DWORD GetUIThreadId() { return idthreadui_; } + WebPreferences* GetWebPreferences() { return webprefs_; } + + bool AddBrowser(CefRefPtr browser); + bool RemoveBrowser(CefRefPtr browser); + BrowserList* GetBrowserList() { return &browserlist_; } + + // Returns true if the calling thread is the same as the UI thread + bool RunningOnUIThread() { return (GetCurrentThreadId() == idthreadui_); } + +private: + void SetMessageLoopForUI(MessageLoopForUI* loop); + void NotifyEvent(); + +protected: + HMODULE hinstance_; + DWORD idthreadui_; + HANDLE hthreadui_; + HANDLE heventui_; + MessageLoopForUI* messageloopui_; + bool in_transition_; + BrowserList browserlist_; + WebPreferences* webprefs_; + + friend DWORD WINAPI ThreadHandlerUI(LPVOID lpParam); +}; + +// Post a task to the UI message loop +void PostTask(const tracked_objects::Location& from_here, Task* task); + +// Global context object pointer +extern CefRefPtr _Context; + +// Macro for requiring that a function be called on the UI thread +#define REQUIRE_UIT() DCHECK(_Context->RunningOnUIThread()) + +#endif // _CONTEXT_H \ No newline at end of file diff --git a/libcef/jscontainer.cc b/libcef/jscontainer.cc new file mode 100644 index 000000000..fcc185f5d --- /dev/null +++ b/libcef/jscontainer.cc @@ -0,0 +1,278 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "jscontainer.h" +#include "variant_impl.h" + +// Here's the control flow of a JS method getting forwarded to a class. +// - Something calls our NPObject with a function like "Invoke". +// - CefNPObject's static invoke() function forwards it to its attached +// CefJSContainer's Invoke() method. +// - CefJSContainer has then overridden Invoke() to look up the function +// name in its internal map of methods, and then calls the appropriate +// method. + +#include "base/compiler_specific.h" +#include "config.h" + +// This is required for the KJS build due to an artifact of the +// npruntime_priv.h file from JavaScriptCore/bindings. +MSVC_PUSH_DISABLE_WARNING(4067) +#include "npruntime_priv.h" +MSVC_POP_WARNING() + +#if USE(JSC) +MSVC_PUSH_WARNING_LEVEL(0) +#include +MSVC_POP_WARNING() +#endif + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "webkit/glue/webframe.h" + + +// Our special NPObject type. We extend an NPObject with a pointer to a +// CefJSContainer, which is just a C++ interface that we forward all NPObject +// callbacks to. +struct CefNPObject { + NPObject parent; // This must be the first field in the struct. + CefRefPtr container; + WebFrame* webframe; + + // + // All following objects and functions are static, and just used to interface + // with NPObject/NPClass. + // + + // An NPClass associates static functions of CefNPObject with the + // function pointers used by the JS runtime. + static NPClass np_class_; + + // Allocate a new NPObject with the specified class. + static NPObject* allocate(NPP npp, NPClass* aClass); + + // Free an object. + static void deallocate(NPObject* obj); + + // Returns true if the C++ class associated with this NPObject exposes the + // given property. Called by the JS runtime. + static bool hasProperty(NPObject *obj, NPIdentifier ident); + + // Returns true if the C++ class associated with this NPObject exposes the + // given method. Called by the JS runtime. + static bool hasMethod(NPObject *obj, NPIdentifier ident); + + // If the given method is exposed by the C++ class associated with this + // NPObject, invokes it with the given args and returns a result. Otherwise, + // returns "undefined" (in the JavaScript sense). Called by the JS runtime. + static bool invoke(NPObject *obj, NPIdentifier ident, + const NPVariant *args, uint32_t arg_count, + NPVariant *result); + + // If the given property is exposed by the C++ class associated with this + // NPObject, returns its value. Otherwise, returns "undefined" (in the + // JavaScript sense). Called by the JS runtime. + static bool getProperty(NPObject *obj, NPIdentifier ident, + NPVariant *result); + + // If the given property is exposed by the C++ class associated with this + // NPObject, sets its value. Otherwise, does nothing. Called by the JS + // runtime. + static bool setProperty(NPObject *obj, NPIdentifier ident, + const NPVariant *value); +}; + +// Build CefNPObject's static function pointers into an NPClass, for use +// in constructing NPObjects for the C++ classes. +NPClass CefNPObject::np_class_ = { + NP_CLASS_STRUCT_VERSION, + CefNPObject::allocate, + CefNPObject::deallocate, + /* NPInvalidateFunctionPtr */ NULL, + CefNPObject::hasMethod, + CefNPObject::invoke, + /* NPInvokeDefaultFunctionPtr */ NULL, + CefNPObject::hasProperty, + CefNPObject::getProperty, + CefNPObject::setProperty, + /* NPRemovePropertyFunctionPtr */ NULL +}; + +/* static */ NPObject* CefNPObject::allocate(NPP npp, NPClass* aClass) { + CefNPObject* obj = new CefNPObject; + // obj->parent will be initialized by the NPObject code calling this. + obj->container = NULL; + return &obj->parent; +} + +/* static */ void CefNPObject::deallocate(NPObject* np_obj) { + CefNPObject* obj = reinterpret_cast(np_obj); + delete obj; +} + +/* static */ bool CefNPObject::hasMethod(NPObject* np_obj, + NPIdentifier ident) { + CefNPObject* obj = reinterpret_cast(np_obj); + return obj->container->HasMethod(ident); +} + +/* static */ bool CefNPObject::hasProperty(NPObject* np_obj, + NPIdentifier ident) { + CefNPObject* obj = reinterpret_cast(np_obj); + return obj->container->HasProperty(ident); +} + +/* static */ bool CefNPObject::invoke(NPObject* np_obj, NPIdentifier ident, + const NPVariant* args, uint32_t arg_count, + NPVariant* result) { + CefNPObject* obj = reinterpret_cast(np_obj); + return obj->container->Invoke(ident, obj->webframe, args, arg_count, result); +} + +/* static */ bool CefNPObject::getProperty(NPObject* np_obj, + NPIdentifier ident, + NPVariant* result) { + CefNPObject* obj = reinterpret_cast(np_obj); + return obj->container->GetProperty(ident, obj->webframe, result); +} + +/* static */ bool CefNPObject::setProperty(NPObject* np_obj, + NPIdentifier ident, + const NPVariant* value) { + CefNPObject* obj = reinterpret_cast(np_obj); + return obj->container->SetProperty(ident, obj->webframe, value); +} + +CefJSContainer::CefJSContainer(CefRefPtr browser, + CefRefPtr handler) + : browser_(browser), handler_(handler) +{ + DCHECK(browser_.get() != NULL); + DCHECK(handler_.get() != NULL); +} + +CefJSContainer::~CefJSContainer() +{ + // Unregister objects we created and bound to a frame. + for (BoundObjectList::iterator i = bound_objects_.begin(); + i != bound_objects_.end(); ++i) { +#if USE(V8) + _NPN_UnregisterObject(*i); +#endif + NPN_ReleaseObject(*i); + } +} + +bool CefJSContainer::HasMethod(NPIdentifier ident) +{ + std::wstring name = UTF8ToWide(NPN_UTF8FromIdentifier(ident)); + return handler_->HasMethod(browser_, name); +} + +bool CefJSContainer::HasProperty(NPIdentifier ident) +{ + std::wstring name = UTF8ToWide(NPN_UTF8FromIdentifier(ident)); + return handler_->HasProperty(browser_, name); +} + +bool CefJSContainer::Invoke(NPIdentifier ident, + WebFrame* frame, + const NPVariant* args, + size_t arg_count, + NPVariant* result) +{ + std::wstring name = UTF8ToWide(NPN_UTF8FromIdentifier(ident)); + + // Build a VariantVector argument vector from the NPVariants coming in. + CefJSHandler::VariantVector cef_args(arg_count); + for (size_t i = 0; i < arg_count; i++) { + cef_args[i] = new CefVariantImpl(frame); + static_cast(cef_args[i].get())->Set(args[i]); + } + + CefRefPtr cef_retval(new CefVariantImpl(frame)); + + // Execute the handler method + bool rv = handler_->ExecuteMethod(browser_, name, cef_args, cef_retval); + if(rv) { + // Assign the return value + static_cast(cef_retval.get())->CopyToNPVariant(result); + } + return rv; +} + +bool CefJSContainer::GetProperty(NPIdentifier ident, + WebFrame* frame, + NPVariant* result) +{ + CefRefPtr cef_result(new CefVariantImpl(frame)); + std::wstring name = UTF8ToWide(NPN_UTF8FromIdentifier(ident)); + + // Execute the handler method + bool rv = handler_->GetProperty(browser_, name, cef_result); + if(rv) { + // Assign the return value + static_cast(cef_result.get())->CopyToNPVariant(result); + } + return rv; +} + +bool CefJSContainer::SetProperty(NPIdentifier ident, + WebFrame* frame, + const NPVariant* value) +{ + std::wstring name = UTF8ToWide(NPN_UTF8FromIdentifier(ident)); + + // Assign the input value + CefRefPtr cef_value(new CefVariantImpl(frame)); + static_cast(cef_value.get())->Set(*value); + + // Execute the handler method + return handler_->SetProperty(browser_, name, cef_value); +} + +void CefJSContainer::BindToJavascript(WebFrame* frame, + const std::wstring& classname) { +#if USE(JSC) + JSC::JSLock lock(false); +#endif + + NPObject* np_obj = NULL; + CefNPObject* obj = NULL; + + // Check if we already have an NPObject bound to this particular frame. + Lock(); + BoundObjectList::const_iterator it = bound_objects_.begin(); + for(; it != bound_objects_.end(); ++it) { + obj = reinterpret_cast(*it); + if(obj->webframe == frame) { + np_obj = *it; + break; + } + } + Unlock(); + + if(!np_obj) { + // Create an NPObject using our static NPClass. The first argument (a + // plugin's instance handle) is passed through to the allocate function + // directly, and we don't use it, so it's ok to be 0. + np_obj = NPN_CreateObject(0, &CefNPObject::np_class_); + obj = reinterpret_cast(np_obj); + obj->container = this; + obj->webframe = frame; + + Lock(); + bound_objects_.push_back(np_obj); + Unlock(); + } + + // BindToWindowObject will (indirectly) retain the np_object. We save it + // so we can release it when we're destroyed. + frame->BindToWindowObject(classname, np_obj); +} + diff --git a/libcef/jscontainer.h b/libcef/jscontainer.h new file mode 100644 index 000000000..95070c992 --- /dev/null +++ b/libcef/jscontainer.h @@ -0,0 +1,65 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 _JSCONTAINER_H +#define _JSCONTAINER_H + +#include "../include/cef.h" +#include "third_party/npapi/bindings/npruntime.h" + +class WebFrame; + +// CefJSContainer lets you map Javascript method calls and property accesses +// directly to C++ method calls and CefVariant* variable access. +// Portions of the implementation are borrowed from +// webkit\glue\cpp_bound_class.cc +class CefJSContainer : public CefThreadSafeBase +{ +public: + CefJSContainer(CefRefPtr browser, + CefRefPtr handler); + ~CefJSContainer(); + + // Given a WebFrame, BindToJavascript builds the NPObject that will represent + // the class and binds it to the frame's window under the given name. This + // should generally be called from the WebView delegate's + // WindowObjectCleared(). A class so bound will be accessible to JavaScript + // as window.. The owner of the CefJSContainer is responsible for + // keeping the object around while the frame is alive, and for destroying it + // afterwards. + void BindToJavascript(WebFrame* frame, + const std::wstring& classname); + + CefRefPtr GetHandler() { return handler_; } + +protected: + bool HasMethod(NPIdentifier ident); + bool HasProperty(NPIdentifier ident); + bool Invoke(NPIdentifier ident, + WebFrame* frame, + const NPVariant* args, + size_t arg_count, + NPVariant* result); + bool GetProperty(NPIdentifier ident, + WebFrame* frame, + NPVariant* result); + bool SetProperty(NPIdentifier ident, + WebFrame* frame, + const NPVariant* value); + + friend struct CefNPObject; + +protected: + CefRefPtr browser_; + CefRefPtr handler_; + + // A list of all NPObjects we created and bound in BindToJavascript(), so we + // can clean them up when we're destroyed. + typedef std::vector BoundObjectList; + BoundObjectList bound_objects_; +}; + + +#endif // _JSHANDLER_CONTAINER_H diff --git a/libcef/libcef.vcproj b/libcef/libcef.vcproj new file mode 100644 index 000000000..c05bc15f1 --- /dev/null +++ b/libcef/libcef.vcproj @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libcef/libcef.vsprops b/libcef/libcef.vsprops new file mode 100644 index 000000000..3126eb186 --- /dev/null +++ b/libcef/libcef.vsprops @@ -0,0 +1,22 @@ + + + + + + diff --git a/libcef/libcef_webkit.vsprops b/libcef/libcef_webkit.vsprops new file mode 100644 index 000000000..0ce62e95b --- /dev/null +++ b/libcef/libcef_webkit.vsprops @@ -0,0 +1,8 @@ + + + diff --git a/libcef/libcef_webkit_includes.vsprops b/libcef/libcef_webkit_includes.vsprops new file mode 100644 index 000000000..2092a56a4 --- /dev/null +++ b/libcef/libcef_webkit_includes.vsprops @@ -0,0 +1,11 @@ + + + + diff --git a/libcef/precompiled_libcef.cc b/libcef/precompiled_libcef.cc new file mode 100644 index 000000000..68f617b69 --- /dev/null +++ b/libcef/precompiled_libcef.cc @@ -0,0 +1,5 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 "precompiled_libcef.h" diff --git a/libcef/precompiled_libcef.h b/libcef/precompiled_libcef.h new file mode 100644 index 000000000..7bb370ac4 --- /dev/null +++ b/libcef/precompiled_libcef.h @@ -0,0 +1,7 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 +#include +#include diff --git a/libcef/printing/page_number.cc b/libcef/printing/page_number.cc new file mode 100644 index 000000000..871b92119 --- /dev/null +++ b/libcef/printing/page_number.cc @@ -0,0 +1,85 @@ +// Copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "page_number.h" +#include "print_settings.h" + +#include + +#include "base/logging.h" + +namespace printing { + +PageNumber::PageNumber(const PrintSettings& settings, int document_page_count) { + Init(settings, document_page_count); +} + +PageNumber::PageNumber() + : ranges_(NULL), + page_number_(-1), + page_range_index_(-1), + document_page_count_(0) { +} + +void PageNumber::operator=(const PageNumber& other) { + ranges_ = other.ranges_; + page_number_ = other.page_number_; + page_range_index_ = other.page_range_index_; + document_page_count_ = other.document_page_count_; +} + +void PageNumber::Init(const PrintSettings& settings, int document_page_count) { + DCHECK(document_page_count); + ranges_ = settings.ranges.empty() ? NULL : &settings.ranges; + document_page_count_ = document_page_count; + if (ranges_) { + page_range_index_ = 0; + page_number_ = (*ranges_)[0].from; + } else { + if (document_page_count) { + page_number_ = 0; + } else { + page_number_ = -1; + } + page_range_index_ = -1; + } +} + +int PageNumber::operator++() { + if (!ranges_) { + // Switch to next page. + if (++page_number_ == document_page_count_) { + // Finished. + *this = npos(); + } + } else { + // Switch to next page. + ++page_number_; + // Page ranges are inclusive. + if (page_number_ > (*ranges_)[page_range_index_].to) { + DCHECK(ranges_->size() <= static_cast( + std::numeric_limits::max())); + if (++page_range_index_ == static_cast(ranges_->size())) { + // Finished. + *this = npos(); + } else { + page_number_ = (*ranges_)[page_range_index_].from; + } + } + } + return ToInt(); +} + +bool PageNumber::operator==(const PageNumber& other) const { + return page_number_ == other.page_number_ && + page_range_index_ == other.page_range_index_; +} +bool PageNumber::operator!=(const PageNumber& other) const { + return page_number_ != other.page_number_ || + page_range_index_ != other.page_range_index_; +} + +} // namespace printing + diff --git a/libcef/printing/page_number.h b/libcef/printing/page_number.h new file mode 100644 index 000000000..2679cd6bd --- /dev/null +++ b/libcef/printing/page_number.h @@ -0,0 +1,74 @@ +// Copyright (c) 2006-2008 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 _PRINTING_PAGE_NUMBER_H +#define _PRINTING_PAGE_NUMBER_H + +#include + +#include "page_range.h" + +namespace printing { + +class PrintSettings; + +// Represents a page series following the array of page ranges defined in a +// PrintSettings. +class PageNumber { + public: + // Initializes the page to the first page in the settings's range or 0. + PageNumber(const PrintSettings& settings, int document_page_count); + + PageNumber(); + + void operator=(const PageNumber& other); + + // Initializes the page to the first page in the setting's range or 0. It + // initialize to npos if the range is empty and document_page_count is 0. + void Init(const PrintSettings& settings, int document_page_count); + + // Converts to a page numbers. + int ToInt() const { + return page_number_; + } + + // Calculates the next page in the serie. + int operator++(); + + // Returns an instance that represents the end of a serie. + static const PageNumber npos() { + return PageNumber(); + } + + // Equality operator. Only the current page number is verified so that + // "page != PageNumber::npos()" works. + bool operator==(const PageNumber& other) const; + bool operator!=(const PageNumber& other) const; + + private: + // The page range to follow. + const PageRanges* ranges_; + + // The next page to be printed. -1 when not printing. + int page_number_; + + // The next page to be printed. -1 when not used. Valid only if + // document()->settings().range.empty() is false. + int page_range_index_; + + // Number of expected pages in the document. Used when ranges_ is NULL. + int document_page_count_; +}; + +// Debug output support. +template +inline typename std::basic_ostream& operator<<( + typename std::basic_ostream& ss, const PageNumber& page) { + return ss << page.ToInt(); +} + +} // namespace printing + +#endif // _PRINTING_PAGE_NUMBER_H + diff --git a/libcef/printing/page_range.cc b/libcef/printing/page_range.cc new file mode 100644 index 000000000..0226773bb --- /dev/null +++ b/libcef/printing/page_range.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "page_range.h" + +#include "chrome/common/stl_util-inl.h" + +namespace printing { + +std::vector PageRange::GetPages(const PageRanges& ranges) { + std::set pages; + for (unsigned i = 0; i < ranges.size(); ++i) { + const PageRange& range = ranges[i]; + // Ranges are inclusive. + for (int i = range.from; i <= range.to; ++i) { + pages.insert(i); + } + } + return SetToVector(pages); +} + +} // namespace printing + diff --git a/libcef/printing/page_range.h b/libcef/printing/page_range.h new file mode 100644 index 000000000..636f6c1e7 --- /dev/null +++ b/libcef/printing/page_range.h @@ -0,0 +1,32 @@ +// Copyright (c) 2006-2008 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 _PRINTING_PAGE_RANGE_H +#define _PRINTING_PAGE_RANGE_H + +#include + +namespace printing { + +struct PageRange; + +typedef std::vector PageRanges; + +// Print range is inclusive. To select one page, set from == to. +struct PageRange { + int from; + int to; + + bool operator==(const PageRange& rhs) const { + return from == rhs.from && to == rhs.to; + } + + // Retrieves the sorted list of unique pages in the page ranges. + static std::vector GetPages(const PageRanges& ranges); +}; + +} // namespace printing + +#endif // _PRINTING_PAGE_RANGE_H + diff --git a/libcef/printing/page_setup.cc b/libcef/printing/page_setup.cc new file mode 100644 index 000000000..2912e80af --- /dev/null +++ b/libcef/printing/page_setup.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "page_setup.h" + +#include "base/logging.h" + +namespace printing { + +PageMargins::PageMargins() + : header(0), + footer(0), + left(0), + right(0), + top(0), + bottom(0) { +} + +void PageMargins::Clear() { + header = 0; + footer = 0; + left = 0; + right = 0; + top = 0; + bottom = 0; +} + +bool PageMargins::Equals(const PageMargins& rhs) const { + return header == rhs.header && + footer == rhs.footer && + left == rhs.left && + top == rhs.top && + right == rhs.right && + bottom == rhs.bottom; +} + +PageSetup::PageSetup() : text_height_(0) { +} + +void PageSetup::Clear() { + physical_size_.SetSize(0, 0); + printable_area_.SetRect(0, 0, 0, 0); + overlay_area_.SetRect(0, 0, 0, 0); + content_area_.SetRect(0, 0, 0, 0); + effective_margins_.Clear(); + text_height_ = 0; +} + +bool PageSetup::Equals(const PageSetup& rhs) const { + return physical_size_ == rhs.physical_size_ && + printable_area_ == rhs.printable_area_ && + overlay_area_ == rhs.overlay_area_ && + content_area_ == rhs.content_area_ && + effective_margins_.Equals(rhs.effective_margins_) && + requested_margins_.Equals(rhs.requested_margins_) && + text_height_ == rhs.text_height_; +} + +void PageSetup::Init(const gfx::Size& physical_size, + const gfx::Rect& printable_area, + int text_height) { + DCHECK_LE(printable_area.right(), physical_size.width()); + // I've seen this assert triggers on Canon GP160PF PCL 5e and HP LaserJet 5. + // Since we don't know the dpi here, just disable the check. + // DCHECK_LE(printable_area.bottom(), physical_size.height()); + DCHECK_GE(printable_area.x(), 0); + DCHECK_GE(printable_area.y(), 0); + DCHECK_GE(text_height, 0); + physical_size_ = physical_size; + printable_area_ = printable_area; + text_height_ = text_height; + + // Calculate the effective margins. The tricky part. + effective_margins_.header = std::max(requested_margins_.header, + printable_area_.y()); + effective_margins_.footer = std::max(requested_margins_.footer, + physical_size.height() - + printable_area_.bottom()); + effective_margins_.left = std::max(requested_margins_.left, + printable_area_.x()); + effective_margins_.top = std::max(std::max(requested_margins_.top, + printable_area_.y()), + effective_margins_.header + text_height); + effective_margins_.right = std::max(requested_margins_.right, + physical_size.width() - + printable_area_.right()); + effective_margins_.bottom = std::max(std::max(requested_margins_.bottom, + physical_size.height() - + printable_area_.bottom()), + effective_margins_.footer + text_height); + + // Calculate the overlay area. If the margins are excessive, the overlay_area + // size will be (0, 0). + overlay_area_.set_x(effective_margins_.left); + overlay_area_.set_y(effective_margins_.header); + overlay_area_.set_width(std::max(0, + physical_size.width() - + effective_margins_.right - + overlay_area_.x())); + overlay_area_.set_height(std::max(0, + physical_size.height() - + effective_margins_.footer - + overlay_area_.y())); + + // Calculate the content area. If the margins are excessive, the content_area + // size will be (0, 0). + content_area_.set_x(effective_margins_.left); + content_area_.set_y(effective_margins_.top); + content_area_.set_width(std::max(0, + physical_size.width() - + effective_margins_.right - + content_area_.x())); + content_area_.set_height(std::max(0, + physical_size.height() - + effective_margins_.bottom - + content_area_.y())); +} + +void PageSetup::SetRequestedMargins(const PageMargins& requested_margins) { + requested_margins_ = requested_margins; + if (physical_size_.width() && physical_size_.height()) + Init(physical_size_, printable_area_, text_height_); +} + +} // namespace printing + diff --git a/libcef/printing/page_setup.h b/libcef/printing/page_setup.h new file mode 100644 index 000000000..c13c3b7e9 --- /dev/null +++ b/libcef/printing/page_setup.h @@ -0,0 +1,83 @@ +// Copyright (c) 2006-2008 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 _PRINTING_PAGE_SETUP_H +#define _PRINTING_PAGE_SETUP_H + +#include "base/gfx/rect.h" + +namespace printing { + +// Margins for a page setup. +class PageMargins { + public: + PageMargins(); + + void Clear(); + + // Equality operator. + bool Equals(const PageMargins& rhs) const; + + // Vertical space for the overlay from the top of the sheet. + int header; + // Vertical space for the overlay from the bottom of the sheet. + int footer; + // Margin on each side of the sheet. + int left; + int right; + int top; + int bottom; +}; + +// Settings that define the size and printable areas of a page. Unit is +// unspecified. +class PageSetup { + public: + PageSetup(); + + void Clear(); + + // Equality operator. + bool Equals(const PageSetup& rhs) const; + + void Init(const gfx::Size& physical_size, const gfx::Rect& printable_area, + int text_height); + + void SetRequestedMargins(const PageMargins& requested_margins); + + const gfx::Size& physical_size() const { return physical_size_; } + const gfx::Rect& overlay_area() const { return overlay_area_; } + const gfx::Rect& content_area() const { return content_area_; } + const PageMargins& effective_margins() const { + return effective_margins_; + } + + private: + // Physical size of the page, including non-printable margins. + gfx::Size physical_size_; + + // The printable area as specified by the printer driver. We can't get + // larger than this. + gfx::Rect printable_area_; + + // The printable area for headers and footers. + gfx::Rect overlay_area_; + + // The printable area as selected by the user's margins. + gfx::Rect content_area_; + + // Effective margins. + PageMargins effective_margins_; + + // Requested margins. + PageMargins requested_margins_; + + // Space that must be kept free for the overlays. + int text_height_; +}; + +} // namespace printing + +#endif // _PRINTING_PAGE_SETUP_H + diff --git a/libcef/printing/print_settings.cc b/libcef/printing/print_settings.cc new file mode 100644 index 000000000..ba3225d9a --- /dev/null +++ b/libcef/printing/print_settings.cc @@ -0,0 +1,173 @@ +// Copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "print_settings.h" +#include "units.h" + +#include "base/atomic_sequence_num.h" +#include "base/logging.h" + +namespace printing { + +// Global SequenceNumber used for generating unique cookie values. +static base::AtomicSequenceNumber cookie_seq(base::LINKER_INITIALIZED); + +PrintSettings::PrintSettings() + : min_shrink(1.25), + max_shrink(2.0), + desired_dpi(72), + dpi_(0), + landscape_(false) { +} + +void PrintSettings::Clear() { + ranges.clear(); + min_shrink = 1.25; + max_shrink = 2.; + desired_dpi = 72; + printer_name_.clear(); + device_name_.clear(); + page_setup_cmm_.Clear(); + page_setup_pixels_.Clear(); + dpi_ = 0; + landscape_ = false; +} + +#ifdef WIN32 +void PrintSettings::Init(HDC hdc, + const DEVMODE& dev_mode, + const PageRanges& new_ranges, + const std::wstring& new_device_name) { + DCHECK(hdc); + printer_name_ = dev_mode.dmDeviceName; + device_name_ = new_device_name; + ranges = new_ranges; + landscape_ = dev_mode.dmOrientation == DMORIENT_LANDSCAPE; + + int old_dpi = dpi_; + dpi_ = GetDeviceCaps(hdc, LOGPIXELSX); + // No printer device is known to advertise different dpi in X and Y axis; even + // the fax device using the 200x100 dpi setting. It's ought to break so many + // applications that it's not even needed to care about. WebKit doesn't + // support different dpi settings in X and Y axis. + DCHECK_EQ(dpi_, GetDeviceCaps(hdc, LOGPIXELSY)); + + DCHECK_EQ(GetDeviceCaps(hdc, SCALINGFACTORX), 0); + DCHECK_EQ(GetDeviceCaps(hdc, SCALINGFACTORY), 0); + + // Initialize page_setup_pixels_. + gfx::Size physical_size_pixels(GetDeviceCaps(hdc, PHYSICALWIDTH), + GetDeviceCaps(hdc, PHYSICALHEIGHT)); + gfx::Rect printable_area_pixels(GetDeviceCaps(hdc, PHYSICALOFFSETX), + GetDeviceCaps(hdc, PHYSICALOFFSETY), + GetDeviceCaps(hdc, HORZRES), + GetDeviceCaps(hdc, VERTRES)); + // Hard-code text_height = 0.5cm = ~1/5 of inch + page_setup_pixels_.Init(physical_size_pixels, printable_area_pixels, + ConvertUnit(500, kHundrethsMMPerInch, dpi_)); + + // Initialize page_setup_cmm_. + // In theory, we should be using HORZSIZE and VERTSIZE but their value is + // so wrong it's useless. So read the values in dpi unit and convert them back + // in 0.01 mm. + gfx::Size physical_size_cmm( + ConvertUnit(physical_size_pixels.width(), dpi_, kHundrethsMMPerInch), + ConvertUnit(physical_size_pixels.height(), dpi_, kHundrethsMMPerInch)); + gfx::Rect printable_area_cmm( + ConvertUnit(printable_area_pixels.x(), dpi_, kHundrethsMMPerInch), + ConvertUnit(printable_area_pixels.y(), dpi_, kHundrethsMMPerInch), + ConvertUnit(printable_area_pixels.width(), dpi_, kHundrethsMMPerInch), + ConvertUnit(printable_area_pixels.bottom(), dpi_, kHundrethsMMPerInch)); + + static const int kRoundingTolerance = 5; + // Some printers may advertise a slightly larger printable area than the + // physical area. This is mostly due to integer calculation and rounding. + if (physical_size_cmm.height() > printable_area_cmm.bottom() && + physical_size_cmm.height() <= (printable_area_cmm.bottom() + + kRoundingTolerance)) { + physical_size_cmm.set_height(printable_area_cmm.bottom()); + } + if (physical_size_cmm.width() > printable_area_cmm.right() && + physical_size_cmm.width() <= (printable_area_cmm.right() + + kRoundingTolerance)) { + physical_size_cmm.set_width(printable_area_cmm.right()); + } + page_setup_cmm_.Init(physical_size_cmm, printable_area_cmm, 500); +} +#endif + +void PrintSettings::UpdateMarginsMetric(const PageMargins& new_margins) { + // Apply the new margins in 0.01 mm unit. + page_setup_cmm_.SetRequestedMargins(new_margins); + + // Converts the margins in dpi unit and apply those too. + PageMargins pixels_margins; + pixels_margins.header = ConvertUnit(new_margins.header, kHundrethsMMPerInch, + dpi_); + pixels_margins.footer = ConvertUnit(new_margins.footer, kHundrethsMMPerInch, + dpi_); + pixels_margins.left = ConvertUnit(new_margins.left, kHundrethsMMPerInch, + dpi_); + pixels_margins.top = ConvertUnit(new_margins.top, kHundrethsMMPerInch, dpi_); + pixels_margins.right = ConvertUnit(new_margins.right, kHundrethsMMPerInch, + dpi_); + pixels_margins.bottom = ConvertUnit(new_margins.bottom, kHundrethsMMPerInch, + dpi_); + page_setup_pixels_.SetRequestedMargins(pixels_margins); +} + +void PrintSettings::UpdateMarginsMilliInch(const PageMargins& new_margins) { + // Convert margins from thousandth inches to cmm (0.01mm). + PageMargins cmm_margins; + cmm_margins.header = + ConvertMilliInchToHundredThousanthMeter(new_margins.header); + cmm_margins.footer = + ConvertMilliInchToHundredThousanthMeter(new_margins.footer); + cmm_margins.left = ConvertMilliInchToHundredThousanthMeter(new_margins.left); + cmm_margins.top = ConvertMilliInchToHundredThousanthMeter(new_margins.top); + cmm_margins.right = + ConvertMilliInchToHundredThousanthMeter(new_margins.right); + cmm_margins.bottom = + ConvertMilliInchToHundredThousanthMeter(new_margins.bottom); + UpdateMarginsMetric(cmm_margins); +} + +void PrintSettings::RenderParams(PrintParams* params) const { + DCHECK(params); + params->printable_size.SetSize(page_setup_pixels_.content_area().width(), + page_setup_pixels_.content_area().height()); + params->dpi = dpi_; + // Currently hardcoded at 1.25. See PrintSettings' constructor. + params->min_shrink = min_shrink; + // Currently hardcoded at 2.0. See PrintSettings' constructor. + params->max_shrink = max_shrink; + // Currently hardcoded at 72dpi. See PrintSettings' constructor. + params->desired_dpi = desired_dpi; + // Always use an invalid cookie. + params->document_cookie = 0; +} + +bool PrintSettings::Equals(const PrintSettings& rhs) const { + // Do not test the display device name (printer_name_) for equality since it + // may sometimes be chopped off at 30 chars. As long as device_name is the + // same, that's fine. + return ranges == rhs.ranges && + min_shrink == rhs.min_shrink && + max_shrink == rhs.max_shrink && + desired_dpi == rhs.desired_dpi && + device_name_ == rhs.device_name_ && + page_setup_pixels_.Equals(rhs.page_setup_pixels_) && + page_setup_cmm_.Equals(rhs.page_setup_cmm_) && + dpi_ == rhs.dpi_ && + landscape_ == rhs.landscape_; +} + +int PrintSettings::NewCookie() { + // A cookie of 0 is used to mark a document as unassigned, count from 1. + return cookie_seq.GetNext() + 1; +} + +} // namespace printing + diff --git a/libcef/printing/print_settings.h b/libcef/printing/print_settings.h new file mode 100644 index 000000000..11c55ee63 --- /dev/null +++ b/libcef/printing/print_settings.h @@ -0,0 +1,141 @@ +// Copyright (c) 2006-2008 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 _PRINTING_PRINT_SETTINGS_H +#define _PRINTING_PRINT_SETTINGS_H + +#include "page_range.h" +#include "page_setup.h" + +#include "base/gfx/rect.h" + +typedef struct HDC__* HDC; +typedef struct _devicemodeW DEVMODE; + +namespace printing { + +// Parameters for a render request. +struct PrintParams { + // In pixels according to dpi_x and dpi_y. + gfx::Size printable_size; + + // Specifies dots per inch. + double dpi; + + // Minimum shrink factor. See PrintSettings::min_shrink for more information. + double min_shrink; + + // Maximum shrink factor. See PrintSettings::max_shrink for more information. + double max_shrink; + + // Desired apparent dpi on paper. + int desired_dpi; + + // Cookie for the document to ensure correctness. + int document_cookie; + + // Warning: do not compare document_cookie. + bool Equals(const PrintParams& rhs) const { + return printable_size == rhs.printable_size && + dpi == rhs.dpi && + min_shrink == rhs.min_shrink && + max_shrink == rhs.max_shrink && + desired_dpi == rhs.desired_dpi; + } +}; + +// OS-independent print settings. +class PrintSettings { + public: + PrintSettings(); + + // Reinitialize the settings to the default values. + void Clear(); + +#ifdef WIN32 + // Reads the settings from the selected device context. Calculates derived + // values like printable_area_. + void Init(HDC hdc, + const DEVMODE& dev_mode, + const PageRanges& new_ranges, + const std::wstring& new_device_name); +#endif + + // Sets margins in 0.01 millimeter unit. + void UpdateMarginsMetric(const PageMargins& new_margins); + + // Sets margins in thousandth of inch. + void UpdateMarginsMilliInch(const PageMargins& new_margins); + + // Initializes the print parameters that needs to be sent to the renderer + // process. + void RenderParams(PrintParams* params) const; + + // Equality operator. + // NOTE: printer_name is NOT tested for equality since it doesn't affect the + // output. + bool Equals(const PrintSettings& rhs) const; + + const std::wstring& printer_name() const { return printer_name_; } + void set_device_name(const std::wstring& device_name) { + device_name_ = device_name; + } + const std::wstring& device_name() const { return device_name_; } + int dpi() const { return dpi_; } + const PageSetup& page_setup_cmm() const { return page_setup_cmm_; } + const PageSetup& page_setup_pixels() const { return page_setup_pixels_; } + + // Multipage printing. Each PageRange describes a from-to page combinaison. + // This permits printing some selected pages only. + PageRanges ranges; + + // By imaging to a width a little wider than the available pixels, thin pages + // will be scaled down a little, matching the way they print in IE and Camino. + // This lets them use fewer sheets than they would otherwise, which is + // presumably why other browsers do this. Wide pages will be scaled down more + // than this. + double min_shrink; + + // This number determines how small we are willing to reduce the page content + // in order to accommodate the widest line. If the page would have to be + // reduced smaller to make the widest line fit, we just clip instead (this + // behavior matches MacIE and Mozilla, at least) + double max_shrink; + + // Desired visible dots per inch rendering for output. Printing should be + // scaled to ScreenDpi/dpix*desired_dpi. + int desired_dpi; + + // Cookie generator. It is used to initialize PrintedDocument with its + // associated PrintSettings, to be sure that each generated PrintedPage is + // correctly associated with its corresponding PrintedDocument. + static int NewCookie(); + + private: + ////////////////////////////////////////////////////////////////////////////// + // Settings that can't be changed without side-effects. + + // Printer name as shown to the user. + std::wstring printer_name_; + + // Printer device name as opened by the OS. + std::wstring device_name_; + + // Page setup in centimillimeter (0.01 mm) units. + PageSetup page_setup_cmm_; + + // Page setup in pixel units, dpi adjusted. + PageSetup page_setup_pixels_; + + // Printer's device effective dots per inch in both axis. + int dpi_; + + // Is the orientation landscape or portrait. + bool landscape_; +}; + +} // namespace printing + +#endif // _PRINTING_PRINT_SETTINGS_H + diff --git a/libcef/printing/units.cc b/libcef/printing/units.cc new file mode 100644 index 000000000..dde0adfbe --- /dev/null +++ b/libcef/printing/units.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "units.h" + +#include "base/logging.h" + +namespace printing { + +int ConvertUnit(int value, int old_unit, int new_unit) { + DCHECK_GT(new_unit, 0); + DCHECK_GT(old_unit, 0); + // With integer arithmetic, to divide a value with correct rounding, you need + // to add half of the divisor value to the dividend value. You need to do the + // reverse with negative number. + if (value >= 0) { + return ((value * new_unit) + (old_unit / 2)) / old_unit; + } else { + return ((value * new_unit) - (old_unit / 2)) / old_unit; + } +} + +double ConvertUnitDouble(double value, double old_unit, double new_unit) { + DCHECK_GT(new_unit, 0); + DCHECK_GT(old_unit, 0); + return value * new_unit / old_unit; +} + +int ConvertMilliInchToHundredThousanthMeter(int milli_inch) { + // 1" == 25.4 mm + // 1" == 25400 um + // 0.001" == 25.4 um + // 0.001" == 2.54 cmm + return ConvertUnit(milli_inch, 100, 254); +} + +int ConvertHundredThousanthMeterToMilliInch(int cmm) { + return ConvertUnit(cmm, 254, 100); +} + +} // namespace printing + diff --git a/libcef/printing/units.h b/libcef/printing/units.h new file mode 100644 index 000000000..4ec39214d --- /dev/null +++ b/libcef/printing/units.h @@ -0,0 +1,28 @@ +// Copyright (c) 2006-2008 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 _PRINTING_UNITS_H +#define _PRINTING_UNITS_H + +namespace printing { + +// Length of a thousanth of inches in 0.01mm unit. +const int kHundrethsMMPerInch = 2540; + +// Converts from one unit system to another using integer arithmetics. +int ConvertUnit(int value, int old_unit, int new_unit); + +// Converts from one unit system to another using doubles. +double ConvertUnitDouble(double value, double old_unit, double new_unit); + +// Converts from 0.001 inch unit to 0.00001 meter. +int ConvertMilliInchToHundredThousanthMeter(int milli_inch); + +// Converts from 0.00001 meter unit to 0.001 inch. +int ConvertHundredThousanthMeterToMilliInch(int cmm); + +} // namespace printing + +#endif // _PRINTING_UNITS_H + diff --git a/libcef/printing/win_printing_context.cc b/libcef/printing/win_printing_context.cc new file mode 100644 index 000000000..fc5dd4029 --- /dev/null +++ b/libcef/printing/win_printing_context.cc @@ -0,0 +1,479 @@ +// Copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "win_printing_context.h" + +#include + +#include "base/file_util.h" +#include "base/gfx/platform_canvas.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/scoped_ptr.h" +#include "base/time_format.h" + +using base::Time; + +namespace { + +// Retrieves the content of a GetPrinter call. +void GetPrinterHelper(HANDLE printer, int level, scoped_array* buffer) { + DWORD buf_size = 0; + GetPrinter(printer, level, NULL, 0, &buf_size); + if (buf_size) { + buffer->reset(new uint8[buf_size]); + memset(buffer->get(), 0, buf_size); + if (!GetPrinter(printer, level, buffer->get(), buf_size, &buf_size)) { + buffer->reset(); + } + } +} + +} // namespace + +namespace printing { + +PrintingContext::PrintingContext() + : hdc_(NULL), +#ifndef NDEBUG + page_number_(-1), +#endif + dialog_box_(NULL), + dialog_box_dismissed_(false), + abort_printing_(false), + in_print_job_(false) { +} + +PrintingContext::~PrintingContext() { + ResetSettings(); +} + +PrintingContext::Result PrintingContext::AskUserForSettings(HWND window, + int max_pages) { + DCHECK(window); + DCHECK(!in_print_job_); + dialog_box_dismissed_ = false; + // Show the OS-dependent dialog box. + // If the user press + // - OK, the settings are reset and reinitialized with the new settings. OK is + // returned. + // - Apply then Cancel, the settings are reset and reinitialized with the new + // settings. CANCEL is returned. + // - Cancel, the settings are not changed, the previous setting, if it was + // initialized before, are kept. CANCEL is returned. + // On failure, the settings are reset and FAILED is returned. + PRINTDLGEX dialog_options = { sizeof(PRINTDLGEX) }; + dialog_options.hwndOwner = window; + // Disables the Current Page and Selection radio buttons since WebKit can't + // print a part of the webpage and we don't know which page is the current + // one. + // TODO(maruel): Reuse the previously loaded settings! + dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | + PD_NOSELECTION | PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE; + PRINTPAGERANGE ranges[32]; + dialog_options.nStartPage = START_PAGE_GENERAL; + if (max_pages) { + // Default initialize to print all the pages. + memset(ranges, 0, sizeof(ranges)); + ranges[0].nFromPage = 1; + ranges[0].nToPage = max_pages; + dialog_options.nPageRanges = 1; + dialog_options.nMaxPageRanges = arraysize(ranges); + dialog_options.nMaxPage = max_pages; + dialog_options.lpPageRanges = ranges; + } else { + // No need to bother, we don't know how many pages are available. + dialog_options.Flags |= PD_NOPAGENUMS; + } + + { + if (PrintDlgEx(&dialog_options) != S_OK) { + ResetSettings(); + return FAILED; + } + } + // TODO(maruel): Support PD_PRINTTOFILE. + return ParseDialogResultEx(dialog_options); +} + +PrintingContext::Result PrintingContext::UseDefaultSettings() { + DCHECK(!in_print_job_); + + PRINTDLG dialog_options = { sizeof(PRINTDLG) }; + dialog_options.Flags = PD_RETURNDC | PD_RETURNDEFAULT; + if (PrintDlg(&dialog_options) == 0) { + ResetSettings(); + return FAILED; + } + return ParseDialogResult(dialog_options); +} + +PrintingContext::Result PrintingContext::InitWithSettings( + const PrintSettings& settings) { + DCHECK(!in_print_job_); + settings_ = settings; + // TODO(maruel): settings_->ToDEVMODE() + HANDLE printer; + if (!OpenPrinter(const_cast(settings_.device_name().c_str()), + &printer, + NULL)) + return FAILED; + + Result status = OK; + + if (!GetPrinterSettings(printer, settings_.device_name())) + status = FAILED; + + // Close the printer after retrieving the context. + ClosePrinter(printer); + + if (status != OK) + ResetSettings(); + return status; +} + +void PrintingContext::ResetSettings() { + if (hdc_ != NULL) { + DeleteDC(hdc_); + hdc_ = NULL; + } + settings_.Clear(); + in_print_job_ = false; + +#ifndef NDEBUG + page_number_ = -1; +#endif +} + +PrintingContext::Result PrintingContext::NewDocument( + const std::wstring& document_name) { + DCHECK(!in_print_job_); + if (!hdc_) + return OnErrror(); + + // Set the flag used by the AbortPrintJob dialog procedure. + abort_printing_ = false; + + in_print_job_ = true; + + // Register the application's AbortProc function with GDI. + if (SP_ERROR == SetAbortProc(hdc_, &AbortProc)) + return OnErrror(); + + DOCINFO di = { sizeof(DOCINFO) }; + di.lpszDocName = document_name.c_str(); + + DCHECK_EQ(MessageLoop::current()->NestableTasksAllowed(), false); + // Begin a print job by calling the StartDoc function. + // NOTE: StartDoc() starts a message loop. That causes a lot of problems with + // IPC. Make sure recursive task processing is disabled. + if (StartDoc(hdc_, &di) <= 0) + return OnErrror(); + +#ifndef NDEBUG + page_number_ = 0; +#endif + return OK; +} + +PrintingContext::Result PrintingContext::NewPage() { + if (abort_printing_) + return CANCEL; + DCHECK(in_print_job_); + + // Inform the driver that the application is about to begin sending data. + if (StartPage(hdc_) <= 0) + return OnErrror(); + +#ifndef NDEBUG + ++page_number_; +#endif + + return OK; +} + +PrintingContext::Result PrintingContext::PageDone() { + if (abort_printing_) + return CANCEL; + DCHECK(in_print_job_); + + if (EndPage(hdc_) <= 0) + return OnErrror(); + return OK; +} + +PrintingContext::Result PrintingContext::DocumentDone() { + if (abort_printing_) + return CANCEL; + DCHECK(in_print_job_); + + // Inform the driver that document has ended. + if (EndDoc(hdc_) <= 0) + return OnErrror(); + + ResetSettings(); + return OK; +} + +void PrintingContext::Cancel() { + abort_printing_ = true; + in_print_job_ = false; + if (hdc_) + CancelDC(hdc_); + DismissDialog(); +} + +void PrintingContext::DismissDialog() { + if (dialog_box_) { + DestroyWindow(dialog_box_); + dialog_box_dismissed_ = true; + } +} + +PrintingContext::Result PrintingContext::OnErrror() { + // This will close hdc_ and clear settings_. + ResetSettings(); + return abort_printing_ ? CANCEL : FAILED; +} + +// static +BOOL PrintingContext::AbortProc(HDC hdc, int nCode) { + if (nCode) { + // TODO(maruel): Need a way to find the right instance to set. Should + // leverage PrintJobManager here? + // abort_printing_ = true; + } + return true; +} + +bool PrintingContext::InitializeSettings(const DEVMODE& dev_mode, + const std::wstring& new_device_name, + const PRINTPAGERANGE* ranges, + int number_ranges) { + gfx::PlatformDeviceWin::InitializeDC(hdc_); + DCHECK(GetDeviceCaps(hdc_, CLIPCAPS)); + DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_STRETCHDIB); + DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_BITMAP64); + // Some printers don't advertise these. + // DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_SCALING); + // DCHECK(GetDeviceCaps(hdc_, SHADEBLENDCAPS) & SB_CONST_ALPHA); + // DCHECK(GetDeviceCaps(hdc_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA); + + // StretchDIBits() support is needed for printing. + if (!(GetDeviceCaps(hdc_, RASTERCAPS) & RC_STRETCHDIB) || + !(GetDeviceCaps(hdc_, RASTERCAPS) & RC_BITMAP64)) { + NOTREACHED(); + ResetSettings(); + return false; + } + + DCHECK(!in_print_job_); + DCHECK(hdc_); + // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector. + PageRanges ranges_vector; + ranges_vector.reserve(number_ranges); + for (int i = 0; i < number_ranges; ++i) { + PageRange range; + // Transfert from 1-based to 0-based. + range.from = ranges[i].nFromPage - 1; + range.to = ranges[i].nToPage - 1; + ranges_vector.push_back(range); + } + settings_.Init(hdc_, dev_mode, ranges_vector, new_device_name); + PageMargins margins; + margins.header = 500; + margins.footer = 500; + margins.left = 500; + margins.top = 500; + margins.right = 500; + margins.bottom = 500; + settings_.UpdateMarginsMilliInch(margins); + return true; +} + +bool PrintingContext::GetPrinterSettings(HANDLE printer, + const std::wstring& device_name) { + DCHECK(!in_print_job_); + scoped_array buffer; + + // A PRINTER_INFO_9 structure specifying the per-user default printer + // settings. + GetPrinterHelper(printer, 9, &buffer); + if (buffer.get()) { + PRINTER_INFO_9* info_9 = reinterpret_cast(buffer.get()); + if (info_9->pDevMode != NULL) { + if (!AllocateContext(device_name, info_9->pDevMode)) { + ResetSettings(); + return false; + } + return InitializeSettings(*info_9->pDevMode, device_name, NULL, 0); + } + buffer.reset(); + } + + // A PRINTER_INFO_8 structure specifying the global default printer settings. + GetPrinterHelper(printer, 8, &buffer); + if (buffer.get()) { + PRINTER_INFO_8* info_8 = reinterpret_cast(buffer.get()); + if (info_8->pDevMode != NULL) { + if (!AllocateContext(device_name, info_8->pDevMode)) { + ResetSettings(); + return false; + } + return InitializeSettings(*info_8->pDevMode, device_name, NULL, 0); + } + buffer.reset(); + } + + // A PRINTER_INFO_2 structure specifying the driver's default printer + // settings. + GetPrinterHelper(printer, 2, &buffer); + if (buffer.get()) { + PRINTER_INFO_2* info_2 = reinterpret_cast(buffer.get()); + if (info_2->pDevMode != NULL) { + if (!AllocateContext(device_name, info_2->pDevMode)) { + ResetSettings(); + return false; + } + return InitializeSettings(*info_2->pDevMode, device_name, NULL, 0); + } + buffer.reset(); + } + // Failed to retrieve the printer settings. + ResetSettings(); + return false; +} + +bool PrintingContext::AllocateContext(const std::wstring& printer_name, + const DEVMODE* dev_mode) { + hdc_ = CreateDC(L"WINSPOOL", printer_name.c_str(), NULL, dev_mode); + DCHECK(hdc_); + return hdc_ != NULL; +} + +PrintingContext::Result PrintingContext::ParseDialogResultEx( + const PRINTDLGEX& dialog_options) { + // If the user clicked OK or Apply then Cancel, but not only Cancel. + if (dialog_options.dwResultAction != PD_RESULT_CANCEL) { + // Start fresh. + ResetSettings(); + + DEVMODE* dev_mode = NULL; + if (dialog_options.hDevMode) { + dev_mode = + reinterpret_cast(GlobalLock(dialog_options.hDevMode)); + DCHECK(dev_mode); + } + + std::wstring device_name; + if (dialog_options.hDevNames) { + DEVNAMES* dev_names = + reinterpret_cast(GlobalLock(dialog_options.hDevNames)); + DCHECK(dev_names); + if (dev_names) { + device_name = + reinterpret_cast( + reinterpret_cast(dev_names) + + dev_names->wDeviceOffset); + GlobalUnlock(dialog_options.hDevNames); + } + } + + bool success = false; + if (dev_mode && !device_name.empty()) { + hdc_ = dialog_options.hDC; + if (dialog_options.Flags & PD_PAGENUMS) { + success = InitializeSettings(*dev_mode, + device_name, + dialog_options.lpPageRanges, + dialog_options.nPageRanges); + } else { + success = InitializeSettings(*dev_mode, device_name, NULL, 0); + } + } + + if (!success && dialog_options.hDC) { + DeleteDC(dialog_options.hDC); + hdc_ = NULL; + } + + if (dev_mode) { + GlobalUnlock(dialog_options.hDevMode); + } + } else { + if (dialog_options.hDC) { + DeleteDC(dialog_options.hDC); + } + } + + if (dialog_options.hDevMode != NULL) + GlobalFree(dialog_options.hDevMode); + if (dialog_options.hDevNames != NULL) + GlobalFree(dialog_options.hDevNames); + + switch (dialog_options.dwResultAction) { + case PD_RESULT_PRINT: + return hdc_ ? OK : FAILED; + case PD_RESULT_APPLY: + return hdc_ ? CANCEL : FAILED; + case PD_RESULT_CANCEL: + return CANCEL; + default: + return FAILED; + } +} + +PrintingContext::Result PrintingContext::ParseDialogResult( + const PRINTDLG& dialog_options) { + // If the user clicked OK or Apply then Cancel, but not only Cancel. + // Start fresh. + ResetSettings(); + + DEVMODE* dev_mode = NULL; + if (dialog_options.hDevMode) { + dev_mode = + reinterpret_cast(GlobalLock(dialog_options.hDevMode)); + DCHECK(dev_mode); + } + + std::wstring device_name; + if (dialog_options.hDevNames) { + DEVNAMES* dev_names = + reinterpret_cast(GlobalLock(dialog_options.hDevNames)); + DCHECK(dev_names); + if (dev_names) { + device_name = + reinterpret_cast( + reinterpret_cast(dev_names) + + dev_names->wDeviceOffset); + GlobalUnlock(dialog_options.hDevNames); + } + } + + bool success = false; + if (dev_mode && !device_name.empty()) { + hdc_ = dialog_options.hDC; + success = InitializeSettings(*dev_mode, device_name, NULL, 0); + } + + if (!success && dialog_options.hDC) { + DeleteDC(dialog_options.hDC); + hdc_ = NULL; + } + + if (dev_mode) { + GlobalUnlock(dialog_options.hDevMode); + } + + if (dialog_options.hDevMode != NULL) + GlobalFree(dialog_options.hDevMode); + if (dialog_options.hDevNames != NULL) + GlobalFree(dialog_options.hDevNames); + + return hdc_ ? OK : FAILED; +} + +} // namespace printing + diff --git a/libcef/printing/win_printing_context.h b/libcef/printing/win_printing_context.h new file mode 100644 index 000000000..48a07628f --- /dev/null +++ b/libcef/printing/win_printing_context.h @@ -0,0 +1,139 @@ +// Copyright (c) 2006-2008 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 _PRINTING_WIN_PRINTING_CONTEXT_H +#define _PRINTING_WIN_PRINTING_CONTEXT_H + +#include "print_settings.h" + +#include +#include +#include + +#include "base/basictypes.h" + +namespace printing { + +// Describe the user selected printing context for Windows. This includes the +// OS-dependent UI to ask the user about the print settings. This class directly +// talk to the printer and manages the document and pages breaks. +class PrintingContext { + public: + // Tri-state result for user behavior-dependent functions. + enum Result { + OK, + CANCEL, + FAILED, + }; + + PrintingContext(); + ~PrintingContext(); + + // Asks the user what printer and format should be used to print. Updates the + // context with the select device settings. + Result AskUserForSettings(HWND window, int max_pages); + + // Selects the user's default printer and format. Updates the context with the + // default device settings. + Result UseDefaultSettings(); + + // Initializes with predefined settings. + Result InitWithSettings(const PrintSettings& settings); + + // Reinitializes the settings to uninitialized for object reuse. + void ResetSettings(); + + // Does platform specific setup of the printer before the printing. Signal the + // printer that a document is about to be spooled. + // Warning: This function enters a message loop. That may cause side effects + // like IPC message processing! Some printers have side-effects on this call + // like virtual printers that ask the user for the path of the saved document; + // for example a PDF printer. + Result NewDocument(const std::wstring& document_name); + + // Starts a new page. + Result NewPage(); + + // Closes the printed page. + Result PageDone(); + + // Closes the printing job. After this call the object is ready to start a new + // document. + Result DocumentDone(); + + // Cancels printing. Can be used in a multithreaded context. Takes effect + // immediately. + void Cancel(); + + // Dismiss the Print... dialog box if shown. + void DismissDialog(); + + HDC context() { + return hdc_; + } + + const PrintSettings& settings() const { + return settings_; + } + + private: + // Class that manages the PrintDlgEx() callbacks. This is meant to be a + // temporary object used during the Print... dialog display. + class CallbackHandler; + + // Does bookeeping when an error occurs. + PrintingContext::Result OnErrror(); + + // Used in response to the user cancelling the printing. + static BOOL CALLBACK AbortProc(HDC hdc, int nCode); + + // Reads the settings from the selected device context. Updates settings_ and + // its margins. + bool InitializeSettings(const DEVMODE& dev_mode, + const std::wstring& new_device_name, + const PRINTPAGERANGE* ranges, + int number_ranges); + + // Retrieves the printer's default low-level settings. hdc_ is allocated with + // this call. + bool GetPrinterSettings(HANDLE printer, + const std::wstring& device_name); + + // Allocates the HDC for a specific DEVMODE. + bool AllocateContext(const std::wstring& printer_name, + const DEVMODE* dev_mode); + + // Parses the result of a PRINTDLGEX result. + Result ParseDialogResultEx(const PRINTDLGEX& dialog_options); + Result ParseDialogResult(const PRINTDLG& dialog_options); + + // The selected printer context. + HDC hdc_; + + // Complete print context settings. + PrintSettings settings_; + +#ifndef NDEBUG + // Current page number in the print job. + int page_number_; +#endif + + // The dialog box for the time it is shown. + volatile HWND dialog_box_; + + // The dialog box has been dismissed. + volatile bool dialog_box_dismissed_; + + // Is a print job being done. + volatile bool in_print_job_; + + // Did the user cancel the print job. + volatile bool abort_printing_; + + DISALLOW_EVIL_CONSTRUCTORS(PrintingContext); +}; + +} // namespace printing + +#endif // _PRINTING_WIN_PRINTING_CONTEXT_H diff --git a/libcef/request_impl.cc b/libcef/request_impl.cc new file mode 100644 index 000000000..80f641423 --- /dev/null +++ b/libcef/request_impl.cc @@ -0,0 +1,398 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 "precompiled_libcef.h" +#include "request_impl.h" + +#include "base/logging.h" +#include "base/string_util.h" +#include "webkit/glue/glue_util.h" + + +CefRefPtr CefRequest::CreateRequest() +{ + CefRefPtr request(new CefRequestImpl()); + return request; +} + +CefRequestImpl::CefRequestImpl() +{ +} + +CefRequestImpl::~CefRequestImpl() +{ +} + +std::wstring CefRequestImpl::GetURL() +{ + Lock(); + std::wstring url = url_; + Unlock(); + return url; +} + +void CefRequestImpl::SetURL(const std::wstring& url) +{ + Lock(); + url_ = url; + Unlock(); +} + +std::wstring CefRequestImpl::GetFrame() +{ + Lock(); + std::wstring frame = frame_; + Unlock(); + return frame; +} + +void CefRequestImpl::SetFrame(const std::wstring& url) +{ + Lock(); + frame_ = url; + Unlock(); +} + +std::wstring CefRequestImpl::GetMethod() +{ + Lock(); + std::wstring method = method_; + Unlock(); + return method; +} + +void CefRequestImpl::SetMethod(const std::wstring& method) +{ + Lock(); + method_ = method; + Unlock(); +} + +CefRefPtr CefRequestImpl::GetPostData() +{ + Lock(); + CefRefPtr postData = postdata_; + Unlock(); + return postData; +} + +void CefRequestImpl::SetPostData(CefRefPtr postData) +{ + Lock(); + postdata_ = postData; + Unlock(); +} + +void CefRequestImpl::GetHeaderMap(HeaderMap& headerMap) +{ + Lock(); + headerMap = headermap_; + Unlock(); +} + +void CefRequestImpl::SetHeaderMap(const HeaderMap& headerMap) +{ + Lock(); + headermap_ = headerMap; + Unlock(); +} + +void CefRequestImpl::Set(const std::wstring& url, + const std::wstring& frame, + const std::wstring& method, + CefRefPtr postData, + const HeaderMap& headerMap) +{ + Lock(); + url_ = url; + frame_ = frame; + method_ = method; + postdata_ = postData; + headermap_ = headerMap; + Unlock(); +} + +void CefRequestImpl::SetHeaderMap(const WebRequest::HeaderMap& map) +{ + Lock(); + WebRequest::HeaderMap::const_iterator it = map.begin(); + for(; it != map.end(); ++it) { + headermap_.insert( + std::make_pair( + UTF8ToWide(it->first.c_str()), + UTF8ToWide(it->second.c_str()))); + } + Unlock(); +} + +void CefRequestImpl::GetHeaderMap(WebRequest::HeaderMap& map) +{ + Lock(); + HeaderMap::const_iterator it = headermap_.begin(); + for(; it != headermap_.end(); ++it) { + map.insert( + std::make_pair( + WideToUTF8(it->first.c_str()), + WideToUTF8(it->second.c_str()))); + } + Unlock(); +} + + +CefRefPtr CefPostData::CreatePostData() +{ + CefRefPtr postdata(new CefPostDataImpl()); + return postdata; +} + +CefPostDataImpl::CefPostDataImpl() +{ +} + +CefPostDataImpl::~CefPostDataImpl() +{ + RemoveElements(); +} + +size_t CefPostDataImpl::GetElementCount() +{ + Lock(); + size_t ct = elements_.size(); + Unlock(); + return ct; +} + +void CefPostDataImpl::GetElements(ElementVector& elements) +{ + Lock(); + elements = elements_; + Unlock(); +} + +bool CefPostDataImpl::RemoveElement(CefRefPtr element) +{ + bool deleted = false; + + Lock(); + + ElementVector::iterator it = elements_.begin(); + for(; it != elements_.end(); ++it) { + if(it->get() == element.get()) { + elements_.erase(it); + deleted = true; + break; + } + } + + Unlock(); + + return deleted; +} + +bool CefPostDataImpl::AddElement(CefRefPtr element) +{ + bool found = false; + + Lock(); + + // check that the element isn't already in the list before adding + ElementVector::const_iterator it = elements_.begin(); + for(; it != elements_.end(); ++it) { + if(it->get() == element.get()) { + found = true; + break; + } + } + + if(!found) + elements_.push_back(element); + + Unlock(); + return !found; +} + +void CefPostDataImpl::RemoveElements() +{ + Lock(); + elements_.clear(); + Unlock(); +} + +void CefPostDataImpl::Set(const net::UploadData& data) +{ + Lock(); + + CefRefPtr postelem; + const std::vector& elements = data.elements(); + std::vector::const_iterator it = elements.begin(); + for (; it != elements.end(); ++it) { + postelem = CefPostDataElement::CreatePostDataElement(); + static_cast(postelem.get())->Set(*it); + AddElement(postelem); + } + + Unlock(); +} + +void CefPostDataImpl::Get(net::UploadData& data) +{ + Lock(); + + net::UploadData::Element* element; + ElementVector::iterator it = elements_.begin(); + for(; it != elements_.end(); ++it) { + element = new net::UploadData::Element(); + static_cast(it->get())->Set(*element); + } + + Unlock(); +} + + +CefRefPtr CefPostDataElement::CreatePostDataElement() +{ + CefRefPtr element(new CefPostDataElementImpl()); + return element; +} + +CefPostDataElementImpl::CefPostDataElementImpl() +{ + type_ = TYPE_EMPTY; +} + +CefPostDataElementImpl::~CefPostDataElementImpl() +{ + SetToEmpty(); +} + +void CefPostDataElementImpl::SetToEmpty() +{ + Lock(); + if(type_ == TYPE_BYTES) + free(data_.bytes.bytes); + else if(type_ == TYPE_FILE) + free(data_.filename); + type_ = TYPE_EMPTY; + Unlock(); +} + +void CefPostDataElementImpl::SetToFile(const std::wstring& fileName) +{ + Lock(); + // Clear any data currently in the element + SetToEmpty(); + + // Assign the new file name + size_t size = fileName.size(); + wchar_t* data = static_cast(malloc((size + 1) * sizeof(wchar_t))); + DCHECK(data != NULL); + if(data == NULL) + return; + + memcpy(static_cast(data), static_cast(fileName.c_str()), + size * sizeof(wchar_t)); + data[size] = 0; + + // Assign the new data + type_ = TYPE_FILE; + data_.filename = data; + Unlock(); +} + +void CefPostDataElementImpl::SetToBytes(size_t size, const void* bytes) +{ + Lock(); + // Clear any data currently in the element + SetToEmpty(); + + // Assign the new data + void* data = malloc(size); + DCHECK(data != NULL); + if(data == NULL) + return; + + memcpy(data, bytes, size); + + type_ = TYPE_BYTES; + data_.bytes.bytes = data; + data_.bytes.size = size; + Unlock(); +} + +CefPostDataElement::Type CefPostDataElementImpl::GetType() +{ + Lock(); + CefPostDataElement::Type type = type_; + Unlock(); + return type; +} + +std::wstring CefPostDataElementImpl::GetFile() +{ + Lock(); + DCHECK(type_ == TYPE_FILE); + std::wstring filename; + if(type_ == TYPE_FILE) + filename = data_.filename; + Unlock(); + return filename; +} + +size_t CefPostDataElementImpl::GetBytesCount() +{ + Lock(); + DCHECK(type_ == TYPE_BYTES); + size_t size = 0; + if(type_ == TYPE_BYTES) + size = data_.bytes.size; + Unlock(); + return size; +} + +size_t CefPostDataElementImpl::GetBytes(size_t size, void *bytes) +{ + Lock(); + DCHECK(type_ == TYPE_BYTES); + size_t rv = 0; + if(type_ == TYPE_BYTES) { + rv = (size < data_.bytes.size ? size : data_.bytes.size); + memcpy(bytes, data_.bytes.bytes, rv); + } + Unlock(); + return rv; +} + +void CefPostDataElementImpl::Set(const net::UploadData::Element& element) +{ + Lock(); + + if (element.type() == net::UploadData::TYPE_BYTES) { + SetToBytes(element.bytes().size(), + static_cast( + std::string(element.bytes().begin(), + element.bytes().end()).c_str())); + } else if (element.type() == net::UploadData::TYPE_FILE) { + SetToFile(element.file_path()); + } else { + NOTREACHED(); + } + + Unlock(); +} + +void CefPostDataElementImpl::Get(net::UploadData::Element& element) +{ + Lock(); + + if(type_ == TYPE_BYTES) { + element.SetToBytes(static_cast(data_.bytes.bytes), data_.bytes.size); + } else if(type_ == TYPE_FILE) { + element.SetToFilePath(data_.filename); + } else { + NOTREACHED(); + } + + Unlock(); +} + diff --git a/libcef/request_impl.h b/libcef/request_impl.h new file mode 100644 index 000000000..6b648ac8d --- /dev/null +++ b/libcef/request_impl.h @@ -0,0 +1,96 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 _REQUEST_IMPL_H +#define _REQUEST_IMPL_H + +#include "../include/cef.h" +#include "net/base/upload_data.h" +#include "webkit/glue/weburlrequest.h" + + +// Implementation of CefRequest +class CefRequestImpl : public CefThreadSafeBase +{ +public: + CefRequestImpl(); + ~CefRequestImpl(); + + virtual std::wstring GetURL(); + virtual void SetURL(const std::wstring& url); + virtual std::wstring GetFrame(); + virtual void SetFrame(const std::wstring& url); + virtual std::wstring GetMethod(); + virtual void SetMethod(const std::wstring& method); + virtual CefRefPtr GetPostData(); + virtual void SetPostData(CefRefPtr postData); + virtual void GetHeaderMap(HeaderMap& headerMap); + virtual void SetHeaderMap(const HeaderMap& headerMap); + virtual void Set(const std::wstring& url, + const std::wstring& frame, + const std::wstring& method, + CefRefPtr postData, + const HeaderMap& headerMap); + + void SetHeaderMap(const WebRequest::HeaderMap& map); + void GetHeaderMap(WebRequest::HeaderMap& map); + +protected: + std::wstring url_; + std::wstring frame_; + std::wstring method_; + CefRefPtr postdata_; + HeaderMap headermap_; +}; + +// Implementation of CefPostData +class CefPostDataImpl : public CefThreadSafeBase +{ +public: + CefPostDataImpl(); + ~CefPostDataImpl(); + + virtual size_t GetElementCount(); + virtual void GetElements(ElementVector& elements); + virtual bool RemoveElement(CefRefPtr element); + virtual bool AddElement(CefRefPtr element); + virtual void RemoveElements(); + + void Set(const net::UploadData& data); + void Get(net::UploadData& data); + +protected: + ElementVector elements_; +}; + +// Implementation of CefPostDataElement +class CefPostDataElementImpl : public CefThreadSafeBase +{ +public: + CefPostDataElementImpl(); + ~CefPostDataElementImpl(); + + virtual void SetToEmpty(); + virtual void SetToFile(const std::wstring& fileName); + virtual void SetToBytes(size_t size, const void* bytes); + virtual Type GetType(); + virtual std::wstring GetFile(); + virtual size_t GetBytesCount(); + virtual size_t GetBytes(size_t size, void *bytes); + + void Set(const net::UploadData::Element& element); + void Get(net::UploadData::Element& element); + +protected: + Type type_; + union { + struct { + void* bytes; + size_t size; + } bytes; + wchar_t* filename; + } data_; +}; + +#endif // _REQUEST_IMPL_H diff --git a/libcef/stream_impl.cc b/libcef/stream_impl.cc new file mode 100644 index 000000000..fadae6a86 --- /dev/null +++ b/libcef/stream_impl.cc @@ -0,0 +1,323 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 "precompiled_libcef.h" +#include "stream_impl.h" + +#include "base/logging.h" + + +// Static functions + +CefRefPtr CefStreamReader::CreateForFile(const std::wstring& fileName) +{ + CefRefPtr reader; + FILE *f = _wfopen(fileName.c_str(), L"rb"); + if(f) + reader = new CefFileReader(f, true); + return reader; +} + +CefRefPtr CefStreamReader::CreateForData(void *data, size_t size) +{ + DCHECK(data != NULL); + DCHECK(size > 0); + CefRefPtr reader; + if(data && size > 0) + reader = new CefBytesReader(data, size, true); + return reader; +} + + +// CefFileReader + +CefFileReader::CefFileReader(FILE* file, bool close) + : file_(file), close_(close) +{ +} + +CefFileReader::~CefFileReader() +{ + Lock(); + if(close_) + fclose(file_); + Unlock(); +} + +size_t CefFileReader::Read(void *ptr, size_t size, size_t n) +{ + Lock(); + size_t rv = fread(ptr, size, n, file_); + Unlock(); + return rv; +} + +int CefFileReader::Seek(long offset, int whence) +{ + Lock(); + int rv = fseek(file_, offset, whence); + Unlock(); + return rv; +} + +long CefFileReader::Tell() +{ + Lock(); + long rv = ftell(file_); + Unlock(); + return rv; +} + +int CefFileReader::Eof() +{ + Lock(); + int rv = feof(file_); + Unlock(); + return rv; +} + + +// CefFileWriter + +CefFileWriter::CefFileWriter(FILE* file, bool close) + : file_(file), close_(close) +{ +} + +CefFileWriter::~CefFileWriter() +{ + Lock(); + if(close_) + fclose(file_); + Unlock(); +} + +size_t CefFileWriter::Write(const void *ptr, size_t size, size_t n) +{ + Lock(); + size_t rv = (size_t)fwrite(ptr, size, n, file_); + Unlock(); + return rv; +} + +int CefFileWriter::Seek(long offset, int whence) +{ + Lock(); + int rv = fseek(file_, offset, whence); + Unlock(); + return rv; +} + +long CefFileWriter::Tell() +{ + Lock(); + long rv = ftell(file_); + Unlock(); + return rv; +} + +int CefFileWriter::Flush() +{ + Lock(); + int rv = fflush(file_); + Unlock(); + return rv; +} + + +// CefBytesReader + +CefBytesReader::CefBytesReader(void *data, long datasize, bool copy) + : data_(NULL), datasize_(0), copy_(false), offset_(0) +{ + SetData(data, datasize, copy); +} + +CefBytesReader::~CefBytesReader() +{ + SetData(NULL, 0, false); +} + +size_t CefBytesReader::Read(void *ptr, size_t size, size_t n) +{ + Lock(); + size_t s = (datasize_ - offset_) / size; + size_t ret = (n < s ? n : s); + memcpy(ptr, ((char*)data_) + offset_, ret * size); + offset_ += ret * size; + Unlock(); + return ret; +} + +int CefBytesReader::Seek(long offset, int whence) +{ + int rv = -1L; + Lock(); + switch(whence) { + case SEEK_CUR: + if(offset_ + offset > datasize_) { + break; + } + offset_ += offset; + rv = offset_; + break; + case SEEK_END: + if(offset > (int)datasize_) { + break; + } + offset_ = datasize_ - offset; + rv = offset_; + case SEEK_SET: + if(offset > (int)datasize_) { + break; + } + offset_ = offset; + rv = offset_; + break; + } + Unlock(); + + return rv; +} + +long CefBytesReader::Tell() +{ + Lock(); + long rv = offset_; + Unlock(); + return rv; +} + +int CefBytesReader::Eof() +{ + Lock(); + int rv = (offset_ >= datasize_); + Unlock(); + return rv; +} + +void CefBytesReader::SetData(void *data, long datasize, bool copy) +{ + Lock(); + if(copy_) + free(data_); + + copy_ = copy; + offset_ = 0; + datasize_ = datasize; + + if(copy) { + data_ = malloc(datasize); + DCHECK(data_ != NULL); + if(data_) + memcpy(data_, data, datasize); + } else { + data_ = data; + } + Unlock(); +} + + +// CefBytesWriter + +CefBytesWriter::CefBytesWriter(size_t grow) + : grow_(grow), offset_(0), datasize_(grow) +{ + DCHECK(grow > 0); + data_ = malloc(grow); + DCHECK(data_ != NULL); +} + +CefBytesWriter::~CefBytesWriter() +{ + Lock(); + if(data_) + free(data_); + Unlock(); +} + +size_t CefBytesWriter::Write(const void *ptr, size_t size, size_t n) +{ + Lock(); + size_t rv; + if(offset_ + size * n >= datasize_ && Grow(size * n) == 0) { + rv = 0; + } else { + memcpy(((char*)data_) + offset_, ptr, size * n); + offset_ += size * n; + rv = n; + } + Unlock(); + return rv; +} + +int CefBytesWriter::Seek(long offset, int whence) +{ + int rv = -1L; + Lock(); + switch(whence) { + case SEEK_CUR: + if(offset_ + offset > datasize_) { + break; + } + offset_ += offset; + rv = offset_; + break; + case SEEK_END: + if(offset > (int)datasize_) { + break; + } + offset_ = datasize_ - offset; + rv = offset_; + case SEEK_SET: + if(offset > (int)datasize_) { + break; + } + offset_ = offset; + rv = offset_; + break; + } + Unlock(); + + return rv; +} + +long CefBytesWriter::Tell() +{ + Lock(); + long rv = offset_; + Unlock(); + return rv; +} + +int CefBytesWriter::Flush() +{ + return 0; +} + +std::string CefBytesWriter::GetDataString() +{ + Lock(); + std::string str((char*)data_, datasize_); + Unlock(); + return str; +} + +size_t CefBytesWriter::Grow(size_t size) +{ + Lock(); + size_t rv; + size_t s = (size > grow_ ? size : grow_); + void *tmp = realloc(data_, datasize_ + s); + DCHECK(tmp != NULL); + if(tmp) { + data_ = tmp; + datasize_ += s; + rv = datasize_; + } else { + rv = 0; + } + Unlock(); + return rv; +} diff --git a/libcef/stream_impl.h b/libcef/stream_impl.h new file mode 100644 index 000000000..9e939a495 --- /dev/null +++ b/libcef/stream_impl.h @@ -0,0 +1,95 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 _STREAM_IMPL_H +#define _STREAM_IMPL_H + +#include "../include/cef.h" +#include + +// Implementation of CefStreamReader for files. +class CefFileReader : public CefThreadSafeBase +{ +public: + CefFileReader(FILE* file, bool close); + ~CefFileReader(); + + virtual size_t Read(void *ptr, size_t size, size_t n); + virtual int Seek(long offset, int whence); + virtual long Tell(); + virtual int Eof(); + +protected: + bool close_; + FILE *file_; +}; + +// Implementation of CefStreamWriter for files. +class CefFileWriter : public CefThreadSafeBase +{ +public: + CefFileWriter(FILE* file, bool close); + ~CefFileWriter(); + + virtual size_t Write(const void *ptr, size_t size, size_t n); + virtual int Seek(long offset, int whence); + virtual long Tell(); + virtual int Flush(); + +protected: + FILE *file_; + bool close_; +}; + +// Implementation of CefStreamReader for byte buffers. +class CefBytesReader : public CefThreadSafeBase +{ +public: + CefBytesReader(void *data, long datasize, bool copy); + ~CefBytesReader(); + + virtual size_t Read(void *ptr, size_t size, size_t n); + virtual int Seek(long offset, int whence); + virtual long Tell(); + virtual int Eof(); + + void SetData(void *data, long datasize, bool copy); + + void *GetData() { return data_; } + size_t GetDataSize() { return offset_; } + +protected: + void *data_; + size_t datasize_; + bool copy_; + size_t offset_; +}; + +// Implementation of CefStreamWriter for byte buffers. +class CefBytesWriter : public CefThreadSafeBase +{ +public: + CefBytesWriter(size_t grow); + ~CefBytesWriter(); + + virtual size_t Write(const void *ptr, size_t size, size_t n); + virtual int Seek(long offset, int whence); + virtual long Tell(); + virtual int Flush(); + + void *GetData() { return data_; } + size_t GetDataSize() { return offset_; } + std::string GetDataString(); + +protected: + size_t Grow(size_t size); + +protected: + size_t grow_; + void *data_; + size_t datasize_; + size_t offset_; +}; + +#endif // _STREAM_IMPL_H diff --git a/libcef/variant_impl.cc b/libcef/variant_impl.cc new file mode 100644 index 000000000..2a7dc973f --- /dev/null +++ b/libcef/variant_impl.cc @@ -0,0 +1,361 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "variant_impl.h" +#include "variant_np_util.h" + +#include "base/compiler_specific.h" + +#include "config.h" +MSVC_PUSH_WARNING_LEVEL(0); +#include "DOMWindow.h" +#include "Frame.h" +#include "npruntime_priv.h" // for NPN_InitializeVariantWithStringCopy +MSVC_POP_WARNING(); + +#undef LOG +#include "base/logging.h" +#include "base/string_util.h" +#include "webkit/glue/webframe.h" + + +CefVariantImpl::CefVariantImpl() +{ + variant_.type = NPVariantType_Null; + webframe_ = NULL; +} + +CefVariantImpl::CefVariantImpl(WebFrame *webframe) +{ + variant_.type = NPVariantType_Null; + webframe_ = webframe; +} + +// Note that Set() performs a deep copy, which is necessary to safely +// call SetNull() on the value in the destructor. +CefVariantImpl::CefVariantImpl(const CefVariantImpl& original) +{ + Lock(); + variant_.type = NPVariantType_Null; + Set(*original.GetNPVariant()); + Unlock(); +} + +// See comment for copy constructor, above. +CefVariantImpl& CefVariantImpl::operator=(const CefVariantImpl& original) +{ + if (&original != this) { + Lock(); + Set(*original.GetNPVariant()); + Unlock(); + } + return *this; +} + +CefVariantImpl::~CefVariantImpl() +{ + SetNull(); +} + +CefVariant::Type CefVariantImpl::GetType() +{ + CefVariant::Type type = TYPE_NULL; + + Lock(); + + // determine the data type of the underlying NPVariant value + switch (variant_.type) { + case NPVariantType_Bool: + type = TYPE_BOOL; + break; + case NPVariantType_Int32: + type = TYPE_INT; + break; + case NPVariantType_Double: + type = TYPE_DOUBLE; + break; + case NPVariantType_String: + type = TYPE_STRING; + break; + case NPVariantType_Object: + { + // determine the most appropriate array type for the NPVariant object + NPVariantType nptype; + if(_NPN_ArrayObjectToVectorTypeHint(variant_.value.objectValue, nptype)) { + switch(nptype) { + case NPVariantType_Bool: + type = TYPE_BOOL_ARRAY; + break; + case NPVariantType_Int32: + type = TYPE_INT_ARRAY; + break; + case NPVariantType_Double: + type = TYPE_DOUBLE_ARRAY; + break; + case NPVariantType_String: + type = TYPE_STRING_ARRAY; + break; + } + } + } + break; + } + + Unlock(); + + return type; +} + +void CefVariantImpl::SetNull() +{ + Lock(); + NPN_ReleaseVariantValue(&variant_); + variant_.type = NPVariantType_Null; + Unlock(); +} + +void CefVariantImpl::SetBool(bool val) +{ + Lock(); + if(variant_.type != NPVariantType_Bool) { + SetNull(); + variant_.type = NPVariantType_Bool; + } + variant_.value.boolValue = val; + Unlock(); +} + +void CefVariantImpl::SetInt(int val) +{ + Lock(); + if(variant_.type != NPVariantType_Int32) { + SetNull(); + variant_.type = NPVariantType_Int32; + } + variant_.value.intValue = val; + Unlock(); +} + +void CefVariantImpl::SetDouble(double val) +{ + Lock(); + if(variant_.type != NPVariantType_Double) { + SetNull(); + variant_.type = NPVariantType_Double; + } + variant_.value.doubleValue = val; + Unlock(); +} + +void CefVariantImpl::SetString(const std::wstring& val) +{ + Lock(); + SetNull(); + variant_.type = NPVariantType_String; + std::string str = WideToUTF8(val); + NPString new_string = {str.c_str(), + static_cast(str.size())}; + _NPN_InitializeVariantWithStringCopy(&variant_, &new_string); + Unlock(); +} + +void CefVariantImpl::SetBoolArray(const std::vector& val) +{ + Lock(); + DCHECK(webframe_ != NULL); + WebCore::Frame* frame = + static_cast(webframe_->GetFrameImplementation()); + WebCore::DOMWindow* domwindow = frame->domWindow(); + NPObject* npobject = _NPN_BooleanVectorToArrayObject(domwindow, val); + DCHECK(npobject != NULL); + Set(npobject); + Unlock(); +} + +void CefVariantImpl::SetIntArray(const std::vector& val) +{ + Lock(); + DCHECK(webframe_ != NULL); + WebCore::Frame* frame = + static_cast(webframe_->GetFrameImplementation()); + WebCore::DOMWindow* domwindow = frame->domWindow(); + NPObject* npobject = _NPN_IntVectorToArrayObject(domwindow, val); + DCHECK(npobject != NULL); + Set(npobject); + Unlock(); +} + +void CefVariantImpl::SetDoubleArray(const std::vector& val) +{ + Lock(); + DCHECK(webframe_ != NULL); + WebCore::Frame* frame = + static_cast(webframe_->GetFrameImplementation()); + WebCore::DOMWindow* domwindow = frame->domWindow(); + NPObject* npobject = _NPN_DoubleVectorToArrayObject(domwindow, val); + DCHECK(npobject != NULL); + Set(npobject); + Unlock(); +} + +void CefVariantImpl::SetStringArray(const std::vector& val) +{ + Lock(); + DCHECK(webframe_ != NULL); + WebCore::Frame* frame = + static_cast(webframe_->GetFrameImplementation()); + WebCore::DOMWindow* domwindow = frame->domWindow(); + NPObject* npobject = _NPN_WStringVectorToArrayObject(domwindow, val); + DCHECK(npobject != NULL); + Set(npobject); + Unlock(); +} + +bool CefVariantImpl::GetBool() +{ + Lock(); + DCHECK(variant_.type == NPVariantType_Bool); + bool rv = variant_.value.boolValue; + Unlock(); + return rv; +} + +int CefVariantImpl::GetInt() +{ + Lock(); + DCHECK(variant_.type == NPVariantType_Int32); + int rv = variant_.value.intValue; + Unlock(); + return rv; +} + +double CefVariantImpl::GetDouble() +{ + Lock(); + DCHECK(variant_.type == NPVariantType_Double); + double rv = variant_.value.doubleValue; + Unlock(); + return rv; +} + +std::wstring CefVariantImpl::GetString() +{ + Lock(); + DCHECK(variant_.type == NPVariantType_String); + std::wstring rv = UTF8ToWide( + std::string( + variant_.value.stringValue.UTF8Characters, + variant_.value.stringValue.UTF8Length)); + Unlock(); + return rv; +} + +bool CefVariantImpl::GetBoolArray(std::vector& val) +{ + Lock(); + DCHECK(variant_.type == NPVariantType_Object); + bool rv = _NPN_ArrayObjectToBooleanVector(variant_.value.objectValue, val); + Unlock(); + return rv; +} + +bool CefVariantImpl::GetIntArray(std::vector& val) +{ + Lock(); + DCHECK(variant_.type == NPVariantType_Object); + bool rv = _NPN_ArrayObjectToIntVector(variant_.value.objectValue, val); + Unlock(); + return rv; +} + +bool CefVariantImpl::GetDoubleArray(std::vector& val) +{ + Lock(); + DCHECK(variant_.type == NPVariantType_Object); + bool rv = _NPN_ArrayObjectToDoubleVector(variant_.value.objectValue, val); + Unlock(); + return rv; +} + +bool CefVariantImpl::GetStringArray(std::vector& val) +{ + Lock(); + DCHECK(variant_.type == NPVariantType_Object); + bool rv = _NPN_ArrayObjectToWStringVector(variant_.value.objectValue, val); + Unlock(); + return rv; +} + +void CefVariantImpl::CopyToNPVariant(NPVariant* result) +{ + Lock(); + result->type = variant_.type; + switch (variant_.type) { + case NPVariantType_Bool: + result->value.boolValue = variant_.value.boolValue; + break; + case NPVariantType_Int32: + result->value.intValue = variant_.value.intValue; + break; + case NPVariantType_Double: + result->value.doubleValue = variant_.value.doubleValue; + break; + case NPVariantType_String: + _NPN_InitializeVariantWithStringCopy(result, &variant_.value.stringValue); + break; + case NPVariantType_Null: + case NPVariantType_Void: + // Nothing to set. + break; + case NPVariantType_Object: + result->type = NPVariantType_Object; + result->value.objectValue = NPN_RetainObject(variant_.value.objectValue); + break; + } + Unlock(); +} + +void CefVariantImpl::Set(NPObject* val) +{ + Lock(); + SetNull(); + variant_.type = NPVariantType_Object; + variant_.value.objectValue = NPN_RetainObject(val); + Unlock(); +} + +void CefVariantImpl::Set(const NPString& val) +{ + Lock(); + SetNull(); + variant_.type = NPVariantType_String; + _NPN_InitializeVariantWithStringCopy(&variant_, &val); + Unlock(); +} + +void CefVariantImpl::Set(const NPVariant& val) +{ + Lock(); + SetNull(); + switch (val.type) { + case NPVariantType_Bool: + SetBool(val.value.boolValue); + break; + case NPVariantType_Int32: + SetInt(val.value.intValue); + break; + case NPVariantType_Double: + SetDouble(val.value.doubleValue); + break; + case NPVariantType_String: + Set(val.value.stringValue); + break; + case NPVariantType_Object: + Set(val.value.objectValue); + break; + } + Unlock(); +} \ No newline at end of file diff --git a/libcef/variant_impl.h b/libcef/variant_impl.h new file mode 100644 index 000000000..a1bd8a41f --- /dev/null +++ b/libcef/variant_impl.h @@ -0,0 +1,76 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2006-2008 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 _VARIANT_IMPL_H +#define _VARIANT_IMPL_H + +#include "../include/cef.h" +#include "third_party/npapi/bindings/npruntime.h" + +class WebFrame; + +// Implementation of CefPostDataElement that provides a class wrapper for an +// NPVariant structure. +// Portions of the implementation are borrowed from webkit\glue\cpp_variant.cc +class CefVariantImpl : public CefThreadSafeBase +{ +public: + CefVariantImpl(); + CefVariantImpl(WebFrame *webframe); + ~CefVariantImpl(); + + virtual Type GetType(); + virtual void SetNull(); + virtual void SetBool(bool val); + virtual void SetInt(int val); + virtual void SetDouble(double val); + virtual void SetString(const std::wstring& val); + virtual void SetBoolArray(const std::vector& val); + virtual void SetIntArray(const std::vector& val); + virtual void SetDoubleArray(const std::vector& val); + virtual void SetStringArray(const std::vector& val); + virtual bool GetBool(); + virtual int GetInt(); + virtual double GetDouble(); + virtual std::wstring GetString(); + virtual bool GetBoolArray(std::vector& val); + virtual bool GetIntArray(std::vector& val); + virtual bool GetDoubleArray(std::vector& val); + virtual bool GetStringArray(std::vector& val); + + // These three methods all perform deep copies of any string data. This + // allows the local CefVariantImpl to be released by the destructor without + // corrupting their sources. In performance-critical code, or when strings + // are very long, avoid creating new CefVariantImpl. + // In case of NPObject as the data, the copying involves ref-counting + // as opposed to deep-copying. The ref-counting ensures that sources don't + // get corrupted when the copies get destroyed. + void CopyToNPVariant(NPVariant* result); + CefVariantImpl& operator=(const CefVariantImpl& original); + CefVariantImpl(const CefVariantImpl& original); + + // Note that setting a CefVariant to an NPObject involves ref-counting + // the actual object. SetNull() should only be called if the CefVariant + // is no longer needed. The other Set() methods handle this internally. + // Also, the object's NPClass is expected to be a static object: neither + // the NP runtime nor CefVariant will ever free it. + void Set(NPObject* val); + + void Set(const NPString& val); + void Set(const NPVariant& val); + + const NPVariant* GetNPVariant() const { return &variant_; } + +protected: + // Underlying NPVariant structure. + NPVariant variant_; + + // Pointer to the WebFrame that represents the context for this CefVariant + // object. This pointer is used for creating new NPObjects in the Set*() + // methods that accept array arguments. + WebFrame* webframe_; +}; + +#endif // _VARIANT_IMPL_H diff --git a/libcef/variant_np_util.cc b/libcef/variant_np_util.cc new file mode 100644 index 000000000..3ddc061e3 --- /dev/null +++ b/libcef/variant_np_util.cc @@ -0,0 +1,214 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 "precompiled_libcef.h" +#include "variant_np_util.h" + +#include "config.h" + +#include +#include "np_v8object.h" +#include "v8_proxy.h" + +#undef LOG +#include "base/string_util.h" +#include "bindings/npruntime.h" + + +// NPScriptObjectClass defined in webkit\port\bindings\v8\np_v8object.cpp +extern NPClass* NPScriptObjectClass; + + +NPObject* _NPN_StringVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec) { + v8::Local array = v8::Array::New(); + for (uint32_t index = 0; index < vec.size(); ++index) { + array->Set(v8::Integer::New(index), + v8::String::New(vec[index].c_str(), vec[index].length())); + } + + return NPN_CreateScriptObject(0, array, domwindow); +} + +NPObject* _NPN_WStringVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec) { + v8::Local array = v8::Array::New(); + for (uint32_t index = 0; index < vec.size(); ++index) { + std::string str = WideToUTF8(vec[index].c_str()); + array->Set(v8::Integer::New(index), + v8::String::New(str.c_str(), str.length())); + } + + return NPN_CreateScriptObject(0, array, domwindow); +} + +NPObject* _NPN_IntVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec) { + v8::Local array = v8::Array::New(); + for (uint32_t index = 0; index < vec.size(); ++index) { + array->Set(v8::Integer::New(index), v8::Int32::New(vec[index])); + } + + return NPN_CreateScriptObject(0, array, domwindow); +} + +NPObject* _NPN_DoubleVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec) { + v8::Local array = v8::Array::New(); + for (uint32_t index = 0; index < vec.size(); ++index) { + array->Set(v8::Integer::New(index), v8::Number::New(vec[index])); + } + + return NPN_CreateScriptObject(0, array, domwindow); +} + +NPObject* _NPN_BooleanVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec) { + v8::Local array = v8::Array::New(); + for (uint32_t index = 0; index < vec.size(); ++index) { + array->Set(v8::Integer::New(index), v8::Boolean::New(vec[index])); + } + + return NPN_CreateScriptObject(0, array, domwindow); +} + +bool _NPN_ArrayObjectToStringVector(NPObject* npobject, + std::vector& vec) { + if (npobject == NULL || npobject->_class != NPScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast(npobject); + if (!object->v8_object->IsArray()) + return false; + + v8::Handle array = v8::Handle::Cast(object->v8_object); + for (uint32_t i = 0; i < array->Length(); i++) { + v8::Local value = array->Get(v8::Integer::New(i)); + v8::Local sval = value->ToString(); + uint16_t* buf = new uint16_t[sval->Length()+1]; + sval->Write(buf); + std::string utf8 = WideToUTF8(reinterpret_cast(buf)); + vec.push_back(utf8); + delete[] buf; + } + + return true; +} + +bool _NPN_ArrayObjectToWStringVector(NPObject* npobject, + std::vector& vec) { + if (npobject == NULL || npobject->_class != NPScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast(npobject); + if (!object->v8_object->IsArray()) + return false; + + v8::Handle array = v8::Handle::Cast(object->v8_object); + for (uint32_t i = 0; i < array->Length(); i++) { + v8::Local value = array->Get(v8::Integer::New(i)); + v8::Local sval = value->ToString(); + uint16_t* buf = new uint16_t[sval->Length()+1]; + sval->Write(buf); + std::wstring utf16 = reinterpret_cast(buf); + vec.push_back(utf16); + delete[] buf; + } + + return true; +} + +bool _NPN_ArrayObjectToIntVector(NPObject* npobject, + std::vector& vec) { + if (npobject == NULL || npobject->_class != NPScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast(npobject); + if (!object->v8_object->IsArray()) + return false; + + v8::Handle array = v8::Handle::Cast(object->v8_object); + for (uint32_t i = 0; i < array->Length(); i++) { + v8::Local value = array->Get(v8::Integer::New(i)); + v8::Local ival = value->ToInt32(); + vec.push_back(ival->Value()); + } + + return true; +} + +bool _NPN_ArrayObjectToDoubleVector(NPObject* npobject, + std::vector& vec) { + if (npobject == NULL || npobject->_class != NPScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast(npobject); + if (!object->v8_object->IsArray()) + return false; + + v8::Handle array = v8::Handle::Cast(object->v8_object); + for (uint32_t i = 0; i < array->Length(); i++) { + v8::Local value = array->Get(v8::Integer::New(i)); + v8::Local dval = value->ToNumber(); + vec.push_back(dval->Value()); + } + + return true; +} + +bool _NPN_ArrayObjectToBooleanVector(NPObject* npobject, + std::vector& vec) { + if (npobject == NULL || npobject->_class != NPScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast(npobject); + if (!object->v8_object->IsArray()) + return false; + + v8::Handle array = v8::Handle::Cast(object->v8_object); + for (uint32_t i = 0; i < array->Length(); i++) { + v8::Local value = array->Get(v8::Integer::New(i)); + v8::Local bval = value->ToBoolean(); + vec.push_back(bval->Value()); + } + + return true; +} + +bool _NPN_ArrayObjectToVectorTypeHint(NPObject* npobject, + NPVariantType &typehint) +{ + if (npobject == NULL || npobject->_class != NPScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast(npobject); + if (!object->v8_object->IsArray()) + return false; + + v8::Handle array = v8::Handle::Cast(object->v8_object); + if (array->Length() == 0) + return false; + + typehint = NPVariantType_Null; + + for (uint32_t i = 0; i < array->Length(); i++) { + v8::Local value = array->Get(v8::Integer::New(i)); + if (value->IsBoolean() && typehint <= NPVariantType_Bool) { + if (typehint != NPVariantType_Bool) + typehint = NPVariantType_Bool; + } else if (value->IsInt32() && typehint <= NPVariantType_Int32) { + if (typehint != NPVariantType_Int32) + typehint = NPVariantType_Int32; + } else if (value->IsNumber() && typehint <= NPVariantType_Double) { + if (typehint != NPVariantType_Double) + typehint = NPVariantType_Double; + } else { + typehint = NPVariantType_String; + // String is the least restrictive type, so we don't need to keep looking + break; + } + } + + return true; +} diff --git a/libcef/variant_np_util.h b/libcef/variant_np_util.h new file mode 100644 index 000000000..e621deff2 --- /dev/null +++ b/libcef/variant_np_util.h @@ -0,0 +1,65 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 _VARIANT_NP_UTIL_H +#define _VARIANT_NP_UTIL_H + +#include "third_party/npapi/bindings/npruntime.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +namespace WebCore { +class DOMWindow; +} + +// Convert a vector of values to an NPObject, attached to the specified +// DOM Window, that represents a JavaScript Array of the same values. +NPObject* _NPN_StringVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec); +NPObject* _NPN_WStringVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec); +NPObject* _NPN_IntVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec); +NPObject* _NPN_DoubleVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec); +NPObject* _NPN_BooleanVectorToArrayObject(WebCore::DOMWindow* domwindow, + const std::vector& vec); + +// Convert an NPObject that represents a JavaScript Array to a vector of +// values. +bool _NPN_ArrayObjectToStringVector(NPObject* npobject, + std::vector& vec); +bool _NPN_ArrayObjectToWStringVector(NPObject* npobject, + std::vector& vec); +bool _NPN_ArrayObjectToIntVector(NPObject* npobject, + std::vector& vec); +bool _NPN_ArrayObjectToDoubleVector(NPObject* npobject, + std::vector& vec); +bool _NPN_ArrayObjectToBooleanVector(NPObject* npobject, + std::vector& vec); + +// Evaluate the types of values contained in an NPObject representing a +// JavaScript Array and suggest the most restrictive type that can safely store +// all of the Array values. For instance, if the Array contains all Int32 +// values, the suggested type will be NPVariantType_Int32. If, on the other +// hand, the Array contains a mix of Int32 values and String values, then the +// suggested type will be NPVariantType_String. The supported values, from +// most restrictive to least restrictive, are NPVariantType_Bool, +// NPVariantType_Int32, NPVariantType_Double and NPVariantType_String. Arrays +// that contain values of type NPVariantType_Void, NPVariantType_Null or +// NPVariantType_Object will always result in a suggestion of type +// NPVariantType_String. +bool _NPN_ArrayObjectToVectorTypeHint(NPObject* npobject, + NPVariantType &typehint); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif // _VARIANT_NP_UTIL_H diff --git a/libcef/webview_host.cc b/libcef/webview_host.cc new file mode 100644 index 000000000..51c300092 --- /dev/null +++ b/libcef/webview_host.cc @@ -0,0 +1,50 @@ +// Copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "webview_host.h" + +#include "base/gfx/platform_canvas.h" +#include "base/gfx/rect.h" +#include "base/gfx/size.h" +#include "base/win_util.h" +#include "webkit/glue/webinputevent.h" +#include "webkit/glue/webview.h" + +static const wchar_t kWindowClassName[] = L"WebViewHost"; + +/*static*/ +WebViewHost* WebViewHost::Create(gfx::WindowHandle parent_window, + WebViewDelegate* delegate, + const WebPreferences& prefs) { + WebViewHost* host = new WebViewHost(); + + static bool registered_class = false; + if (!registered_class) { + WNDCLASSEX wcex = {0}; + wcex.cbSize = sizeof(wcex); + wcex.style = CS_DBLCLKS; + wcex.lpfnWndProc = WebWidgetHost::WndProc; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.lpszClassName = kWindowClassName; + RegisterClassEx(&wcex); + registered_class = true; + } + + host->view_ = CreateWindow(kWindowClassName, NULL, + WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, + 0, 0, parent_window, NULL, + GetModuleHandle(NULL), NULL); + win_util::SetWindowUserData(host->view_, host); + + host->webwidget_ = WebView::Create(delegate, prefs); + + return host; +} + +WebView* WebViewHost::webview() const { + return static_cast(webwidget_); +} + diff --git a/libcef/webview_host.h b/libcef/webview_host.h new file mode 100644 index 000000000..bd7103ec6 --- /dev/null +++ b/libcef/webview_host.h @@ -0,0 +1,38 @@ +// Copyright (c) 2006-2008 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 _WEBVIEW_HOST_H +#define _WEBVIEW_HOST_H + +#include "base/basictypes.h" +#include "base/gfx/native_widget_types.h" +#include "base/gfx/rect.h" +#include "base/scoped_ptr.h" +#include "webwidget_host.h" + +struct WebPreferences; +class WebView; +class WebViewDelegate; + +// This class is a simple ViewHandle-based host for a WebView +class WebViewHost : public WebWidgetHost { + public: + // The new instance is deleted once the associated ViewHandle is destroyed. + // The newly created window should be resized after it is created, using the + // MoveWindow (or equivalent) function. + static WebViewHost* Create(gfx::WindowHandle parent_window, + WebViewDelegate* delegate, + const WebPreferences& prefs); + + WebView* webview() const; + + protected: +#if defined(OS_WIN) + virtual bool WndProc(UINT message, WPARAM wparam, LPARAM lparam) { + return false; + } +#endif +}; + +#endif // _WEBVIEW_HOST_H diff --git a/libcef/webwidget_host.cc b/libcef/webwidget_host.cc new file mode 100644 index 000000000..d73f39eee --- /dev/null +++ b/libcef/webwidget_host.cc @@ -0,0 +1,340 @@ +// Copyright (c) 2006-2008 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 "precompiled_libcef.h" +#include "webwidget_host.h" + +#include "base/gfx/platform_canvas.h" +#include "base/gfx/rect.h" +#include "base/logging.h" +#include "base/win_util.h" +#include "webkit/glue/webinputevent.h" +#include "webkit/glue/webwidget.h" + +static const wchar_t kWindowClassName[] = L"WebWidgetHost"; + +/*static*/ +WebWidgetHost* WebWidgetHost::Create(gfx::WindowHandle parent_window, + WebWidgetDelegate* delegate) { + WebWidgetHost* host = new WebWidgetHost(); + + static bool registered_class = false; + if (!registered_class) { + WNDCLASSEX wcex = {0}; + wcex.cbSize = sizeof(wcex); + wcex.style = CS_DBLCLKS; + wcex.lpfnWndProc = WebWidgetHost::WndProc; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.lpszClassName = kWindowClassName; + RegisterClassEx(&wcex); + registered_class = true; + } + + host->view_ = CreateWindowEx(WS_EX_TOOLWINDOW, + kWindowClassName, kWindowClassName, WS_POPUP, + 0, 0, 0, 0, + parent_window, NULL, GetModuleHandle(NULL), NULL); + + win_util::SetWindowUserData(host->view_, host); + + host->webwidget_ = WebWidget::Create(delegate); + + return host; +} + +/*static*/ +WebWidgetHost* WebWidgetHost::FromWindow(gfx::WindowHandle hwnd) { + return reinterpret_cast(win_util::GetWindowUserData(hwnd)); +} + +/*static*/ +LRESULT CALLBACK WebWidgetHost::WndProc(HWND hwnd, UINT message, WPARAM wparam, + LPARAM lparam) { + WebWidgetHost* host = FromWindow(hwnd); + if (host && !host->WndProc(message, wparam, lparam)) { + switch (message) { + case WM_DESTROY: + delete host; + break; + + case WM_PAINT: { + RECT rect; + if (GetUpdateRect(hwnd, &rect, FALSE)) { + host->UpdatePaintRect(gfx::Rect(rect)); + } + host->Paint(); + return 0; + } + + case WM_ERASEBKGND: + // Do nothing here to avoid flashing, the background will be erased + // during painting. + return 0; + + case WM_SIZE: + host->Resize(lparam); + return 0; + + case WM_MOUSEMOVE: + case WM_MOUSELEAVE: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + host->MouseEvent(message, wparam, lparam); + break; + + case WM_MOUSEWHEEL: + host->WheelEvent(wparam, lparam); + break; + + case WM_CAPTURECHANGED: + case WM_CANCELMODE: + host->CaptureLostEvent(); + break; + + // TODO(darin): add WM_SYSKEY{DOWN/UP} to capture ALT key actions + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_CHAR: + case WM_SYSCHAR: + case WM_IME_CHAR: + host->KeyEvent(message, wparam, lparam); + break; + + case WM_SETFOCUS: + host->SetFocus(true); + break; + + case WM_KILLFOCUS: + host->SetFocus(false); + break; + } + } + + return DefWindowProc(hwnd, message, wparam, lparam);; +} + +void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { + DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting"; + + // If this invalidate overlaps with a pending scroll, then we have to + // downgrade to invalidating the scroll rect. + if (damaged_rect.Intersects(scroll_rect_)) { + paint_rect_ = paint_rect_.Union(scroll_rect_); + ResetScrollRect(); + } + paint_rect_ = paint_rect_.Union(damaged_rect); + + RECT r = damaged_rect.ToRECT(); + InvalidateRect(view_, &r, FALSE); +} + +void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { + DCHECK(dx || dy); + + // If we already have a pending scroll operation or if this scroll operation + // intersects the existing paint region, then just failover to invalidating. + if (!scroll_rect_.IsEmpty() || paint_rect_.Intersects(clip_rect)) { + paint_rect_ = paint_rect_.Union(scroll_rect_); + ResetScrollRect(); + paint_rect_ = paint_rect_.Union(clip_rect); + } + + // We will perform scrolling lazily, when requested to actually paint. + scroll_rect_ = clip_rect; + scroll_dx_ = dx; + scroll_dy_ = dy; + + RECT r = clip_rect.ToRECT(); + InvalidateRect(view_, &r, FALSE); +} + +void WebWidgetHost::SetCursor(HCURSOR cursor) { + SetClassLong(view_, GCL_HCURSOR, + static_cast(reinterpret_cast(cursor))); + ::SetCursor(cursor); +} + +void WebWidgetHost::DiscardBackingStore() { + canvas_.reset(); +} + +WebWidgetHost::WebWidgetHost() + : view_(NULL), + webwidget_(NULL), + track_mouse_leave_(false), + scroll_dx_(0), + scroll_dy_(0) { + set_painting(false); +} + +WebWidgetHost::~WebWidgetHost() { + win_util::SetWindowUserData(view_, 0); + + TrackMouseLeave(false); + + webwidget_->Close(); + webwidget_->Release(); +} + +bool WebWidgetHost::WndProc(UINT message, WPARAM wparam, LPARAM lparam) { + switch (message) { + case WM_ACTIVATE: + if (wparam == WA_INACTIVE) { + PostMessage(view_, WM_CLOSE, 0, 0); + return true; + } + break; + } + + return false; +} + +void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { + paint_rect_ = paint_rect_.Union(rect); +} + +void WebWidgetHost::Paint() { + RECT r; + GetClientRect(view_, &r); + gfx::Rect client_rect(r); + + // Allocate a canvas if necessary + if (!canvas_.get()) { + ResetScrollRect(); + paint_rect_ = client_rect; + canvas_.reset(new gfx::PlatformCanvas( + paint_rect_.width(), paint_rect_.height(), true)); + } + + // This may result in more invalidation + webwidget_->Layout(); + + // Scroll the canvas if necessary + scroll_rect_ = client_rect.Intersect(scroll_rect_); + if (!scroll_rect_.IsEmpty()) { + HDC hdc = canvas_->getTopPlatformDevice().getBitmapDC(); + + RECT damaged_rect, r = scroll_rect_.ToRECT(); + ScrollDC(hdc, scroll_dx_, scroll_dy_, NULL, &r, NULL, &damaged_rect); + + PaintRect(gfx::Rect(damaged_rect)); + } + ResetScrollRect(); + + // Paint the canvas if necessary. Allow painting to generate extra rects the + // first time we call it. This is necessary because some WebCore rendering + // objects update their layout only when painted. + for (int i = 0; i < 2; ++i) { + paint_rect_ = client_rect.Intersect(paint_rect_); + if (!paint_rect_.IsEmpty()) { + gfx::Rect rect(paint_rect_); + paint_rect_ = gfx::Rect(); + + DLOG_IF(WARNING, i == 1) << "painting caused additional invalidations"; + PaintRect(rect); + } + } + DCHECK(paint_rect_.IsEmpty()); + + // Paint to the screen + PAINTSTRUCT ps; + BeginPaint(view_, &ps); + canvas_->getTopPlatformDevice().drawToHDC(ps.hdc, + ps.rcPaint.left, + ps.rcPaint.top, + &ps.rcPaint); + EndPaint(view_, &ps); + + // Draw children + UpdateWindow(view_); +} + +void WebWidgetHost::Resize(LPARAM lparam) { + // Force an entire re-paint. TODO(darin): Maybe reuse this memory buffer. + DiscardBackingStore(); + + webwidget_->Resize(gfx::Size(LOWORD(lparam), HIWORD(lparam))); +} + +void WebWidgetHost::MouseEvent(UINT message, WPARAM wparam, LPARAM lparam) { + WebMouseEvent event(view_, message, wparam, lparam); + switch (event.type) { + case WebInputEvent::MOUSE_MOVE: + TrackMouseLeave(true); + break; + case WebInputEvent::MOUSE_LEAVE: + TrackMouseLeave(false); + break; + case WebInputEvent::MOUSE_DOWN: + SetCapture(view_); + break; + case WebInputEvent::MOUSE_UP: + if (GetCapture() == view_) + ReleaseCapture(); + break; + } + webwidget_->HandleInputEvent(&event); +} + +void WebWidgetHost::WheelEvent(WPARAM wparam, LPARAM lparam) { + WebMouseWheelEvent event(view_, WM_MOUSEWHEEL, wparam, lparam); + webwidget_->HandleInputEvent(&event); +} + +void WebWidgetHost::KeyEvent(UINT message, WPARAM wparam, LPARAM lparam) { + WebKeyboardEvent event(view_, message, wparam, lparam); + webwidget_->HandleInputEvent(&event); +} + +void WebWidgetHost::CaptureLostEvent() { + webwidget_->MouseCaptureLost(); +} + +void WebWidgetHost::SetFocus(bool enable) { + webwidget_->SetFocus(enable); +} + +void WebWidgetHost::TrackMouseLeave(bool track) { + if (track == track_mouse_leave_) + return; + track_mouse_leave_ = track; + + DCHECK(view_); + + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + if (!track_mouse_leave_) + tme.dwFlags |= TME_CANCEL; + tme.hwndTrack = view_; + + TrackMouseEvent(&tme); +} + +void WebWidgetHost::ResetScrollRect() { + scroll_rect_ = gfx::Rect(); + scroll_dx_ = 0; + scroll_dy_ = 0; +} + +void WebWidgetHost::PaintRect(const gfx::Rect& rect) { +#ifndef NDEBUG + DCHECK(!painting_); +#endif + DCHECK(canvas_.get()); + + set_painting(true); + webwidget_->Paint(canvas_.get(), rect); + set_painting(false); +} diff --git a/libcef/webwidget_host.h b/libcef/webwidget_host.h new file mode 100644 index 000000000..9fe303bbe --- /dev/null +++ b/libcef/webwidget_host.h @@ -0,0 +1,120 @@ +// Copyright (c) 2006-2008 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 _WEBWIDGET_HOST_H +#define _WEBWIDGET_HOST_H + +#include "base/basictypes.h" +#include "base/gfx/native_widget_types.h" +#include "base/gfx/platform_canvas.h" +#include "base/gfx/rect.h" +#include "base/scoped_ptr.h" + +class WebWidget; +class WebWidgetDelegate; + +namespace gfx { +class Size; +} + +// This class is a simple ViewHandle-based host for a WebWidget +class WebWidgetHost { + public: + // The new instance is deleted once the associated ViewHandle is destroyed. + // The newly created window should be resized after it is created, using the + // MoveWindow (or equivalent) function. + static WebWidgetHost* Create(gfx::WindowHandle parent_window, + WebWidgetDelegate* delegate); + + static WebWidgetHost* FromWindow(gfx::WindowHandle view); +#if defined(OS_MACOSX) + static void HandleEvent(gfx::WindowHandle window, NSEvent *event); +#endif + + gfx::ViewHandle window_handle() const { return view_; } + WebWidget* webwidget() const { return webwidget_; } + + void DidInvalidateRect(const gfx::Rect& rect); + void DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect); +#if defined(OS_WIN) + void SetCursor(HCURSOR cursor); +#endif + + void DiscardBackingStore(); + // Allow clients to update the paint rect. For example, if we get a gdk + // expose or WM_PAINT event, we need to update the paint rect. + void UpdatePaintRect(const gfx::Rect& rect); + void Paint(); + + protected: + WebWidgetHost(); + ~WebWidgetHost(); + +#if defined(OS_WIN) + // Per-class wndproc. Returns true if the event should be swallowed. + virtual bool WndProc(UINT message, WPARAM wparam, LPARAM lparam); + + void Resize(LPARAM lparam); + void MouseEvent(UINT message, WPARAM wparam, LPARAM lparam); + void WheelEvent(WPARAM wparam, LPARAM lparam); + void KeyEvent(UINT message, WPARAM wparam, LPARAM lparam); + void CaptureLostEvent(); + void SetFocus(bool enable); + + static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +#elif defined(OS_MACOSX) + // These need to be called from a non-subclass, so they need to be public. + public: + void Resize(const gfx::Rect& rect); + void MouseEvent(NSEvent *); + void WheelEvent(NSEvent *); + void KeyEvent(NSEvent *); + void SetFocus(bool enable); + protected: +#elif defined(OS_LINUX) + public: + // --------------------------------------------------------------------------- + // This is needed on Linux because the GtkWidget creation is the same between + // both web view hosts and web widget hosts. The Windows code manages this by + // reusing the WndProc function (static, above). However, GTK doesn't use a + // single big callback function like that so we have a static function that + // sets up a GtkWidget correctly. + // parent: a GtkBox to pack the new widget at the end of + // host: a pointer to a WebWidgetHost (or subclass thereof) + // --------------------------------------------------------------------------- + static gfx::WindowHandle CreateWindow(gfx::WindowHandle parent, void* host); + void WindowDestroyed(); + void Resize(const gfx::Size& size); +#endif + + void TrackMouseLeave(bool enable); + void ResetScrollRect(); + void PaintRect(const gfx::Rect& rect); + + void set_painting(bool value) { +#ifndef NDEBUG + painting_ = value; +#endif + } + + gfx::ViewHandle view_; + WebWidget* webwidget_; + scoped_ptr canvas_; + + // specifies the portion of the webwidget that needs painting + gfx::Rect paint_rect_; + + // specifies the portion of the webwidget that needs scrolling + gfx::Rect scroll_rect_; + int scroll_dx_; + int scroll_dy_; + + bool track_mouse_leave_; + +#ifndef NDEBUG + bool painting_; +#endif +}; + +#endif // _WEBWIDGET_HOST_H diff --git a/tests/cefclient/cefclient.cpp b/tests/cefclient/cefclient.cpp new file mode 100644 index 000000000..fc5457c1e --- /dev/null +++ b/tests/cefclient/cefclient.cpp @@ -0,0 +1,860 @@ +// Copyright (c) 2008 The Chromium Embedded Framework 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 "stdafx.h" +#include "cefclient.h" +#include "cef.h" + +#include + +#define MAX_LOADSTRING 100 +#define MAX_URL_LENGTH 255 +#define BUTTON_WIDTH 72 +#define URLBAR_HEIGHT 24 + +// Global Variables: +HINSTANCE hInst; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name + +// Forward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); + +int APIENTRY _tWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + // Initialize the CEF + CefInitialize(); + + MSG msg; + HACCEL hAccelTable; + + // Initialize global strings + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING); + MyRegisterClass(hInstance); + + // Perform application initialization + if (!InitInstance (hInstance, nCmdShow)) + { + return FALSE; + } + + hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT)); + + // Main message loop + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + // Shut down the CEF + CefShutdown(); + + return (int) msg.wParam; +} + + + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +// COMMENTS: +// +// This function and its usage are only necessary if you want this code +// to be compatible with Win32 systems prior to the 'RegisterClassEx' +// function that was added to Windows 95. It is important to call this +// function so that the application will get 'well formed' small icons +// associated with it. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CEFCLIENT)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CEFCLIENT); + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); + + return RegisterClassEx(&wcex); +} + +// +// FUNCTION: InitInstance(HINSTANCE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; // Store instance handle in our global variable + + hWnd = CreateWindow(szWindowClass, szTitle, + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, 0, CW_USEDEFAULT, + 0, NULL, NULL, hInstance, NULL); + + if (!hWnd) + { + return FALSE; + } + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + return TRUE; +} + +// Client implementation of the JS handler class +// Select the "JavaScript" option from the "Tests" menu for an example +class ClientJSHandler : public CefThreadSafeBase +{ +public: + ClientJSHandler() + { + } + ~ClientJSHandler() + { + } + + // Return true if the specified method exists. + virtual bool HasMethod(CefRefPtr browser, + const std::wstring& name) + { + // We have a method called "mymethod" + return (name.compare(L"mymethod") == 0); + } + + // Return true if the specified property exists. + virtual bool HasProperty(CefRefPtr browser, + const std::wstring& name) + { + return false; + } + + // Set the property value. Return true if the property is accepted. + virtual bool SetProperty(CefRefPtr browser, + const std::wstring& name, + const CefRefPtr value) + { + return false; + } + + // Get the property value. Return true if the value is returned. + virtual bool GetProperty(CefRefPtr browser, + const std::wstring& name, + CefRefPtr value) + { + return false; + } + + // Execute a method with the specified argument vector and return + // value. Return true if the method was handled. + virtual bool ExecuteMethod(CefRefPtr browser, + const std::wstring& name, + const VariantVector& args, + CefRefPtr retval) + { + // We only handle the "mymethod" method + if(name.compare(L"mymethod") != 0) + return false; + + // Return a description of the input arguments + std::wstringstream ss; + for(size_t i = 0; i < args.size(); i++) + { + ss << L"arg" << i; + switch(args[i]->GetType()) + { + case CefVariant::TYPE_NULL: + ss << L" null"; + break; + case CefVariant::TYPE_BOOL: + ss << L" bool = " << args[i]->GetBool(); + break; + case CefVariant::TYPE_INT: + ss << L" int = " << args[i]->GetInt(); + break; + case CefVariant::TYPE_DOUBLE: + ss << L" double = " << args[i]->GetDouble(); + break; + case CefVariant::TYPE_STRING: + ss << L" string = " << args[i]->GetString().c_str(); + break; + case CefVariant::TYPE_BOOL_ARRAY: + ss << L" bool array = "; + { + std::vector vec; + args[i]->GetBoolArray(vec); + for(size_t x = 0; x < vec.size(); x++) + { + ss << vec[x]; + if(x < vec.size()-1) + ss << L","; + } + } + break; + case CefVariant::TYPE_INT_ARRAY: + ss << L" int array = "; + { + std::vector vec; + args[i]->GetIntArray(vec); + for(size_t x = 0; x < vec.size(); x++) + { + ss << vec[x]; + if(x < vec.size()-1) + ss << L","; + } + } + break; + case CefVariant::TYPE_DOUBLE_ARRAY: + ss << L" double array = "; + { + std::vector vec; + args[i]->GetDoubleArray(vec); + for(size_t x = 0; x < vec.size(); x++) + { + ss << vec[x]; + if(x < vec.size()-1) + ss << L","; + } + } + break; + case CefVariant::TYPE_STRING_ARRAY: + ss << L" string array = "; + { + std::vector vec; + args[i]->GetStringArray(vec); + for(size_t x = 0; x < vec.size(); x++) + { + ss << vec[x].c_str(); + if(x < vec.size()-1) + ss << L","; + } + } + break; + } + ss << L"\n
"; + } + + retval->SetString(ss.str()); + + return true; + } +}; + +// Load a resource of type BINARY +bool LoadBinaryResource(int binaryId, DWORD &dwSize, LPBYTE &pBytes) +{ + HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(binaryId), + MAKEINTRESOURCE(256)); + if(hRes) + { + HGLOBAL hGlob = LoadResource(hInst, hRes); + if(hGlob) + { + dwSize = SizeofResource(hInst, hRes); + pBytes = (LPBYTE)LockResource(hGlob); + if(dwSize > 0 && pBytes) + return true; + } + } + + return false; +} + +// Client implementation of the browser handler class +class ClientHandler : public CefThreadSafeBase +{ +public: + ClientHandler() + { + m_MainHwnd = NULL; + m_BrowserHwnd = NULL; + m_EditHwnd = NULL; + m_bLoading = false; + m_bCanGoBack = false; + m_bCanGoForward = false; + } + + ~ClientHandler() + { + } + + // Event called before a new window is created. The |parentBrowser| parameter + // will point to the parent browser window, if any. The |popup| parameter + // will be true if the new window is a popup window. If you create the window + // yourself you should populate the window handle member of |createInfo| and + // return RV_HANDLED. Otherwise, return RV_CONTINUE and the framework will + // create the window. By default, a newly created window will recieve the + // same handler as the parent window. To change the handler for the new + // window modify the object that |handler| points to. + virtual RetVal HandleBeforeCreated(CefRefPtr parentBrowser, + CefWindowInfo& createInfo, bool popup, + CefRefPtr& handler, + std::wstring& url) + { + return RV_CONTINUE; + } + + // Event called after a new window is created. The return value is currently + // ignored. + virtual RetVal HandleAfterCreated(CefRefPtr browser) + { + Lock(); + if(!browser->IsPopup()) + { + // We need to keep the main child window, but not popup windows + m_Browser = browser; + m_BrowserHwnd = browser->GetWindowHandle(); + } + // Register our JavaScript "myclass" object + browser->AddJSHandler(L"myclass", new ClientJSHandler()); + Unlock(); + return RV_CONTINUE; + } + + // Event called when the address bar changes. The return value is currently + // ignored. + virtual RetVal HandleAddressChange(CefRefPtr browser, + const std::wstring& url) + { + // Set the edit window text + SetWindowText(m_EditHwnd, url.c_str()); + return RV_CONTINUE; + } + + // Event called when the page title changes. The return value is currently + // ignored. + virtual RetVal HandleTitleChange(CefRefPtr browser, + const std::wstring& title) + { + // Set the frame window title bar + SetWindowText(m_MainHwnd, title.c_str()); + return RV_CONTINUE; + } + + // Event called before browser navigation. The client has an opportunity to + // modify the |request| object if desired. Return RV_HANDLED to cancel + // navigation. + virtual RetVal HandleBeforeBrowse(CefRefPtr browser, + CefRefPtr request, + NavType navType, bool isRedirect) + { + return RV_CONTINUE; + } + + // Event called when the browser begins loading a page. The return value is + // currently ignored. + virtual RetVal HandleLoadStart(CefRefPtr browser) + { + Lock(); + // We've just started loading a page + m_bLoading = true; + m_bCanGoBack = false; + m_bCanGoForward = false; + Unlock(); + return RV_CONTINUE; + } + + // Event called when the browser is done loading a page. This event will + // be generated irrespective of whether the request completes successfully. + // The return value is currently ignored. + virtual RetVal HandleLoadEnd(CefRefPtr browser) + { + Lock(); + // We've just finished loading a page + m_bLoading = false; + m_bCanGoBack = browser->CanGoBack(); + m_bCanGoForward = browser->CanGoForward(); + Unlock(); + return RV_CONTINUE; + } + + // Called when the browser fails to load a resource. |errorCode is the + // error code number and |failedUrl| is the URL that failed to load. To + // provide custom error text assign the text to |errorText| and return + // RV_HANDLED. Otherwise, return RV_CONTINUE for the default error text. + virtual RetVal HandleLoadError(CefRefPtr browser, + ErrorCode errorCode, + const std::wstring& failedUrl, + std::wstring& errorText) + { + if(errorCode == ERR_CACHE_MISS) + { + // Usually caused by navigating to a page with POST data via back or + // forward buttons. + errorText = L"Expired Form Data" + L"

Expired Form Data

" + L"

Your form request has expired. " + L"Click reload to re-submit the form data.

" + L""; + } + else + { + // All other messages. + std::wstringstream ss; + ss << L"Load Failed" + L"

Load Failed

" + L"

Load of URL " << failedUrl << + L"failed with error code " << static_cast(errorCode) << + L".

" + L""; + errorText = ss.str(); + } + return RV_HANDLED; + } + + // Event called before a resource is loaded. To allow the resource to load + // normally return RV_CONTINUE. To redirect the resource to a new url + // populate the |redirectUrl| value and return RV_CONTINUE. To specify + // data for the resource return a CefStream object in |resourceStream|, set + // 'mimeType| to the resource stream's mime type, and return RV_CONTINUE. + // To cancel loading of the resource return RV_HANDLED. + virtual RetVal HandleBeforeResourceLoad(CefRefPtr browser, + CefRefPtr request, + std::wstring& redirectUrl, + CefRefPtr& resourceStream, + std::wstring& mimeType, + int loadFlags) + { + std::wstring url = request->GetURL(); + if(wcsstr(url.c_str(), L"logo.gif") != NULL) { + // Any time we find "logo.gif" in the URL substitute in our own image + DWORD dwSize; + LPBYTE pBytes; + if(LoadBinaryResource(IDS_LOGO, dwSize, pBytes)) { + resourceStream = CefStreamReader::CreateForData(pBytes, dwSize); + mimeType = L"image/jpg"; + } + } + return RV_CONTINUE; + } + + // Event called before a context menu is displayed. To cancel display of the + // default context menu return RV_HANDLED. + virtual RetVal HandleBeforeMenu(CefRefPtr browser, + const MenuInfo& menuInfo) + { + return RV_CONTINUE; + } + + + // Event called to optionally override the default text for a context menu + // item. |label| contains the default text and may be modified to substitute + // alternate text. The return value is currently ignored. + virtual RetVal HandleGetMenuLabel(CefRefPtr browser, + MenuId menuId, std::wstring& label) + { + return RV_CONTINUE; + } + + // Event called when an option is selected from the default context menu. + // Return RV_HANDLED to cancel default handling of the action. + virtual RetVal HandleMenuAction(CefRefPtr browser, + MenuId menuId) + { + return RV_CONTINUE; + } + + // Event called to format print headers and footers. |printInfo| contains + // platform-specific information about the printer context. |url| is the + // URL if the currently printing page, |title| is the title of the currently + // printing page, |currentPage| is the current page number and |maxPages| is + // the total number of pages. Six default header locations are provided + // by the implementation: top left, top center, top right, bottom left, + // bottom center and bottom right. To use one of these default locations + // just assign a string to the appropriate variable. To draw the header + // and footer yourself return RV_HANDLED. Otherwise, populate the approprate + // variables and return RV_CONTINUE. + virtual RetVal HandlePrintHeaderFooter(CefRefPtr browser, + CefPrintInfo& printInfo, + const std::wstring& url, + const std::wstring& title, + int currentPage, int maxPages, + std::wstring& topLeft, + std::wstring& topCenter, + std::wstring& topRight, + std::wstring& bottomLeft, + std::wstring& bottomCenter, + std::wstring& bottomRight) + { + // Place the page title at top left + topLeft = title; + // Place the page URL at top right + topRight = url; + + // Place "Page X of Y" at bottom center + std::wstringstream strstream; + strstream << L"Page " << currentPage << L" of " << maxPages; + bottomCenter = strstream.str(); + + return RV_CONTINUE; + } + + // Run a JS alert message. Return RV_CONTINUE to display the default alert + // or RV_HANDLED if you displayed a custom alert. + virtual RetVal HandleJSAlert(CefRefPtr browser, + const std::wstring& message) + { + return RV_CONTINUE; + } + + // Run a JS confirm request. Return RV_CONTINUE to display the default alert + // or RV_HANDLED if you displayed a custom alert. If you handled the alert + // set |retval| to true if the user accepted the confirmation. + virtual RetVal HandleJSConfirm(CefRefPtr browser, + const std::wstring& message, bool& retval) + { + return RV_CONTINUE; + } + + // Run a JS prompt request. Return RV_CONTINUE to display the default prompt + // or RV_HANDLED if you displayed a custom prompt. If you handled the prompt + // set |retval| to true if the user accepted the prompt and request and + // |result| to the resulting value. + virtual RetVal HandleJSPrompt(CefRefPtr browser, + const std::wstring& message, + const std::wstring& default_value, + bool& retval, + std::wstring& result) + { + return RV_CONTINUE; + } + + // Retrieve the current navigation state flags + void GetNavState(bool &isLoading, bool &canGoBack, bool &canGoForward) + { + Lock(); + isLoading = m_bLoading; + canGoBack = m_bCanGoBack; + canGoForward = m_bCanGoForward; + Unlock(); + } + + void SetMainHwnd(HWND hwnd) + { + Lock(); + m_MainHwnd = hwnd; + Unlock(); + } + + void SetEditHwnd(HWND hwnd) + { + Lock(); + m_EditHwnd = hwnd; + Unlock(); + } + + CefRefPtr GetBrowser() + { + return m_Browser; + } + + HWND GetBrowserHwnd() + { + return m_BrowserHwnd; + } + +protected: + // The child browser window + CefRefPtr m_Browser; + + // The main frame window handle + HWND m_MainHwnd; + + // The child browser window handle + HWND m_BrowserHwnd; + + // The edit window handle + HWND m_EditHwnd; + + // True if the page is currently loading + bool m_bLoading; + // True if the user can navigate backwards + bool m_bCanGoBack; + // True if the user can navigate forwards + bool m_bCanGoForward; +}; + + +// +// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) +// +// PURPOSE: Processes messages for the main window. +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static CefRefPtr handler; + static HWND backWnd = NULL, forwardWnd = NULL, reloadWnd = NULL, + stopWnd = NULL, editWnd = NULL; + static WNDPROC editWndOldProc = NULL; + + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + + if(hWnd == editWnd) + { + // Callback for the edit window + switch (message) + { + case WM_CHAR: + if (wParam == VK_RETURN && handler.get()) + { + // When the user hits the enter key load the URL + CefRefPtr browser = handler->GetBrowser(); + wchar_t strPtr[MAX_URL_LENGTH]; + *((LPWORD)strPtr) = MAX_URL_LENGTH; + LRESULT strLen = SendMessage(hWnd, EM_GETLINE, 0, (LPARAM)strPtr); + if (strLen > 0) + browser->LoadURL(strPtr, std::wstring()); + + return 0; + } + } + + return (LRESULT)CallWindowProc(editWndOldProc, hWnd, message, wParam, lParam); + } + else + { + // Callback for the main window + switch (message) + { + case WM_CREATE: + { + // Create the single static handler class instance + handler = new ClientHandler(); + handler->SetMainHwnd(hWnd); + + // Create the child windows used for navigation + RECT rect; + int x = 0; + + GetClientRect(hWnd, &rect); + + backWnd = CreateWindow(L"BUTTON", L"Back", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON + | WS_DISABLED, x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, + hWnd, (HMENU) IDC_NAV_BACK, hInst, 0); + x += BUTTON_WIDTH; + + forwardWnd = CreateWindow(L"BUTTON", L"Forward", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON + | WS_DISABLED, x, 0, BUTTON_WIDTH, + URLBAR_HEIGHT, hWnd, (HMENU) IDC_NAV_FORWARD, + hInst, 0); + x += BUTTON_WIDTH; + + reloadWnd = CreateWindow(L"BUTTON", L"Reload", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON + | WS_DISABLED, x, 0, BUTTON_WIDTH, + URLBAR_HEIGHT, hWnd, (HMENU) IDC_NAV_RELOAD, + hInst, 0); + x += BUTTON_WIDTH; + + stopWnd = CreateWindow(L"BUTTON", L"Stop", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON + | WS_DISABLED, x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, + hWnd, (HMENU) IDC_NAV_STOP, hInst, 0); + x += BUTTON_WIDTH; + + editWnd = CreateWindow(L"EDIT", 0, + WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | + ES_AUTOVSCROLL | ES_AUTOHSCROLL| WS_DISABLED, + x, 0, rect.right - BUTTON_WIDTH * 4, + URLBAR_HEIGHT, hWnd, 0, hInst, 0); + + // Assign the edit window's WNDPROC to this function so that we can + // capture the enter key + editWndOldProc = + reinterpret_cast(GetWindowLongPtr(editWnd, GWLP_WNDPROC)); + SetWindowLongPtr(editWnd, GWLP_WNDPROC, + reinterpret_cast(WndProc)); + handler->SetEditHwnd(editWnd); + + rect.top += URLBAR_HEIGHT; + + CefWindowInfo info; + + // Initialize window info to the defaults for a child window + info.SetAsChild(hWnd, rect); + + // Creat the new child child browser window + CefBrowser::CreateBrowser(info, false, + static_cast>(handler), + L"http://www.google.com"); + + // Start the timer that will be used to update child window state + SetTimer(hWnd, 1, 500, NULL); + } + return 0; + + case WM_TIMER: + if(handler.get() && handler->GetBrowserHwnd()) + { + // Retrieve the current navigation state + bool isLoading, canGoBack, canGoForward; + handler->GetNavState(isLoading, canGoBack, canGoForward); + + // Update the status of child windows + EnableWindow(editWnd, TRUE); + EnableWindow(backWnd, canGoBack); + EnableWindow(forwardWnd, canGoForward); + EnableWindow(reloadWnd, !isLoading); + EnableWindow(stopWnd, isLoading); + } + + case WM_COMMAND: + { + CefRefPtr browser; + if(handler.get()) + browser = handler->GetBrowser(); + + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDM_ABOUT: + DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); + return 0; + case IDM_EXIT: + DestroyWindow(hWnd); + return 0; + case IDC_NAV_BACK: // Back button + if(browser.get()) + browser->GoBack(); + return 0; + case IDC_NAV_FORWARD: // Forward button + if(browser.get()) + browser->GoForward(); + return 0; + case IDC_NAV_RELOAD: // Reload button + if(browser.get()) + browser->Reload(); + return 0; + case IDC_NAV_STOP: // Stop button + if(browser.get()) + browser->StopLoad(); + return 0; + case ID_TESTS_JAVASCRIPT: // Test our javascript handler + if(browser.get()) + { + std::wstring html = + L"ClientJSHandler says:
" + L"" + L""; + browser->LoadString(html, L"about:blank"); + } + return 0; + } + } + break; + + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + return 0; + + case WM_SETFOCUS: + if(handler.get() && handler->GetBrowserHwnd()) + { + // Pass focus to the browser window + PostMessage(handler->GetBrowserHwnd(), WM_SETFOCUS, wParam, NULL); + } + return 0; + + case WM_SIZE: + if(handler.get() && handler->GetBrowserHwnd()) + { + // Resize the browser window and address bar to match the new frame + // window size + RECT rect; + GetClientRect(hWnd, &rect); + rect.top += URLBAR_HEIGHT; + + int urloffset = rect.left + BUTTON_WIDTH * 4; + + HDWP hdwp = BeginDeferWindowPos(1); + hdwp = DeferWindowPos(hdwp, editWnd, NULL, urloffset, + 0, rect.right - urloffset, URLBAR_HEIGHT, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, handler->GetBrowserHwnd(), NULL, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + SWP_NOZORDER); + EndDeferWindowPos(hdwp); + } + break; + + case WM_ERASEBKGND: + if(handler.get() && handler->GetBrowserHwnd()) + { + // Dont erase the background if the browser window has been loaded + // (this avoids flashing) + return 0; + } + break; + + case WM_DESTROY: + // The frame window has exited + KillTimer(hWnd, 1); + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hWnd, message, wParam, lParam); + } +} + +// Message handler for about box. +INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + UNREFERENCED_PARAMETER(lParam); + switch (message) + { + case WM_INITDIALOG: + return (INT_PTR)TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + } + break; + } + return (INT_PTR)FALSE; +} diff --git a/tests/cefclient/cefclient.h b/tests/cefclient/cefclient.h new file mode 100644 index 000000000..12aef5271 --- /dev/null +++ b/tests/cefclient/cefclient.h @@ -0,0 +1,7 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#pragma once + +#include "resource.h" diff --git a/tests/cefclient/cefclient.rc b/tests/cefclient/cefclient.rc new file mode 100644 index 000000000..d2fd2fed5 --- /dev/null +++ b/tests/cefclient/cefclient.rc @@ -0,0 +1,147 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Binary +// + +IDS_LOGO BINARY "res\logo.jpg" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_CEFCLIENT ICON "res\cefclient.ico" +IDI_SMALL ICON "res\small.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_CEFCLIENT MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", IDM_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&About ...", IDM_ABOUT + END + POPUP "Tests" + BEGIN + MENUITEM "JavaScript", ID_TESTS_JAVASCRIPT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_CEFCLIENT ACCELERATORS +BEGIN + "?", IDM_ABOUT, ASCII, ALT + "/", IDM_ABOUT, ASCII, ALT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG 22, 17, 230, 75 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "System" +BEGIN + ICON IDI_CEFCLIENT,IDC_MYICON,14,9,16,16 + LTEXT "cefclient Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2008",IDC_STATIC,49,20,119,8 + DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_APP_TITLE "cefclient" + IDC_CEFCLIENT "CEFCLIENT" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tests/cefclient/cefclient.vcproj b/tests/cefclient/cefclient.vcproj new file mode 100644 index 000000000..0d37635e5 --- /dev/null +++ b/tests/cefclient/cefclient.vcproj @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cefclient/cefclient.vsprops b/tests/cefclient/cefclient.vsprops new file mode 100644 index 000000000..2ae3e7ca0 --- /dev/null +++ b/tests/cefclient/cefclient.vsprops @@ -0,0 +1,22 @@ + + + + + + diff --git a/tests/cefclient/res/cefclient.ico b/tests/cefclient/res/cefclient.ico new file mode 100644 index 000000000..d551aa3aa Binary files /dev/null and b/tests/cefclient/res/cefclient.ico differ diff --git a/tests/cefclient/res/logo.jpg b/tests/cefclient/res/logo.jpg new file mode 100644 index 000000000..1050d1b84 Binary files /dev/null and b/tests/cefclient/res/logo.jpg differ diff --git a/tests/cefclient/res/small.ico b/tests/cefclient/res/small.ico new file mode 100644 index 000000000..d551aa3aa Binary files /dev/null and b/tests/cefclient/res/small.ico differ diff --git a/tests/cefclient/resource.h b/tests/cefclient/resource.h new file mode 100644 index 000000000..63e0462a5 --- /dev/null +++ b/tests/cefclient/resource.h @@ -0,0 +1,38 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by cefclient.rc +// +#define BINARY 256 +#define IDC_MYICON 2 +#define IDD_CEFCLIENT_DIALOG 102 +#define IDS_APP_TITLE 103 +#define IDD_ABOUTBOX 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDI_CEFCLIENT 107 +#define IDI_SMALL 108 +#define IDC_CEFCLIENT 109 +#define IDR_MAINFRAME 128 +#define IDC_NAV_BACK 200 +#define IDC_NAV_FORWARD 201 +#define IDC_NAV_RELOAD 202 +#define IDC_NAV_STOP 203 +#define ID_TESTS_JAVASCRIPT 32771 +#define IDC_STATIC -1 +#define IDS_LOGO 1000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 32772 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/tests/cefclient/stdafx.cpp b/tests/cefclient/stdafx.cpp new file mode 100644 index 000000000..1f42222fa --- /dev/null +++ b/tests/cefclient/stdafx.cpp @@ -0,0 +1,12 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +// stdafx.cpp : source file that includes just the standard includes +// cefclient.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/tests/cefclient/stdafx.h b/tests/cefclient/stdafx.h new file mode 100644 index 000000000..91f74713d --- /dev/null +++ b/tests/cefclient/stdafx.h @@ -0,0 +1,46 @@ +// Copyright (c) 2008 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows XP or later. +#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. +#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. +#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. +#endif + +#undef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +// C RunTime Header Files +#include +#include +#include +#include + +//#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +//#include +//#include + +// TODO: reference additional headers your program requires here