diff --git a/src/libs/qtcreatorcdbext/knowntype.h b/src/libs/qtcreatorcdbext/knowntype.h index 2b766cfc9d6..39e8c8cd501 100644 --- a/src/libs/qtcreatorcdbext/knowntype.h +++ b/src/libs/qtcreatorcdbext/knowntype.h @@ -80,7 +80,7 @@ enum KnownType KT_QUrl = KT_Qt_Type + KT_Qt_MovableType + 31 + KT_HasSimpleDumper, KT_QIcon = KT_Qt_Type + KT_Qt_MovableType + 32, KT_QBrush = KT_Qt_Type + KT_Qt_MovableType + 33, - KT_QImage = KT_Qt_Type + KT_Qt_MovableType + 35, + KT_QImage = KT_Qt_Type + KT_HasSimpleDumper + KT_Qt_MovableType + 35, KT_QLocale = KT_Qt_Type + KT_Qt_MovableType + 36, KT_QMatrix = KT_Qt_Type + KT_Qt_MovableType + 37, KT_QRegExp = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 38, diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 2eaea005c47..ae0cdf7b24a 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -2066,6 +2066,70 @@ static bool dumpQDateTime(const SymbolGroupValue &v, std::wostream &str) return true; } +static bool dumpQImage(const SymbolGroupValue &v, std::wostream &str, MemoryHandle **memoryHandle) +{ + struct CreatorImageHeader { // Header for image display as edit format, followed by data. + int width; + int height; + int format; + }; + const QtInfo &qtInfo(QtInfo::get(v.context())); + // Fetch data of unexported private class + const ULONG64 address = v["d"].pointerValue(); + if (!address) { + str << L""; + return true; + } + const std::string qImageDataType = qtInfo.prependQtGuiModule("QImageData"); + const unsigned long size = SymbolGroupValue::sizeOf(qImageDataType.c_str()); + if (!size) + return false; + unsigned char *qImageData = SymbolGroupValue::readMemory(v.context().dataspaces, address, size); + if (!qImageData) + return false; + // read size data + unsigned char *ptr = qImageData + qAtomicIntSize(v.context()); + CreatorImageHeader header; + header.width = *(reinterpret_cast(ptr)); + ptr += SymbolGroupValue::intSize(); + header.height = *(reinterpret_cast(ptr)); + ptr += SymbolGroupValue::intSize(); + const int depth = *(reinterpret_cast(ptr)); + ptr += SymbolGroupValue::intSize(); + const int nbytes = *(reinterpret_cast(ptr)); + const unsigned dataOffset = SymbolGroupValue::fieldOffset(qImageDataType.c_str(), "data"); + // Qt 4 has a Qt 3 support pointer member between 'data' and 'format'. + const unsigned formatOffset = SymbolGroupValue::fieldOffset(qImageDataType.c_str(), "format"); + if (!dataOffset || !formatOffset) + return false; + ptr = qImageData + dataOffset; + // read data pointer + ULONG64 data = 0; + memcpy(&data, ptr, SymbolGroupValue::pointerSize()); + // read format + ptr = qImageData + formatOffset; + header.format = *(reinterpret_cast(ptr)); + if (header.width < 0 || header.height < 0 || header.format < 0 || header.format > 255 + || nbytes < 0 || depth < 0) { + return false; + } + str << header.width << L'x' << header.height << L", depth: " << depth + << L", format: " << header.format << L", " + << nbytes << L" bytes @0x" << std::hex << data << std::dec; + delete [] qImageData; + // Create Creator Image data for display if reasonable size + if (memoryHandle && data && nbytes > 0 && nbytes < 205824) { + if (unsigned char *imageData = SymbolGroupValue::readMemory(v.context().dataspaces, data, nbytes)) { + unsigned char *creatorImageData = new unsigned char[sizeof(CreatorImageHeader) + nbytes]; + memcpy(creatorImageData, &header, sizeof(CreatorImageHeader)); + memcpy(creatorImageData + sizeof(CreatorImageHeader), imageData, nbytes); + delete [] imageData; + *memoryHandle = new MemoryHandle(creatorImageData, sizeof(CreatorImageHeader) + nbytes); + } + } + return true; +} + // Dump a rectangle in X11 syntax template inline void dumpRect(std::wostream &str, T x, T y, T width, T height) @@ -2564,6 +2628,9 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, case KT_QLineF: rc = dumpQLine_F(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed; break; + case KT_QImage: + rc = dumpQImage(v, str, memoryHandleIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed; + break; case KT_QRect: rc = dumpQRect(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed; break; @@ -2654,6 +2721,11 @@ bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &, if (const MemoryHandle *mh = n->memory()) formatEditValue(DisplayLatin1String, mh, str); break; + case KT_QImage: + if (desiredFormat == 1) // Image. + if (const MemoryHandle *mh = n->memory()) + formatEditValue(DisplayImageData, mh, str); + break; } return true; } diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 383107e5065..f24a4d48461 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -625,14 +625,19 @@ void CdbEngine::setupEngine() STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed") notifyEngineSetupFailed(); } + const QString normalFormat = tr("Normal"); const QStringList stringFormats = QStringList() - << tr("Normal") << tr("Separate Window"); + << normalFormat << tr("Separate Window"); WatchHandler *wh = watchHandler(); wh->addTypeFormats("QString", stringFormats); wh->addTypeFormats("QString *", stringFormats); wh->addTypeFormats("QByteArray", stringFormats); wh->addTypeFormats("QByteArray *", stringFormats); wh->addTypeFormats("std__basic_string", stringFormats); // Python dumper naming convention for std::[w]string + const QStringList imageFormats = QStringList() + << normalFormat << tr("Image"); + wh->addTypeFormats("QImage", imageFormats); + wh->addTypeFormats("QImage *", imageFormats); } bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessage)