📄 clipboardutilitieswin.cpp
字号:
/* * Copyright (C) 2007, 2008 Apple 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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. */#include "config.h"#include "ClipboardUtilitiesWin.h"#include "CString.h"#include "DocumentFragment.h"#include "KURL.h"#include "PlatformString.h"#include "TextEncoding.h"#include "markup.h"#include <CoreFoundation/CoreFoundation.h>#include <wtf/RetainPtr.h>#include <shlwapi.h>#include <wininet.h> // for INTERNET_MAX_URL_LENGTHnamespace WebCore {FORMATETC* cfHDropFormat(){ static FORMATETC urlFormat = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat;}static bool getWebLocData(IDataObject* dataObject, String& url, String* title) { bool succeeded = false; WCHAR filename[MAX_PATH]; WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH]; STGMEDIUM medium; if (FAILED(dataObject->GetData(cfHDropFormat(), &medium))) return false; HDROP hdrop = (HDROP)GlobalLock(medium.hGlobal); if (!hdrop) return false; if (!DragQueryFileW(hdrop, 0, filename, ARRAYSIZE(filename))) goto exit; if (_wcsicmp(PathFindExtensionW(filename), L".url")) goto exit; if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, ARRAYSIZE(urlBuffer), filename)) goto exit; if (title) { PathRemoveExtension(filename); *title = String((UChar*)filename); } url = String((UChar*)urlBuffer); succeeded = true;exit: // Free up memory. DragFinish(hdrop); GlobalUnlock(medium.hGlobal); return succeeded;}static String extractURL(const String &inURL, String* title){ String url = inURL; int splitLoc = url.find('\n'); if (splitLoc > 0) { if (title) *title = url.substring(splitLoc+1); url.truncate(splitLoc); } else if (title) *title = url; return url;}//Firefox text/htmlstatic FORMATETC* texthtmlFormat() { static UINT cf = RegisterClipboardFormat(L"text/html"); static FORMATETC texthtmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &texthtmlFormat;}HGLOBAL createGlobalData(const KURL& url, const String& title){ String mutableURL(url.string()); String mutableTitle(title); SIZE_T size = mutableURL.length() + mutableTitle.length() + 2; // +1 for "\n" and +1 for null terminator HGLOBAL cbData = ::GlobalAlloc(GPTR, size * sizeof(UChar)); if (cbData) { PWSTR buffer = (PWSTR)::GlobalLock(cbData); swprintf_s(buffer, size, L"%s\n%s", mutableURL.charactersWithNullTermination(), mutableTitle.charactersWithNullTermination()); ::GlobalUnlock(cbData); } return cbData;}HGLOBAL createGlobalData(const String& str){ HGLOBAL globalData = ::GlobalAlloc(GPTR, (str.length() + 1) * sizeof(UChar)); if (!globalData) return 0; UChar* buffer = static_cast<UChar*>(::GlobalLock(globalData)); memcpy(buffer, str.characters(), str.length() * sizeof(UChar)); buffer[str.length()] = 0; ::GlobalUnlock(globalData); return globalData;}HGLOBAL createGlobalData(const Vector<char>& vector){ HGLOBAL globalData = ::GlobalAlloc(GPTR, vector.size() + 1); if (!globalData) return 0; char* buffer = static_cast<char*>(::GlobalLock(globalData)); memcpy(buffer, vector.data(), vector.size()); buffer[vector.size()] = 0; ::GlobalUnlock(globalData); return globalData;}static void append(Vector<char>& vector, const char* string){ vector.append(string, strlen(string));}static void append(Vector<char>& vector, const CString& string){ vector.append(string.data(), string.length());}// Documentation for the CF_HTML format is available at http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.aspvoid markupToCF_HTML(const String& markup, const String& srcURL, Vector<char>& result){ if (markup.isEmpty()) return; #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) const char* header = "Version:0.9\n" "StartHTML:" NUMBER_FORMAT "\n" "EndHTML:" NUMBER_FORMAT "\n" "StartFragment:" NUMBER_FORMAT "\n" "EndFragment:" NUMBER_FORMAT "\n"; const char* sourceURLPrefix = "SourceURL:"; const char* startMarkup = "<HTML>\n<BODY>\n<!--StartFragment-->\n"; const char* endMarkup = "\n<!--EndFragment-->\n</BODY>\n</HTML>"; CString sourceURLUTF8 = srcURL == blankURL() ? "" : srcURL.utf8(); CString markupUTF8 = markup.utf8(); // calculate offsets unsigned startHTMLOffset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4; if (sourceURLUTF8.length()) startHTMLOffset += strlen(sourceURLPrefix) + sourceURLUTF8.length() + 1; unsigned startFragmentOffset = startHTMLOffset + strlen(startMarkup); unsigned endFragmentOffset = startFragmentOffset + markupUTF8.length(); unsigned endHTMLOffset = endFragmentOffset + strlen(endMarkup); append(result, String::format(header, startHTMLOffset, endHTMLOffset, startFragmentOffset, endFragmentOffset).utf8()); if (sourceURLUTF8.length()) { append(result, sourceURLPrefix); append(result, sourceURLUTF8); result.append('\n'); } append(result, startMarkup); append(result, markupUTF8); append(result, endMarkup); #undef MAX_DIGITS #undef MAKE_NUMBER_FORMAT_1 #undef MAKE_NUMBER_FORMAT_2 #undef NUMBER_FORMAT}String urlToMarkup(const KURL& url, const String& title){ Vector<UChar> markup; append(markup, "<a href=\""); append(markup, url.string()); append(markup, "\">"); append(markup, title); append(markup, "</a>"); return String::adopt(markup);}void replaceNewlinesWithWindowsStyleNewlines(String& str){ static const UChar Newline = '\n'; static const char* const WindowsNewline("\r\n"); str.replace(Newline, WindowsNewline);}void replaceNBSPWithSpace(String& str){ static const UChar NonBreakingSpaceCharacter = 0xA0; static const UChar SpaceCharacter = ' '; str.replace(NonBreakingSpaceCharacter, SpaceCharacter);}FORMATETC* urlWFormat(){ static UINT cf = RegisterClipboardFormat(L"UniformResourceLocatorW"); static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat;}FORMATETC* urlFormat(){ static UINT cf = RegisterClipboardFormat(L"UniformResourceLocator"); static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat;}FORMATETC* plainTextFormat(){ static FORMATETC textFormat = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &textFormat;}FORMATETC* plainTextWFormat(){ static FORMATETC textFormat = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &textFormat;}FORMATETC* filenameWFormat(){ static UINT cf = RegisterClipboardFormat(L"FileNameW"); static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat;}FORMATETC* filenameFormat(){ static UINT cf = RegisterClipboardFormat(L"FileName"); static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat;}//MSIE HTML FormatFORMATETC* htmlFormat() { static UINT cf = RegisterClipboardFormat(L"HTML Format"); static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &htmlFormat;}FORMATETC* smartPasteFormat(){ static UINT cf = RegisterClipboardFormat(L"WebKit Smart Paste Format"); static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &htmlFormat;}static bool urlFromPath(CFStringRef path, String& url){ if (!path) return false; RetainPtr<CFURLRef> cfURL(AdoptCF, CFURLCreateWithFileSystemPath(0, path, kCFURLWindowsPathStyle, false)); if (!cfURL) return false; url = String(CFURLGetString(cfURL.get())); return true;}String getURL(IDataObject* dataObject, bool& success, String* title){ STGMEDIUM store; String url; success = false; if (getWebLocData(dataObject, url, title)) { success = true; return url; } else if (SUCCEEDED(dataObject->GetData(urlWFormat(), &store))) { //URL using unicode UChar* data = (UChar*)GlobalLock(store.hGlobal); url = extractURL(String(data), title); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } else if (SUCCEEDED(dataObject->GetData(urlFormat(), &store))) { //URL using ascii char* data = (char*)GlobalLock(store.hGlobal); url = extractURL(String(data), title); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } else if (SUCCEEDED(dataObject->GetData(filenameWFormat(), &store))) { //file using unicode wchar_t* data = (wchar_t*)GlobalLock(store.hGlobal); if (data && data[0] && (PathFileExists(data) || PathIsUNC(data))) { RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar*)data, wcslen(data))); if (urlFromPath(pathAsCFString.get(), url)) { if (title) *title = url; success = true; } } GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } else if (SUCCEEDED(dataObject->GetData(filenameFormat(), &store))) { //filename using ascii char* data = (char*)GlobalLock(store.hGlobal); if (data && data[0] && (PathFileExistsA(data) || PathIsUNCA(data))) { RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, data, kCFStringEncodingASCII)); if (urlFromPath(pathAsCFString.get(), url)) { if (title) *title = url; success = true; } } GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } return url;}String getPlainText(IDataObject* dataObject, bool& success){ STGMEDIUM store; String text; success = false; if (SUCCEEDED(dataObject->GetData(plainTextWFormat(), &store))) { //unicode text UChar* data = (UChar*)GlobalLock(store.hGlobal); text = String(data); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } else if (SUCCEEDED(dataObject->GetData(plainTextFormat(), &store))) { //ascii text char* data = (char*)GlobalLock(store.hGlobal); text = String(data); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } else { //If a file is dropped on the window, it does not provide either of the //plain text formats, so here we try to forcibly get a url. text = getURL(dataObject, success); success = true; } return text;}PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*){ //FIXME: We should be able to create fragments from files return 0;}bool containsFilenames(const IDataObject*){ //FIXME: We'll want to update this once we can produce fragments from files return false;}//Convert a String containing CF_HTML formatted text to a DocumentFragmentPassRefPtr<DocumentFragment> fragmentFromCF_HTML(Document* doc, const String& cf_html){ // obtain baseURL if present String srcURLStr("sourceURL:"); String srcURL; unsigned lineStart = cf_html.find(srcURLStr, 0, false); if (lineStart != -1) { unsigned srcEnd = cf_html.find("\n", lineStart, false); unsigned srcStart = lineStart+srcURLStr.length(); String rawSrcURL = cf_html.substring(srcStart, srcEnd-srcStart); replaceNBSPWithSpace(rawSrcURL); srcURL = rawSrcURL.stripWhiteSpace(); } // find the markup between "<!--StartFragment -->" and "<!--EndFragment -->", accounting for browser quirks unsigned markupStart = cf_html.find("<html", 0, false); unsigned tagStart = cf_html.find("startfragment", markupStart, false); unsigned fragmentStart = cf_html.find('>', tagStart) + 1; unsigned tagEnd = cf_html.find("endfragment", fragmentStart, false); unsigned fragmentEnd = cf_html.reverseFind('<', tagEnd); String markup = cf_html.substring(fragmentStart, fragmentEnd - fragmentStart).stripWhiteSpace(); return createFragmentFromMarkup(doc, markup, srcURL);}PassRefPtr<DocumentFragment> fragmentFromHTML(Document* doc, IDataObject* data) { if (!doc || !data) return 0; STGMEDIUM store; String html; String srcURL; if (SUCCEEDED(data->GetData(htmlFormat(), &store))) { //MS HTML Format parsing char* data = (char*)GlobalLock(store.hGlobal); SIZE_T dataSize = ::GlobalSize(store.hGlobal); String cf_html(UTF8Encoding().decode(data, dataSize)); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); if (PassRefPtr<DocumentFragment> fragment = fragmentFromCF_HTML(doc, cf_html)) return fragment; } if (SUCCEEDED(data->GetData(texthtmlFormat(), &store))) { //raw html UChar* data = (UChar*)GlobalLock(store.hGlobal); html = String(data); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); return createFragmentFromMarkup(doc, html, srcURL); } return 0;}bool containsHTML(IDataObject* data){ return SUCCEEDED(data->QueryGetData(texthtmlFormat())) || SUCCEEDED(data->QueryGetData(htmlFormat()));}} // namespace WebCore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -