// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_FRAME_URLMON_BIND_STATUS_CALLBACK_H_ #define CHROME_FRAME_URLMON_BIND_STATUS_CALLBACK_H_ #include <atlbase.h> #include <atlcom.h> #include "base/memory/scoped_ptr.h" #include "chrome_frame/bind_status_callback_impl.h" #include "chrome_frame/stream_impl.h" // A fake stream class to serve cached data to arbitrary // IBindStatusCallback class CacheStream : public CComObjectRoot, public StreamImpl { public: BEGIN_COM_MAP(CacheStream) COM_INTERFACE_ENTRY(IStream) COM_INTERFACE_ENTRY(ISequentialStream) END_COM_MAP() CacheStream() : size_(0), position_(0), eof_(false) { } HRESULT Initialize(const char* cache, size_t size, bool eof); static HRESULT BSCBFeedData(IBindStatusCallback* bscb, const char* data, size_t size, CLIPFORMAT clip_format, size_t flags, bool eof); // IStream overrides STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read); protected: scoped_ptr<char[]> cache_; size_t size_; size_t position_; bool eof_; private: DISALLOW_COPY_AND_ASSIGN(CacheStream); }; // Utility class for data sniffing class SniffData { public: SniffData() : renderer_type_(OTHER), size_(0), eof_(false) {} enum RendererType { UNDETERMINED, CHROME, OTHER }; HRESULT InitializeCache(const std::wstring& url); HRESULT ReadIntoCache(IStream* stream, bool force_determination); HRESULT DrainCache(IBindStatusCallback* bscb, DWORD bscf, CLIPFORMAT clip_format); void DetermineRendererType(bool last_chance); bool is_undetermined() const { return (UNDETERMINED == renderer_type_); } bool is_chrome() const { return (CHROME == renderer_type_); } RendererType renderer_type() const { return renderer_type_; } size_t size() const { return size_; } bool is_cache_valid() { return (size_ != 0); } base::win::ScopedComPtr<IStream> cache_; std::wstring url_; RendererType renderer_type_; size_t size_; static const size_t kMaxSniffSize = 2 * 1024; bool eof_; private: DISALLOW_COPY_AND_ASSIGN(SniffData); }; // A wrapper for bind status callback in IMoniker::BindToStorage class BSCBStorageBind : public BSCBImpl { public: typedef BSCBImpl CallbackImpl; BSCBStorageBind(); ~BSCBStorageBind(); BEGIN_COM_MAP(BSCBStorageBind) COM_INTERFACE_ENTRY(IBindStatusCallback) COM_INTERFACE_ENTRY_CHAIN(CallbackImpl) END_COM_MAP() HRESULT Initialize(IMoniker* moniker, IBindCtx* bind_ctx); HRESULT MayPlayBack(DWORD flags); // IBindStatusCallback STDMETHOD(OnProgress)(ULONG progress, ULONG progress_max, ULONG status_code, LPCWSTR status_text); STDMETHOD(OnDataAvailable)(DWORD flags, DWORD size, FORMATETC* format_etc, STGMEDIUM* stgmed); STDMETHOD(OnStopBinding)(HRESULT hresult, LPCWSTR error); protected: // is it a good time to start caching progress notifications bool ShouldCacheProgress(ULONG status_code) const; protected: SniffData data_sniffer_; // A structure to cache the progress notifications. class Progress { public: Progress(ULONG progress, ULONG progress_max, ULONG status_code, const wchar_t* status_text) : progress_(progress), progress_max_(progress_max), status_code_(status_code) { if (status_text) { int len = lstrlenW(status_text) + 1; status_text_.reset(new wchar_t[len]); if (status_text_.get()) { lstrcpynW(status_text_.get(), status_text, len); } else { NOTREACHED(); } } } ~Progress() { } ULONG progress() const { return progress_; } ULONG progress_max() const { return progress_max_; } ULONG status_code() const { return status_code_; } const wchar_t* status_text() const { return status_text_.get(); } protected: ULONG progress_; ULONG progress_max_; ULONG status_code_; // We don't use std::wstring here since we want to be able to play // progress notifications back exactly as we got them. NULL and L"" are // not equal. scoped_ptr<wchar_t[]> status_text_; }; typedef std::vector<Progress*> ProgressVector; ProgressVector saved_progress_; CLIPFORMAT clip_format_; private: DISALLOW_COPY_AND_ASSIGN(BSCBStorageBind); }; #endif // CHROME_FRAME_URLMON_BIND_STATUS_CALLBACK_H_