// Copyright (c) 2014 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 "tests/cefclient/browser/osr_dragdrop_win.h" #if defined(CEF_USE_ATL) #include #include #include #include #include #include "include/wrapper/cef_helpers.h" #include "tests/cefclient/browser/bytes_write_handler.h" #include "tests/cefclient/browser/resource.h" #include "tests/shared/browser/util_win.h" namespace client { namespace { DWORD DragOperationToDropEffect(CefRenderHandler::DragOperation allowed_ops) { DWORD effect = DROPEFFECT_NONE; if (allowed_ops & DRAG_OPERATION_COPY) { effect |= DROPEFFECT_COPY; } if (allowed_ops & DRAG_OPERATION_LINK) { effect |= DROPEFFECT_LINK; } if (allowed_ops & DRAG_OPERATION_MOVE) { effect |= DROPEFFECT_MOVE; } return effect; } CefRenderHandler::DragOperationsMask DropEffectToDragOperation(DWORD effect) { DWORD operation = DRAG_OPERATION_NONE; if (effect & DROPEFFECT_COPY) { operation |= DRAG_OPERATION_COPY; } if (effect & DROPEFFECT_LINK) { operation |= DRAG_OPERATION_LINK; } if (effect & DROPEFFECT_MOVE) { operation |= DRAG_OPERATION_MOVE; } return static_cast(operation); } CefMouseEvent ToMouseEvent(POINTL p, DWORD key_state, HWND hWnd) { CefMouseEvent ev; POINT screen_point = {p.x, p.y}; ScreenToClient(hWnd, &screen_point); ev.x = screen_point.x; ev.y = screen_point.y; ev.modifiers = GetCefMouseModifiers(key_state); return ev; } void GetStorageForBytes(STGMEDIUM* storage, const void* data, size_t bytes) { HANDLE handle = GlobalAlloc(GPTR, static_cast(bytes)); if (handle) { memcpy(handle, data, bytes); } storage->hGlobal = handle; storage->tymed = TYMED_HGLOBAL; storage->pUnkForRelease = nullptr; } template void GetStorageForString(STGMEDIUM* stgmed, const std::basic_string& data) { GetStorageForBytes( stgmed, data.c_str(), (data.size() + 1) * sizeof(typename std::basic_string::value_type)); } void GetStorageForFileDescriptor(STGMEDIUM* storage, const std::wstring& file_name) { DCHECK(!file_name.empty()); HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR)); FILEGROUPDESCRIPTOR* descriptor = reinterpret_cast(hdata); descriptor->cItems = 1; descriptor->fgd[0].dwFlags = FD_LINKUI; wcsncpy_s(descriptor->fgd[0].cFileName, MAX_PATH, file_name.c_str(), std::min(file_name.size(), static_cast(MAX_PATH - 1u))); storage->tymed = TYMED_HGLOBAL; storage->hGlobal = hdata; storage->pUnkForRelease = nullptr; } // Helper method for converting from text/html to MS CF_HTML. // Documentation for the CF_HTML format is available at // http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx std::string HtmlToCFHtml(const std::string& html, const std::string& base_url) { if (html.empty()) { return std::string(); } #define MAX_DIGITS 10 #define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits) #define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u" #define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS) static const char* header = "Version:0.9\r\n" "StartHTML:" NUMBER_FORMAT "\r\n" "EndHTML:" NUMBER_FORMAT "\r\n" "StartFragment:" NUMBER_FORMAT "\r\n" "EndFragment:" NUMBER_FORMAT "\r\n"; static const char* source_url_prefix = "SourceURL:"; static const char* start_markup = "\r\n\r\n"; static const char* end_markup = "\r\n\r\n"; // Calculate offsets size_t start_html_offset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4; if (!base_url.empty()) { start_html_offset += strlen(source_url_prefix) + base_url.length() + 2; // Add 2 for \r\n. } size_t start_fragment_offset = start_html_offset + strlen(start_markup); size_t end_fragment_offset = start_fragment_offset + html.length(); size_t end_html_offset = end_fragment_offset + strlen(end_markup); char raw_result[1024]; _snprintf(raw_result, sizeof(1024), header, start_html_offset, end_html_offset, start_fragment_offset, end_fragment_offset); std::string result = raw_result; if (!base_url.empty()) { result.append(source_url_prefix); result.append(base_url); result.append("\r\n"); } result.append(start_markup); result.append(html); result.append(end_markup); #undef MAX_DIGITS #undef MAKE_NUMBER_FORMAT_1 #undef MAKE_NUMBER_FORMAT_2 #undef NUMBER_FORMAT return result; } void CFHtmlExtractMetadata(const std::string& cf_html, std::string* base_url, size_t* html_start, size_t* fragment_start, size_t* fragment_end) { // Obtain base_url if present. if (base_url) { static std::string src_url_str("SourceURL:"); size_t line_start = cf_html.find(src_url_str); if (line_start != std::string::npos) { size_t src_end = cf_html.find("\n", line_start); size_t src_start = line_start + src_url_str.length(); if (src_end != std::string::npos && src_start != std::string::npos) { *base_url = cf_html.substr(src_start, src_end - src_start); } } } // Find the markup between "" and "". // If the comments cannot be found, like copying from OpenOffice Writer, // we simply fall back to using StartFragment/EndFragment bytecount values // to determine the fragment indexes. std::string cf_html_lower = cf_html; size_t markup_start = cf_html_lower.find("(atoi(cf_html.c_str() + start_fragment_start + start_fragment_str.length())); } static std::string end_fragment_str("EndFragment:"); size_t end_fragment_start = cf_html.find(end_fragment_str); if (end_fragment_start != std::string::npos) { *fragment_end = static_cast(atoi( cf_html.c_str() + end_fragment_start + end_fragment_str.length())); } } else { *fragment_start = cf_html.find('>', tag_start) + 1; size_t tag_end = cf_html.rfind("