Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  nsClipboard.mm   Sprache: unbekannt

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <algorithm>

#include "mozilla/gfx/2D.h"
#include "mozilla/Logging.h"
#include "mozilla/Unused.h"

#include "gfxPlatform.h"
#include "nsArrayUtils.h"
#include "nsCOMPtr.h"
#include "nsClipboard.h"
#include "nsString.h"
#include "nsISupportsPrimitives.h"
#include "nsPrimitiveHelpers.h"
#include "nsIFile.h"
#include "nsStringStream.h"
#include "nsEscape.h"
#include "nsPrintfCString.h"
#include "nsObjCExceptions.h"
#include "imgIContainer.h"
#include "nsCocoaUtils.h"

using mozilla::gfx::DataSourceSurface;
using mozilla::gfx::SourceSurface;

mozilla::StaticRefPtr<nsITransferable> nsClipboard::sSelectionCache;
int32_t nsClipboard::sSelectionCacheChangeCount = 0;

nsClipboard::nsClipboard()
    : nsBaseClipboard(mozilla::dom::ClipboardCapabilities(
          false /* supportsSelectionClipboard */,
          true /* supportsFindClipboard */,
          true /* supportsSelectionCache */)) {}

nsClipboard::~nsClipboard() { ClearSelectionCache(); }

NS_IMPL_ISUPPORTS_INHERITED0(nsClipboard, nsBaseClipboard)

namespace {

// We separate this into its own function because after an @try, all local
// variables within that function get marked as volatile, and our C++ type
// system doesn't like volatile things.
static NSData* GetDataFromPasteboard(NSPasteboard* aPasteboard,
                                     NSString* aType) {
  NSData* data = nil;
  @try {
    data = [aPasteboard dataForType:aType];
  } @catch (NSException* e) {
    NS_WARNING(nsPrintfCString("Exception raised while getting data from the "
                               "pasteboard: \"%s - %s\"",
                               [[e name] UTF8String], [[e reason] UTF8String])
                   .get());
    mozilla::Unused << e;
  }
  return data;
}

static NSPasteboard* GetPasteboard(
    nsIClipboard::ClipboardType aWhichClipboard) {
  switch (aWhichClipboard) {
    case nsIClipboard::kGlobalClipboard:
      return [NSPasteboard generalPasteboard];
    case nsIClipboard::kFindClipboard:
      return [NSPasteboard pasteboardWithName:NSPasteboardNameFind];
    default:
      return nil;
  }
}

}  // namespace

void nsClipboard::SetSelectionCache(nsITransferable* aTransferable) {
  sSelectionCacheChangeCount++;
  sSelectionCache = aTransferable;
}

void nsClipboard::ClearSelectionCache() { SetSelectionCache(nullptr); }

NS_IMETHODIMP
nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable,
                                    ClipboardType aWhichClipboard) {
  NS_OBJC_BEGIN_TRY_BLOCK_RETURN;

  MOZ_ASSERT(aTransferable);
  MOZ_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));

  if (aWhichClipboard == kSelectionCache) {
    SetSelectionCache(aTransferable);
    return NS_OK;
  }

  NSDictionary* pasteboardOutputDict =
      PasteboardDictFromTransferable(aTransferable);
  if (!pasteboardOutputDict) return NS_ERROR_FAILURE;

  unsigned int outputCount = [pasteboardOutputDict count];
  NSArray* outputKeys = [pasteboardOutputDict allKeys];
  NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
  MOZ_ASSERT(cocoaPasteboard);
  if (aWhichClipboard == kFindClipboard) {
    NSString* stringType =
        [UTIHelper stringFromPboardType:NSPasteboardTypeString];
    [cocoaPasteboard declareTypes:[NSArray arrayWithObject:stringType]
                            owner:nil];
  } else {
    // Write everything else out to the general pasteboard.
    MOZ_ASSERT(aWhichClipboard == kGlobalClipboard);
    [cocoaPasteboard declareTypes:outputKeys owner:nil];
  }

  for (unsigned int i = 0; i < outputCount; i++) {
    NSString* currentKey = [outputKeys objectAtIndex:i];
    id currentValue = [pasteboardOutputDict valueForKey:currentKey];
    if (aWhichClipboard == kFindClipboard) {
      if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:
                                                     NSPasteboardTypeString]]) {
        [cocoaPasteboard setString:currentValue forType:currentKey];
      }
    } else {
      if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:
                                                     NSPasteboardTypeString]] ||
          [currentKey
              isEqualToString:[UTIHelper
                                  stringFromPboardType:kPublicUrlPboardType]] ||
          [currentKey
              isEqualToString:
                  [UTIHelper stringFromPboardType:kPublicUrlNamePboardType]]) {
        [cocoaPasteboard setString:currentValue forType:currentKey];
      } else if ([currentKey
                     isEqualToString:
                         [UTIHelper
                             stringFromPboardType:kUrlsWithTitlesPboardType]]) {
        [cocoaPasteboard
            setPropertyList:[pasteboardOutputDict valueForKey:currentKey]
                    forType:currentKey];
      } else if ([currentKey
                     isEqualToString:[UTIHelper stringFromPboardType:
                                                    NSPasteboardTypeHTML]]) {
        [cocoaPasteboard
            setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
              forType:currentKey];
      } else if ([currentKey
                     isEqualToString:[UTIHelper stringFromPboardType:
                                                    kMozFileUrlsPboardType]]) {
        [cocoaPasteboard writeObjects:currentValue];
      } else if ([currentKey
                     isEqualToString:
                         [UTIHelper
                             stringFromPboardType:(NSString*)kUTTypeFileURL]]) {
        [cocoaPasteboard setString:currentValue forType:currentKey];
      } else if ([currentKey
                     isEqualToString:
                         [UTIHelper
                             stringFromPboardType:kPasteboardConcealedType]]) {
        // It's fine to set the data to null for this field - this field is an
        // addition to a value's other type and works like a flag.
        [cocoaPasteboard setData:NULL forType:currentKey];
      } else {
        [cocoaPasteboard setData:currentValue forType:currentKey];
      }
    }
  }

  return NS_OK;

  NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
}

nsresult nsClipboard::TransferableFromPasteboard(
    nsITransferable* aTransferable, NSPasteboard* cocoaPasteboard) {
  NS_OBJC_BEGIN_TRY_BLOCK_RETURN;

  // get flavor list that includes all acceptable flavors (including ones
  // obtained through conversion)
  nsTArray<nsCString> flavors;
  nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
  if (NS_FAILED(rv)) return NS_ERROR_FAILURE;

  for (uint32_t i = 0; i < flavors.Length(); i++) {
    nsCString& flavorStr = flavors[i];

    // printf("looking for clipboard data of type %s\n", flavorStr.get());

    NSString* pboardType = nil;
    if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
      NSString* pString = [cocoaPasteboard stringForType:pboardType];
      if (!pString) {
        continue;
      }

      NSData* stringData;
      bool isRTF = [pboardType
          isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]];
      if (isRTF) {
        stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
      } else {
        stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
      }
      unsigned int dataLength = [stringData length];
      void* clipboardDataPtr = malloc(dataLength);
      if (!clipboardDataPtr) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
      [stringData getBytes:clipboardDataPtr length:dataLength];

      // The DOM only wants LF, so convert from MacOS line endings to DOM line
      // endings.
      int32_t signedDataLength = dataLength;
      nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
          isRTF, &clipboardDataPtr, &signedDataLength);
      dataLength = signedDataLength;

      // skip BOM (Byte Order Mark to distinguish little or big endian)
      char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
      if ((dataLength > 2) && ((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
                               (clipboardDataPtrNoBOM[0] == 0xFFFE))) {
        dataLength -= sizeof(char16_t);
        clipboardDataPtrNoBOM += 1;
      }

      nsCOMPtr<nsISupports> genericDataWrapper;
      nsPrimitiveHelpers::CreatePrimitiveForData(
          flavorStr, clipboardDataPtrNoBOM, dataLength,
          getter_AddRefs(genericDataWrapper));
      aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
      free(clipboardDataPtr);
      break;
    } else if (flavorStr.EqualsLiteral(kFileMime)) {
      NSArray* items = [cocoaPasteboard pasteboardItems];
      if (!items || [items count] <= 0) {
        continue;
      }

      // XXX we don't support multiple clipboard item on DOM and XPCOM interface
      // for now, so we only get the data from the first pasteboard item.
      NSPasteboardItem* item = [items objectAtIndex:0];
      if (!item) {
        continue;
      }

      nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable,
                                                             flavorStr, item);
    } else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
      NSString* type = [cocoaPasteboard
          availableTypeFromArray:
              [NSArray
                  arrayWithObject:[UTIHelper stringFromPboardType:
                                                 kMozCustomTypesPboardType]]];
      if (!type) {
        continue;
      }

      NSData* pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
      if (!pasteboardData) {
        continue;
      }

      unsigned int dataLength = [pasteboardData length];
      void* clipboardDataPtr = malloc(dataLength);
      if (!clipboardDataPtr) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
      [pasteboardData getBytes:clipboardDataPtr length:dataLength];

      nsCOMPtr<nsISupports> genericDataWrapper;
      nsPrimitiveHelpers::CreatePrimitiveForData(
          flavorStr, clipboardDataPtr, dataLength,
          getter_AddRefs(genericDataWrapper));

      aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
      free(clipboardDataPtr);
    } else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
               flavorStr.EqualsLiteral(kJPGImageMime) ||
               flavorStr.EqualsLiteral(kPNGImageMime) ||
               flavorStr.EqualsLiteral(kGIFImageMime)) {
      // Figure out if there's data on the pasteboard we can grab (sanity check)
      NSString* type = [cocoaPasteboard
          availableTypeFromArray:
              [NSArray
                  arrayWithObjects:
                      [UTIHelper
                          stringFromPboardType:(NSString*)kUTTypeFileURL],
                      [UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
                      [UTIHelper stringFromPboardType:NSPasteboardTypePNG],
                      nil]];
      if (!type) continue;

      // Read data off the clipboard
      NSData* pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
      if (!pasteboardData) continue;

      // Figure out what type we're converting to
      CFStringRef outputType = NULL;
      if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
          flavorStr.EqualsLiteral(kJPGImageMime))
        outputType = CFSTR("public.jpeg");
      else if (flavorStr.EqualsLiteral(kPNGImageMime))
        outputType = CFSTR("public.png");
      else if (flavorStr.EqualsLiteral(kGIFImageMime))
        outputType = CFSTR("com.compuserve.gif");
      else
        continue;

      // Use ImageIO to interpret the data on the clipboard and transcode.
      // Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
      // and safely in most cases (like ObjC). A notable exception is CFRelease.
      NSDictionary* options = [NSDictionary
          dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue,
                                       kCGImageSourceShouldAllowFloat, type,
                                       kCGImageSourceTypeIdentifierHint, nil];
      CGImageSourceRef source = nullptr;
      if (type == [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]) {
        NSString* urlStr = [cocoaPasteboard stringForType:type];
        NSURL* url = [NSURL URLWithString:urlStr];
        source =
            CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options);
      } else {
        source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
                                             (CFDictionaryRef)options);
      }

      NSMutableData* encodedData = [NSMutableData data];
      CGImageDestinationRef dest = CGImageDestinationCreateWithData(
          (CFMutableDataRef)encodedData, outputType, 1, NULL);
      CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
      bool successfullyConverted = CGImageDestinationFinalize(dest);

      if (successfullyConverted) {
        // Put the converted data in a form Gecko can understand
        nsCOMPtr<nsIInputStream> byteStream;
        NS_NewByteInputStream(getter_AddRefs(byteStream),
                              mozilla::Span((const char*)[encodedData bytes],
                                            [encodedData length]),
                              NS_ASSIGNMENT_COPY);

        aTransferable->SetTransferData(flavorStr.get(), byteStream);
      }

      if (dest) CFRelease(dest);
      if (source) CFRelease(source);

      if (successfullyConverted) {
        // XXX Maybe try to fill in more types? Is there a point?
        break;
      } else {
        continue;
      }
    }
  }

  return NS_OK;

  NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
}

NS_IMETHODIMP
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
                                    ClipboardType aWhichClipboard) {
  NS_OBJC_BEGIN_TRY_BLOCK_RETURN;

  MOZ_DIAGNOSTIC_ASSERT(aTransferable);
  MOZ_DIAGNOSTIC_ASSERT(
      nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));

  if (kSelectionCache == aWhichClipboard) {
    if (!sSelectionCache) {
      return NS_OK;
    }

    // get flavor list that includes all acceptable flavors (including ones
    // obtained through conversion)
    nsTArray<nsCString> flavors;
    nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
    if (NS_FAILED(rv)) {
      return NS_ERROR_FAILURE;
    }

    for (const auto& flavor : flavors) {
      nsCOMPtr<nsISupports> dataSupports;
      rv = sSelectionCache->GetTransferData(flavor.get(),
                                            getter_AddRefs(dataSupports));
      if (NS_SUCCEEDED(rv)) {
        MOZ_CLIPBOARD_LOG("%s: getting %s from cache.", __FUNCTION__,
                          flavor.get());
        aTransferable->SetTransferData(flavor.get(), dataSupports);
        // XXX Maybe try to fill in more types? Is there a point?
        break;
      }
    }
    return NS_OK;
  }

  NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
  if (!cocoaPasteboard) {
    return NS_ERROR_FAILURE;
  }

  return TransferableFromPasteboard(aTransferable, cocoaPasteboard);

  NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
}

// returns true if we have *any* of the passed in flavors available for pasting
mozilla::Result<bool, nsresult>
nsClipboard::HasNativeClipboardDataMatchingFlavors(
    const nsTArray<nsCString>& aFlavorList, ClipboardType aWhichClipboard) {
  NS_OBJC_BEGIN_TRY_BLOCK_RETURN;

  MOZ_DIAGNOSTIC_ASSERT(
      nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));

  if (kSelectionCache == aWhichClipboard) {
    nsTArray<nsCString> transferableFlavors;
    if (sSelectionCache &&
        NS_SUCCEEDED(sSelectionCache->FlavorsTransferableCanExport(
            transferableFlavors))) {
      if (MOZ_CLIPBOARD_LOG_ENABLED()) {
        MOZ_CLIPBOARD_LOG("    SelectionCache types (nums %zu)\n",
                          transferableFlavors.Length());
        for (const auto& transferableFlavor : transferableFlavors) {
          MOZ_CLIPBOARD_LOG("        MIME %s", transferableFlavor.get());
        }
      }

      for (const auto& transferableFlavor : transferableFlavors) {
        for (const auto& flavor : aFlavorList) {
          if (transferableFlavor.Equals(flavor)) {
            MOZ_CLIPBOARD_LOG("    has %s", flavor.get());
            return true;
          }
        }
      }
    }

    if (MOZ_CLIPBOARD_LOG_ENABLED()) {
      MOZ_CLIPBOARD_LOG("    no targets at clipboard (bad match)\n");
    }

    return false;
  }

  NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
  MOZ_ASSERT(cocoaPasteboard);
  if (MOZ_CLIPBOARD_LOG_ENABLED()) {
    NSArray* types = [cocoaPasteboard types];
    uint32_t count = [types count];
    MOZ_CLIPBOARD_LOG("    Pasteboard types (nums %d)\n", count);
    for (uint32_t i = 0; i < count; i++) {
      NSPasteboardType type = [types objectAtIndex:i];
      if (!type) {
        MOZ_CLIPBOARD_LOG("        failed to get MIME\n");
        continue;
      }
      MOZ_CLIPBOARD_LOG("        MIME %s\n", [type UTF8String]);
    }
  }

  for (auto& mimeType : aFlavorList) {
    NSString* pboardType = nil;
    if (nsClipboard::IsStringType(mimeType, &pboardType)) {
      NSString* availableType = [cocoaPasteboard
          availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
      if (availableType && [availableType isEqualToString:pboardType]) {
        MOZ_CLIPBOARD_LOG("    has %s\n", mimeType.get());
        return true;
      }
    } else if (mimeType.EqualsLiteral(kCustomTypesMime)) {
      NSString* availableType = [cocoaPasteboard
          availableTypeFromArray:
              [NSArray
                  arrayWithObject:[UTIHelper stringFromPboardType:
                                                 kMozCustomTypesPboardType]]];
      if (availableType) {
        MOZ_CLIPBOARD_LOG("    has %s\n", mimeType.get());
        return true;
      }
    } else if (mimeType.EqualsLiteral(kJPEGImageMime) ||
               mimeType.EqualsLiteral(kJPGImageMime) ||
               mimeType.EqualsLiteral(kPNGImageMime) ||
               mimeType.EqualsLiteral(kGIFImageMime)) {
      NSString* availableType = [cocoaPasteboard
          availableTypeFromArray:
              [NSArray
                  arrayWithObjects:
                      [UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
                      [UTIHelper stringFromPboardType:NSPasteboardTypePNG],
                      nil]];
      if (availableType) {
        MOZ_CLIPBOARD_LOG("    has %s\n", mimeType.get());
        return true;
      }
    } else if (mimeType.EqualsLiteral(kFileMime)) {
      NSArray* items = [cocoaPasteboard pasteboardItems];
      if (items && [items count] > 0) {
        // XXX we only check the first pasteboard item as we only get data from
        // first item in TransferableFromPasteboard for now.
        if (NSPasteboardItem* item = [items objectAtIndex:0]) {
          if ([item availableTypeFromArray:
                        [NSArray
                            arrayWithObjects:[UTIHelper
                                                 stringFromPboardType:
                                                     (NSString*)kUTTypeFileURL],
                                             nil]]) {
            MOZ_CLIPBOARD_LOG("    has %s\n", mimeType.get());
            return true;
          }
        }
      }
    }
  }

  if (MOZ_CLIPBOARD_LOG_ENABLED()) {
    MOZ_CLIPBOARD_LOG("    no targets at clipboard (bad match)\n");
  }

  return false;

  NS_OBJC_END_TRY_BLOCK_RETURN(mozilla::Err(NS_ERROR_FAILURE));
}

// static
mozilla::Maybe<uint32_t> nsClipboard::FindIndexOfImageFlavor(
    const nsTArray<nsCString>& aMIMETypes) {
  for (uint32_t i = 0; i < aMIMETypes.Length(); ++i) {
    if (nsClipboard::IsImageType(aMIMETypes[i])) {
      return mozilla::Some(i);
    }
  }

  return mozilla::Nothing();
}

// This function converts anything that other applications might understand into
// the system format and puts it into a dictionary which it returns. static
NSDictionary* nsClipboard::PasteboardDictFromTransferable(
    nsITransferable* aTransferable) {
  NS_OBJC_BEGIN_TRY_BLOCK_RETURN;

  if (!aTransferable) {
    return nil;
  }

  NSMutableDictionary* pasteboardOutputDict = [NSMutableDictionary dictionary];

  nsTArray<nsCString> flavors;
  nsresult rv = aTransferable->FlavorsTransferableCanExport(flavors);
  if (NS_FAILED(rv)) {
    return nil;
  }

  const mozilla::Maybe<uint32_t> imageFlavorIndex =
      nsClipboard::FindIndexOfImageFlavor(flavors);

  if (imageFlavorIndex) {
    // When right-clicking and "Copy Image" is clicked on macOS, some apps
    // expect the first flavor to be the image flavor. See bug 1689992. For
    // other apps, the order shouldn't matter.
    std::swap(*flavors.begin(), flavors[*imageFlavorIndex]);
  }
  for (uint32_t i = 0; i < flavors.Length(); i++) {
    nsCString& flavorStr = flavors[i];

    MOZ_CLIPBOARD_LOG("writing out clipboard data of type %s (%d)\n",
                      flavorStr.get(), i);

    NSString* pboardType = nil;
    if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
      nsCOMPtr<nsISupports> genericDataWrapper;
      rv = aTransferable->GetTransferData(flavorStr.get(),
                                          getter_AddRefs(genericDataWrapper));
      if (NS_FAILED(rv)) {
        continue;
      }

      nsAutoString data;
      if (nsCOMPtr<nsISupportsString> text =
              do_QueryInterface(genericDataWrapper)) {
        text->GetData(data);
      }

      NSString* nativeString;
      if (!data.IsEmpty()) {
        nativeString = [NSString stringWithCharacters:(const unichar*)data.get()
                                               length:data.Length()];
      } else {
        nativeString = [NSString string];
      }

      // be nice to Carbon apps, normalize the receiver's contents using Form C.
      nativeString = [nativeString precomposedStringWithCanonicalMapping];
      if (nativeString) {
        [pasteboardOutputDict setObject:nativeString forKey:pboardType];
      }

      if (aTransferable->GetIsPrivateData()) {
        // In the case of password strings, we want to include the key for
        // concealed type. These will be flagged as private data.
        [pasteboardOutputDict
            setObject:nativeString
               forKey:[UTIHelper
                          stringFromPboardType:kPasteboardConcealedType]];
      }
    } else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
      nsCOMPtr<nsISupports> genericDataWrapper;
      rv = aTransferable->GetTransferData(flavorStr.get(),
                                          getter_AddRefs(genericDataWrapper));
      if (NS_FAILED(rv)) {
        continue;
      }

      nsAutoCString data;
      if (nsCOMPtr<nsISupportsCString> text =
              do_QueryInterface(genericDataWrapper)) {
        text->GetData(data);
      }

      if (!data.IsEmpty()) {
        NSData* nativeData = [NSData dataWithBytes:data.get()
                                            length:data.Length()];
        NSString* customType =
            [UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
        if (!nativeData) {
          continue;
        }
        [pasteboardOutputDict setObject:nativeData forKey:customType];
      }
    } else if (nsClipboard::IsImageType(flavorStr)) {
      nsCOMPtr<nsISupports> transferSupports;
      rv = aTransferable->GetTransferData(flavorStr.get(),
                                          getter_AddRefs(transferSupports));
      if (NS_FAILED(rv)) {
        continue;
      }

      nsCOMPtr<imgIContainer> image(do_QueryInterface(transferSupports));
      if (!image) {
        NS_WARNING("Image isn't an imgIContainer in transferable");
        continue;
      }

      RefPtr<SourceSurface> surface = image->GetFrame(
          imgIContainer::FRAME_CURRENT,
          imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
      if (!surface) {
        continue;
      }
      CGImageRef imageRef = NULL;
      rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef);
      if (NS_FAILED(rv) || !imageRef) {
        continue;
      }

      // Convert the CGImageRef to TIFF and PNG data.
      CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
      CFMutableDataRef pngData = CFDataCreateMutable(kCFAllocatorDefault, 0);
      CGImageDestinationRef destRefTIFF = CGImageDestinationCreateWithData(
          tiffData, CFSTR("public.tiff"), 1, NULL);
      CGImageDestinationRef destRefPNG = CGImageDestinationCreateWithData(
          pngData, CFSTR("public.png"), 1, NULL);
      CGImageDestinationAddImage(destRefTIFF, imageRef, NULL);
      CGImageDestinationAddImage(destRefPNG, imageRef, NULL);
      const bool successfullyConvertedTIFF =
          CGImageDestinationFinalize(destRefTIFF);
      const bool successfullyConvertedPNG =
          CGImageDestinationFinalize(destRefPNG);

      CGImageRelease(imageRef);
      if (destRefTIFF) {
        CFRelease(destRefTIFF);
      }
      if (destRefPNG) {
        CFRelease(destRefPNG);
      }

      if (successfullyConvertedTIFF && tiffData) {
        NSString* tiffType =
            [UTIHelper stringFromPboardType:NSPasteboardTypeTIFF];
        [pasteboardOutputDict setObject:(NSMutableData*)tiffData
                                 forKey:tiffType];
      }
      if (successfullyConvertedPNG && pngData) {
        NSString* pngType =
            [UTIHelper stringFromPboardType:NSPasteboardTypePNG];

        [pasteboardOutputDict setObject:(NSMutableData*)pngData forKey:pngType];
      }
      if (tiffData) {
        CFRelease(tiffData);
      }
      if (pngData) {
        CFRelease(pngData);
      }
    } else if (flavorStr.EqualsLiteral(kFileMime)) {
      nsCOMPtr<nsISupports> genericFile;
      rv = aTransferable->GetTransferData(flavorStr.get(),
                                          getter_AddRefs(genericFile));
      if (NS_FAILED(rv)) {
        continue;
      }

      nsCOMPtr<nsIFile> file(do_QueryInterface(genericFile));
      if (!file) {
        continue;
      }

      nsAutoString fileURI;
      rv = file->GetPath(fileURI);
      if (NS_FAILED(rv)) {
        continue;
      }

      NSString* str = nsCocoaUtils::ToNSString(fileURI);
      NSURL* url = [NSURL fileURLWithPath:str isDirectory:NO];
      if (!url || ![url absoluteString]) {
        continue;
      }
      NSString* fileUTType =
          [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL];
      [pasteboardOutputDict setObject:[url absoluteString] forKey:fileUTType];
    } else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
      NSString* urlPromise = [UTIHelper
          stringFromPboardType:(NSString*)kPasteboardTypeFileURLPromise];
      NSString* urlPromiseContent = [UTIHelper
          stringFromPboardType:(NSString*)kPasteboardTypeFilePromiseContent];
      [pasteboardOutputDict setObject:[NSArray arrayWithObject:@""]
                               forKey:urlPromise];
      [pasteboardOutputDict setObject:[NSArray arrayWithObject:@""]
                               forKey:urlPromiseContent];
    } else if (flavorStr.EqualsLiteral(kURLMime)) {
      nsCOMPtr<nsISupports> genericURL;
      rv = aTransferable->GetTransferData(flavorStr.get(),
                                          getter_AddRefs(genericURL));
      nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL));

      nsAutoString url;
      urlObject->GetData(url);

      NSString* nativeTitle = nil;

      // A newline embedded in the URL means that the form is actually URL +
      // title. This embedding occurs in nsDragService::GetData.
      int32_t newlinePos = url.FindChar(char16_t('\n'));
      if (newlinePos >= 0) {
        url.Truncate(newlinePos);

        nsAutoString urlTitle;
        urlObject->GetData(urlTitle);
        urlTitle.Mid(urlTitle, newlinePos + 1,
                     urlTitle.Length() - (newlinePos + 1));

        nativeTitle =
            [NSString stringWithCharacters:reinterpret_cast<const unichar*>(
                                               urlTitle.get())
                                    length:urlTitle.Length()];
      }
      // The Finder doesn't like getting random binary data aka
      // Unicode, so change it into an escaped URL containing only
      // ASCII.
      nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length());
      nsAutoCString escData;
      NS_EscapeURL(utf8Data.get(), utf8Data.Length(),
                   esc_OnlyNonASCII | esc_AlwaysCopy, escData);

      NSString* nativeURL = [NSString stringWithUTF8String:escData.get()];
      NSString* publicUrl =
          [UTIHelper stringFromPboardType:kPublicUrlPboardType];
      if (!nativeURL) {
        continue;
      }
      [pasteboardOutputDict setObject:nativeURL forKey:publicUrl];
      if (nativeTitle) {
        NSArray* urlsAndTitles = @[ @[ nativeURL ], @[ nativeTitle ] ];
        NSString* urlName =
            [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
        NSString* urlsWithTitles =
            [UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType];
        [pasteboardOutputDict setObject:nativeTitle forKey:urlName];
        [pasteboardOutputDict setObject:urlsAndTitles forKey:urlsWithTitles];
      }
    }
    // If it wasn't a type that we recognize as exportable we don't put it on
    // the system clipboard. We'll just access it from our cached transferable
    // when we need it.
  }

  return pasteboardOutputDict;

  NS_OBJC_END_TRY_BLOCK_RETURN(nil);
}

bool nsClipboard::IsStringType(const nsCString& aMIMEType,
                               NSString** aPboardType) {
  if (aMIMEType.EqualsLiteral(kTextMime)) {
    *aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
    return true;
  } else if (aMIMEType.EqualsLiteral(kRTFMime)) {
    *aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeRTF];
    return true;
  } else if (aMIMEType.EqualsLiteral(kHTMLMime)) {
    *aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeHTML];
    return true;
  } else {
    return false;
  }
}

// static
bool nsClipboard::IsImageType(const nsACString& aMIMEType) {
  return aMIMEType.EqualsLiteral(kPNGImageMime) ||
         aMIMEType.EqualsLiteral(kJPEGImageMime) ||
         aMIMEType.EqualsLiteral(kJPGImageMime) ||
         aMIMEType.EqualsLiteral(kGIFImageMime) ||
         aMIMEType.EqualsLiteral(kNativeImageMime);
}

NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString) {
  NSString* wrapped =
      [NSString stringWithFormat:@"<html>"
                                  "<head>"
                                  "<meta http-equiv=\"content-type\" "
                                  "content=\"text/html; charset=utf-8\">"
                                  "</head>"
                                  "<body>"
                                  "%@"
                                  "</body>"
                                  "</html>",
                                 aString];
  return wrapped;
}

nsresult nsClipboard::EmptyNativeClipboardData(ClipboardType aWhichClipboard) {
  NS_OBJC_BEGIN_TRY_BLOCK_RETURN;

  MOZ_DIAGNOSTIC_ASSERT(
      nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));

  if (kSelectionCache == aWhichClipboard) {
    ClearSelectionCache();
    return NS_OK;
  }

  if (NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard)) {
    [cocoaPasteboard clearContents];
  }

  return NS_OK;

  NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
}

mozilla::Result<int32_t, nsresult>
nsClipboard::GetNativeClipboardSequenceNumber(ClipboardType aWhichClipboard) {
  NS_OBJC_BEGIN_TRY_BLOCK_RETURN;

  MOZ_DIAGNOSTIC_ASSERT(
      nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));

  if (kSelectionCache == aWhichClipboard) {
    return sSelectionCacheChangeCount;
  }

  NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
  if (!cocoaPasteboard) {
    return mozilla::Err(NS_ERROR_FAILURE);
  }

  return [cocoaPasteboard changeCount];

  NS_OBJC_END_TRY_BLOCK_RETURN(mozilla::Err(NS_ERROR_FAILURE));
}

[ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge