void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, true>& list, bool evenOdd, bool oppEvenOdd) { int count = contours.count(); if (count == 0) { return; } for (int index = 0; index < count; ++index) { SkOpContour& contour = contours[index]; contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd); list.push_back(&contour); } SkTQSort<SkOpContour>(list.begin(), list.end() - 1); }
/* check start and end of each contour if not the same, record them match them up connect closest reassemble contour pieces into new path */ void Assemble(const SkPathWriter& path, SkPathWriter* simple) { #if DEBUG_PATH_CONSTRUCTION SkDebugf("%s\n", __FUNCTION__); #endif SkTArray<SkOpContour> contours; SkOpEdgeBuilder builder(path, contours); builder.finish(); int count = contours.count(); int outer; SkTArray<int, true> runs(count); // indices of partial contours for (outer = 0; outer < count; ++outer) { const SkOpContour& eContour = contours[outer]; const SkPoint& eStart = eContour.start(); const SkPoint& eEnd = eContour.end(); #if DEBUG_ASSEMBLE SkDebugf("%s contour", __FUNCTION__); if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { SkDebugf("[%d]", runs.count()); } else { SkDebugf(" "); } SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); #endif if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { eContour.toPath(simple); continue; } runs.push_back(outer); } count = runs.count(); if (count == 0) { return; } SkTArray<int, true> sLink, eLink; sLink.push_back_n(count); eLink.push_back_n(count); int rIndex, iIndex; for (rIndex = 0; rIndex < count; ++rIndex) { sLink[rIndex] = eLink[rIndex] = SK_MaxS32; } const int ends = count * 2; // all starts and ends const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2 SkTArray<double, true> distances; distances.push_back_n(entries); for (rIndex = 0; rIndex < ends - 1; ++rIndex) { outer = runs[rIndex >> 1]; const SkOpContour& oContour = contours[outer]; const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start(); const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) * ends - rIndex - 1; for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { int inner = runs[iIndex >> 1]; const SkOpContour& iContour = contours[inner]; const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start(); double dx = iPt.fX - oPt.fX; double dy = iPt.fY - oPt.fY; double dist = dx * dx + dy * dy; distances[row + iIndex] = dist; // oStart distance from iStart } } SkTArray<int, true> sortedDist; sortedDist.push_back_n(entries); for (rIndex = 0; rIndex < entries; ++rIndex) { sortedDist[rIndex] = rIndex; } SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin())); int remaining = count; // number of start/end pairs for (rIndex = 0; rIndex < entries; ++rIndex) { int pair = sortedDist[rIndex]; int row = pair / ends; int col = pair - row * ends; int thingOne = row < col ? row : ends - row - 2; int ndxOne = thingOne >> 1; bool endOne = thingOne & 1; int* linkOne = endOne ? eLink.begin() : sLink.begin(); if (linkOne[ndxOne] != SK_MaxS32) { continue; } int thingTwo = row < col ? col : ends - row + col - 1; int ndxTwo = thingTwo >> 1; bool endTwo = thingTwo & 1; int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); if (linkTwo[ndxTwo] != SK_MaxS32) { continue; } SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); bool flip = endOne == endTwo; linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; if (!--remaining) { break; } } SkASSERT(!remaining); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < count; ++rIndex) { int s = sLink[rIndex]; int e = eLink[rIndex]; SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); } #endif rIndex = 0; do { bool forward = true; bool first = true; int sIndex = sLink[rIndex]; SkASSERT(sIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; int eIndex; if (sIndex < 0) { eIndex = sLink[~sIndex]; sLink[~sIndex] = SK_MaxS32; } else { eIndex = eLink[sIndex]; eLink[sIndex] = SK_MaxS32; } SkASSERT(eIndex != SK_MaxS32); #if DEBUG_ASSEMBLE SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', eIndex < 0 ? ~eIndex : eIndex); #endif do { outer = runs[rIndex]; const SkOpContour& contour = contours[outer]; if (first) { first = false; const SkPoint* startPtr = &contour.start(); simple->deferredMove(startPtr[0]); } if (forward) { contour.toPartialForward(simple); } else { contour.toPartialBackward(simple); } #if DEBUG_ASSEMBLE SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); #endif if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { simple->close(); break; } if (forward) { eIndex = eLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); eLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(sLink[eIndex] == rIndex); sLink[eIndex] = SK_MaxS32; } else { SkASSERT(eLink[~eIndex] == ~rIndex); eLink[~eIndex] = SK_MaxS32; } } else { eIndex = sLink[rIndex]; SkASSERT(eIndex != SK_MaxS32); sLink[rIndex] = SK_MaxS32; if (eIndex >= 0) { SkASSERT(eLink[eIndex] == rIndex); eLink[eIndex] = SK_MaxS32; } else { SkASSERT(sLink[~eIndex] == ~rIndex); sLink[~eIndex] = SK_MaxS32; } } rIndex = eIndex; if (rIndex < 0) { forward ^= 1; rIndex = ~rIndex; } } while (true); for (rIndex = 0; rIndex < count; ++rIndex) { if (sLink[rIndex] != SK_MaxS32) { break; } } } while (rIndex < count); #if DEBUG_ASSEMBLE for (rIndex = 0; rIndex < count; ++rIndex) { SkASSERT(sLink[rIndex] == SK_MaxS32); SkASSERT(eLink[rIndex] == SK_MaxS32); } #endif }
bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { #if DEBUG_SHOW_TEST_NAME char* debugName = DEBUG_FILENAME_STRING; if (debugName && debugName[0]) { SkPathOpsDebug::BumpTestName(debugName); SkPathOpsDebug::ShowPath(one, two, op, debugName); } #endif op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()]; SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()] ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType; const SkPath* minuend = &one; const SkPath* subtrahend = &two; if (op == kReverseDifference_PathOp) { minuend = &two; subtrahend = &one; op = kDifference_PathOp; } #if DEBUG_SORT || DEBUG_SWAP_TOP SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; #endif // turn path into list of segments SkTArray<SkOpContour> contours; // FIXME: add self-intersecting cubics' T values to segment SkOpEdgeBuilder builder(*minuend, contours); const int xorMask = builder.xorMask(); builder.addOperand(*subtrahend); if (!builder.finish()) { return false; } result->reset(); result->setFillType(fillType); const int xorOpMask = builder.xorMask(); SkTArray<SkOpContour*, true> contourList; MakeContourList(contours, contourList, xorMask == kEvenOdd_PathOpsMask, xorOpMask == kEvenOdd_PathOpsMask); SkOpContour** currentPtr = contourList.begin(); if (!currentPtr) { return true; } SkOpContour** listEnd = contourList.end(); // find all intersections between segments do { SkOpContour** nextPtr = currentPtr; SkOpContour* current = *currentPtr++; if (current->containsCubics()) { AddSelfIntersectTs(current); } SkOpContour* next; do { next = *nextPtr++; } while (AddIntersectTs(current, next) && nextPtr != listEnd); } while (currentPtr != listEnd); // eat through coincident edges int total = 0; int index; for (index = 0; index < contourList.count(); ++index) { total += contourList[index]->segments().count(); } HandleCoincidence(&contourList, total); // construct closed contours SkPathWriter wrapper(*result); bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); { // if some edges could not be resolved, assemble remaining fragments SkPath temp; temp.setFillType(fillType); SkPathWriter assembled(temp); Assemble(wrapper, &assembled); *result = *assembled.nativePath(); result->setFillType(fillType); } return true; }
bool SkKTXFile::WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap) { const SkColorType ct = bitmap.colorType(); SkAutoLockPixels alp(bitmap); const int width = bitmap.width(); const int height = bitmap.width(); const uint8_t* src = reinterpret_cast<uint8_t*>(bitmap.getPixels()); if (NULL == bitmap.getPixels()) { return false; } // First thing's first, write out the magic identifier and endianness... if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE) || !stream->write(&kKTX_ENDIANNESS_CODE, 4)) { return false; } // Collect our key/value pairs... SkTArray<KeyValue> kvPairs; // Next, write the header based on the bitmap's config. Header hdr; switch (ct) { case kIndex_8_SkColorType: // There is a compressed format for this, but we don't support it yet. SkDebugf("Writing indexed bitmap to KTX unsupported.\n"); // VVV fall through VVV default: case kUnknown_SkColorType: // Bitmap hasn't been configured. return false; case kAlpha_8_SkColorType: hdr.fGLType = GR_GL_UNSIGNED_BYTE; hdr.fGLTypeSize = 1; hdr.fGLFormat = GR_GL_RED; hdr.fGLInternalFormat = GR_GL_R8; hdr.fGLBaseInternalFormat = GR_GL_RED; break; case kRGB_565_SkColorType: hdr.fGLType = GR_GL_UNSIGNED_SHORT_5_6_5; hdr.fGLTypeSize = 2; hdr.fGLFormat = GR_GL_RGB; hdr.fGLInternalFormat = GR_GL_RGB; hdr.fGLBaseInternalFormat = GR_GL_RGB; break; case kARGB_4444_SkColorType: hdr.fGLType = GR_GL_UNSIGNED_SHORT_4_4_4_4; hdr.fGLTypeSize = 2; hdr.fGLFormat = GR_GL_RGBA; hdr.fGLInternalFormat = GR_GL_RGBA4; hdr.fGLBaseInternalFormat = GR_GL_RGBA; kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True")); break; case kN32_SkColorType: hdr.fGLType = GR_GL_UNSIGNED_BYTE; hdr.fGLTypeSize = 1; hdr.fGLFormat = GR_GL_RGBA; hdr.fGLInternalFormat = GR_GL_RGBA8; hdr.fGLBaseInternalFormat = GR_GL_RGBA; kvPairs.push_back(CreateKeyValue("KTXPremultipliedAlpha", "True")); break; } // Everything else in the header is shared. hdr.fPixelWidth = width; hdr.fPixelHeight = height; hdr.fNumberOfArrayElements = 0; hdr.fNumberOfFaces = 1; hdr.fNumberOfMipmapLevels = 1; // Calculate the key value data size hdr.fBytesOfKeyValueData = 0; for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) { // Key value size is the size of the key value data, // four bytes for saying how big the key value size is // and then additional bytes for padding to four byte boundary size_t kvsize = kv->size(); kvsize += 4; kvsize = (kvsize + 3) & ~3; hdr.fBytesOfKeyValueData = SkToU32(hdr.fBytesOfKeyValueData + kvsize); } // Write the header if (!stream->write(&hdr, sizeof(hdr))) { return false; } // Write out each key value pair for (KeyValue *kv = kvPairs.begin(); kv != kvPairs.end(); ++kv) { if (!kv->writeKeyAndValueForKTX(stream)) { return false; } } // Calculate the size of the data int bpp = bitmap.bytesPerPixel(); uint32_t dataSz = bpp * width * height; if (0 >= bpp) { return false; } // Write it into the buffer if (!stream->write(&dataSz, 4)) { return false; } // Write the pixel data... const uint8_t* rowPtr = src; if (kN32_SkColorType == ct) { for (int j = 0; j < height; ++j) { const uint32_t* pixelsPtr = reinterpret_cast<const uint32_t*>(rowPtr); for (int i = 0; i < width; ++i) { uint32_t pixel = pixelsPtr[i]; uint8_t dstPixel[4]; dstPixel[0] = pixel >> SK_R32_SHIFT; dstPixel[1] = pixel >> SK_G32_SHIFT; dstPixel[2] = pixel >> SK_B32_SHIFT; dstPixel[3] = pixel >> SK_A32_SHIFT; if (!stream->write(dstPixel, 4)) { return false; } } rowPtr += bitmap.rowBytes(); } } else { for (int i = 0; i < height; ++i) {