void srTGenTrjDat::CompTrjKickMatr(SRWLKickM* arKickM, int nKickM, double sStart, double sEnd, long ns, double* pInPrecPar, double* pOutBtX, double* pOutX, double* pOutBtY, double* pOutY, double* pOutBtZ, double* pOutZ) { if((arKickM == 0) || (nKickM <= 0)) throw SRWL_INCORRECT_PARAM_FOR_TRJ_COMP; if(ns <= 0) throw SRWL_INCORRECT_PARAM_FOR_TRJ_COMP; //sort arKickM to find groups of kick-matrices with non-overlapping longitudinal intervals vector<pair<int, pair<double, double> > > vKickStInd; SRWLKickM *t_arKickM = arKickM; for(int i=0; i<nKickM; i++) { double curHalfRange = 0.5*t_arKickM->rz; pair<double, double> curRange(t_arKickM->z - curHalfRange, t_arKickM->z + curHalfRange); pair<int, pair<double, double> > curPair(i, curRange); vKickStInd.push_back(curPair); } sort(vKickStInd.begin(), vKickStInd.end(), CAuxParse::LessInPairBasedOnFirstInNestedPair<int, double, double>); vector<vector<int> > vIndNonOverlapKickGroups; vector<pair<double, double> > vIndNonOverlapKickGroupRanges; vector<int> vIndKickM; vIndKickM.push_back(vKickStInd[0].first); double curGroupStart = vKickStInd[0].second.first; double curGroupEnd = vKickStInd[0].second.second; for(int j=1; j<nKickM; j++) { double newStart = vKickStInd[j].second.first; double newEnd = vKickStInd[j].second.second; if((newEnd <= curGroupStart) || (newStart >= curGroupEnd)) {//end current group vIndNonOverlapKickGroups.push_back(vIndKickM); pair<double, double> curRange(curGroupStart, curGroupEnd); vIndNonOverlapKickGroupRanges.push_back(curRange); vIndKickM.erase(vIndKickM.begin(), vIndKickM.end()); curGroupStart = newStart; curGroupEnd = newEnd; } else {//continue stuffing current group vIndKickM.push_back(vKickStInd[j].first); if(curGroupStart > newStart) curGroupStart = newStart; if(curGroupEnd < newEnd) curGroupEnd = newEnd; } } if(!vIndKickM.empty()) { vIndNonOverlapKickGroups.push_back(vIndKickM); pair<double, double> curRange(curGroupStart, curGroupEnd); vIndNonOverlapKickGroupRanges.push_back(curRange); vIndKickM.erase(vIndKickM.begin(), vIndKickM.end()); } //sorting completed bool trjShouldBeAdded = (pInPrecPar[0] == 1); const double sResEdgeToler = 1.E-12; double sAbsEdgeToler = (sEnd - sStart)*sResEdgeToler; bool integOnLeftIsNeeded = (sStart < -sAbsEdgeToler); bool integOnRightIsNeeded = (sEnd > sAbsEdgeToler); double sStep = (ns <= 1)? 0 : (sEnd - sStart)/(ns - 1); double initCond[] = {EbmDat.x0, EbmDat.dxds0, EbmDat.z0, EbmDat.dzds0, EbmDat.s0}; //? double inv_B_pho = EbmDat.Inv_B_rho(); //[1/(T*m)] double gamEm2 = EbmDat.GammaEm2, btx, bty; long is0 = 0; double s0Act = 0.; if(integOnLeftIsNeeded) { double *tOutBtX = pOutBtX, *tOutX = pOutX; double *tOutBtY = pOutBtY, *tOutY = pOutY; double *tOutBtZ = pOutBtZ, *tOutZ = pOutZ; if(sEnd < -sAbsEdgeToler) //i.e. < 0 {//need to "arrive" to sEnd without storing trajectory data; step can be re-adjusted long auxNp = (long)fabs(sEnd/sStep) + 1; if(auxNp <= 1) auxNp = 2; double *auxTrjRes = new double[(auxNp + ns)*5]; if(auxTrjRes == 0) throw MEMORY_ALLOCATION_FAILURE; IntegrateKicks(arKickM, vIndNonOverlapKickGroups, vIndNonOverlapKickGroupRanges, inv_B_pho, initCond, 0., sEnd, auxNp, auxTrjRes); //gmIntRK.solve(initCond, 0., sMax, auxNp, auxTrjRes); double *pResEnd = auxTrjRes + (auxNp - 1)*5; for(int i=0; i<5; i++) initCond[i] = pResEnd[i]; //arrived to sMax; now solve for the entire main trajectory: if(ns <= 1) { double *t_auxTrjRes = auxTrjRes; for(int i=0; i<5; i++) *(t_auxTrjRes++) = initCond[i]; } else IntegrateKicks(arKickM, vIndNonOverlapKickGroups, vIndNonOverlapKickGroupRanges, inv_B_pho, initCond, sEnd, sStart, ns, auxTrjRes); //else gmIntRK.solve(initCond, sMax, sMin, ns, auxTrjRes); double *t_auxTrjRes = auxTrjRes + (ns*5 - 1); for(int j=0; j<ns; j++) { if(trjShouldBeAdded) { //if(pOutZ) *(tOutZ++) += *t_auxTrjRes; //longitudinal position is not modified in this case t_auxTrjRes--; *tOutBtY += *(t_auxTrjRes--); bty = *(tOutBtY++); *(tOutY++) += *(t_auxTrjRes--); *tOutBtX += *(t_auxTrjRes--); btx = *(tOutBtX++); *(tOutX++) += *(t_auxTrjRes--); if(pOutBtZ) *(tOutBtZ++) = CGenMathMeth::radicalOnePlusSmall(-(gamEm2 + btx*btx + bty*bty)); } else { if(pOutZ) *(tOutZ++) = *t_auxTrjRes; t_auxTrjRes--; bty = *(t_auxTrjRes--); *(tOutBtY++) = bty; *(tOutY++) = *(t_auxTrjRes--); btx = *(t_auxTrjRes--); *(tOutBtX++) = btx; *(tOutX++) = *(t_auxTrjRes--); if(pOutBtZ) *(tOutBtZ++) = CGenMathMeth::radicalOnePlusSmall(-(gamEm2 + btx*btx + bty*bty)); } } delete[] auxTrjRes; } else { is0 = (int)fabs((-sStart + sAbsEdgeToler)/sStep); if(is0 >= ns) is0 = ns - 1; s0Act = sStart + is0*sStep; if(s0Act < -sAbsEdgeToler) {//one small step to s0Act double twoPtTrjRes[2*5]; IntegrateKicks(arKickM, vIndNonOverlapKickGroups, vIndNonOverlapKickGroupRanges, inv_B_pho, initCond, 0., s0Act, 2, twoPtTrjRes); //gmIntRK.solve(initCond, 0., s0Act, 2, twoPtTrjRes); double *pResEnd = twoPtTrjRes + 5; for(int i=0; i<5; i++) initCond[i] = pResEnd[i]; } //arrived to s0Act; now solve for the left part of the trajectory: int nsLeft = is0 + 1; double *auxTrjRes = new double[nsLeft*5]; if(auxTrjRes == 0) throw MEMORY_ALLOCATION_FAILURE; if(nsLeft <= 1) { double *t_auxTrjRes = auxTrjRes; //*(t_auxTrjRes++) = s0Act; for(int i=0; i<5; i++) *(t_auxTrjRes++) = initCond[i]; } else IntegrateKicks(arKickM, vIndNonOverlapKickGroups, vIndNonOverlapKickGroupRanges, inv_B_pho, initCond, s0Act, sStart, nsLeft, auxTrjRes); //else gmIntRK.solve(initCond, s0Act, sMin, nsLeft, auxTrjRes); double *t_auxTrjRes = auxTrjRes + nsLeft*5 - 1; for(int j=0; j<nsLeft; j++) { if(trjShouldBeAdded) { //if(pOutZ) *(tOutZ++) += *t_auxTrjRes; //longitudinal position is not modified in this case t_auxTrjRes--; *tOutBtY += *(t_auxTrjRes--); bty = *(tOutBtY++); *(tOutY++) += *(t_auxTrjRes--); *tOutBtX += *(t_auxTrjRes--); btx = *(tOutBtX++); *(tOutX++) += *(t_auxTrjRes--); if(pOutBtZ) *(tOutBtZ++) = CGenMathMeth::radicalOnePlusSmall(-(gamEm2 + btx*btx + bty*bty)); } else { if(pOutZ) *(tOutZ++) = *t_auxTrjRes; t_auxTrjRes--; bty = *(t_auxTrjRes--); *(tOutBtY++) = bty; *(tOutY++) = *(t_auxTrjRes--); btx = *(t_auxTrjRes--); *(tOutBtX++) = btx; *(tOutX++) = *(t_auxTrjRes--); if(pOutBtZ) *(tOutBtZ++) = CGenMathMeth::radicalOnePlusSmall(-(gamEm2 + btx*btx + bty*bty)); } } delete[] auxTrjRes; } } if(integOnRightIsNeeded) { double *tOutBtX = pOutBtX + is0, *tOutX = pOutX + is0; double *tOutBtY = pOutBtY + is0, *tOutY = pOutY + is0; double *tOutBtZ = pOutBtZ + is0, *tOutZ = pOutZ + is0; if(sStart > sAbsEdgeToler) {//need to "arrive" to sMin without storing trajectory data; step can be re-adjusted int auxNp = (int)fabs(sStart/sStep) + 1; if(auxNp <= 1) auxNp = 2; double *auxTrjRes = new double[(auxNp + ns)*5]; if(auxTrjRes == 0) throw MEMORY_ALLOCATION_FAILURE; IntegrateKicks(arKickM, vIndNonOverlapKickGroups, vIndNonOverlapKickGroupRanges, inv_B_pho, initCond, 0., sStart, auxNp, auxTrjRes); //gmIntRK.solve(initCond, 0., sMin, auxNp, auxTrjRes); double *pResEnd = auxTrjRes + (auxNp - 1)*5; for(int i=0; i<5; i++) initCond[i] = pResEnd[i]; //arrived to sMax; now solve for the entire main trajectory: if(ns <= 1) { double *t_auxTrjRes = auxTrjRes; //*(t_auxTrjRes++) = sMin; for(int i=0; i<5; i++) *(t_auxTrjRes++) = initCond[i]; } else IntegrateKicks(arKickM, vIndNonOverlapKickGroups, vIndNonOverlapKickGroupRanges, inv_B_pho, initCond, sStart, sEnd, ns, auxTrjRes); //else gmIntRK.solve(initCond, sMin, sMax, ns, auxTrjRes); double *t_auxTrjRes = auxTrjRes; for(int j=0; j<ns; j++) { if(trjShouldBeAdded) { *(tOutX++) += *(t_auxTrjRes++); *tOutBtX += *(t_auxTrjRes++); btx = *(tOutBtX++); *(tOutY++) += *(t_auxTrjRes++); *tOutBtY += *(t_auxTrjRes++); bty = *(tOutBtY++); //if(pOutZ) *(tOutZ++) += *t_auxTrjRes; //longitudinal position is not modified in this case t_auxTrjRes++; if(pOutBtZ) *(tOutBtZ++) = CGenMathMeth::radicalOnePlusSmall(-(gamEm2 + btx*btx + bty*bty)); } else { *(tOutX++) = *(t_auxTrjRes++); btx = *(t_auxTrjRes++); *(tOutBtX++) = btx; *(tOutY++) = *(t_auxTrjRes++); bty = *(t_auxTrjRes++); *(tOutBtY++) = bty; if(pOutZ) *(tOutZ++) = *t_auxTrjRes; t_auxTrjRes++; if(pOutBtZ) *(tOutBtZ++) = CGenMathMeth::radicalOnePlusSmall(-(gamEm2 + btx*btx + bty*bty)); } } delete[] auxTrjRes; } else { //normally, initial conditions should be already set here int nsRight = ns - is0; if(nsRight < 1) nsRight = 1; double *auxTrjRes = new double[nsRight*5]; if(auxTrjRes == 0) throw MEMORY_ALLOCATION_FAILURE; if(nsRight <= 1) { double *t_auxTrjRes = auxTrjRes; //*(t_auxTrjRes++) = s0Act; for(int i=0; i<5; i++) *(t_auxTrjRes++) = initCond[i]; } //s0Act has been defined above! else IntegrateKicks(arKickM, vIndNonOverlapKickGroups, vIndNonOverlapKickGroupRanges, inv_B_pho, initCond, s0Act, sEnd, nsRight, auxTrjRes); //else gmIntRK.solve(initCond, s0Act, sMax, nsRight, auxTrjRes); double *t_auxTrjRes = auxTrjRes; for(int j=0; j<nsRight; j++) { if(trjShouldBeAdded) { *(tOutX++) += *(t_auxTrjRes++); *tOutBtX += *(t_auxTrjRes++); btx = *(tOutBtX++); *(tOutY++) += *(t_auxTrjRes++); *tOutBtY += *(t_auxTrjRes++); bty = *(tOutBtY++); //if(pOutZ) *(tOutZ++) += *t_auxTrjRes; //longitudinal position is not modified in this case t_auxTrjRes++; if(pOutBtZ) *(tOutBtZ++) = CGenMathMeth::radicalOnePlusSmall(-(gamEm2 + btx*btx + bty*bty)); } else { *(tOutX++) = *(t_auxTrjRes++); btx = *(t_auxTrjRes++); *(tOutBtX++) = btx; *(tOutY++) = *(t_auxTrjRes++); bty = *(t_auxTrjRes++); *(tOutBtY++) = bty; if(pOutZ) *(tOutZ++) = *t_auxTrjRes; t_auxTrjRes++; if(pOutBtZ) *(tOutBtZ++) = CGenMathMeth::radicalOnePlusSmall(-(gamEm2 + btx*btx + bty*bty)); } } delete[] auxTrjRes; } } }
// TODO(halcanary): this function is complex enough to need its logic // tested with unit tests. sk_sp<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(SkGlyphCache* cache, const SkBitSet* subset, uint16_t emSize, int16_t* defaultAdvance) { // Assuming that on average, the ASCII representation of an advance plus // a space is 8 characters and the ASCII representation of a glyph id is 3 // characters, then the following cut offs for using different range types // apply: // The cost of stopping and starting the range is 7 characers // a. Removing 4 0's or don't care's is a win // The cost of stopping and starting the range plus a run is 22 // characters // b. Removing 3 repeating advances is a win // c. Removing 2 repeating advances and 3 don't cares is a win // When not currently in a range the cost of a run over a range is 16 // characaters, so: // d. Removing a leading 0/don't cares is a win because it is omitted // e. Removing 2 repeating advances is a win auto result = sk_make_sp<SkPDFArray>(); int num_glyphs = SkToInt(cache->getGlyphCount()); bool prevRange = false; int16_t lastAdvance = kInvalidAdvance; int repeatedAdvances = 0; int wildCardsInRun = 0; int trailingWildCards = 0; // Limit the loop count to glyph id ranges provided. int lastIndex = num_glyphs; if (subset) { while (!subset->has(lastIndex - 1) && lastIndex > 0) { --lastIndex; } } AdvanceMetric curRange(0); for (int gId = 0; gId <= lastIndex; gId++) { int16_t advance = kInvalidAdvance; if (gId < lastIndex) { if (!subset || 0 == gId || subset->has(gId)) { advance = (int16_t)cache->getGlyphIDAdvance(gId).fAdvanceX; } else { advance = kDontCareAdvance; } } if (advance == lastAdvance) { repeatedAdvances++; trailingWildCards = 0; } else if (advance == kDontCareAdvance) { wildCardsInRun++; trailingWildCards++; } else if (curRange.fAdvance.count() == repeatedAdvances + 1 + wildCardsInRun) { // All in run. if (lastAdvance == 0) { curRange.fStartId = gId; // reset curRange.fAdvance.setCount(0); trailingWildCards = 0; } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) { finish_range(&curRange, gId - 1, AdvanceMetric::kRun); compose_advance_data(curRange, emSize, defaultAdvance, result.get()); prevRange = true; curRange = AdvanceMetric(gId); trailingWildCards = 0; } repeatedAdvances = 0; wildCardsInRun = trailingWildCards; trailingWildCards = 0; } else { if (lastAdvance == 0 && repeatedAdvances + 1 + wildCardsInRun >= 4) { finish_range(&curRange, gId - repeatedAdvances - wildCardsInRun - 2, AdvanceMetric::kRange); compose_advance_data(curRange, emSize, defaultAdvance, result.get()); prevRange = true; curRange = AdvanceMetric(gId); trailingWildCards = 0; } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) { finish_range(&curRange, gId - trailingWildCards - 1, AdvanceMetric::kRange); compose_advance_data(curRange, emSize, defaultAdvance, result.get()); prevRange = true; curRange = AdvanceMetric(gId); trailingWildCards = 0; } else if (lastAdvance != 0 && (repeatedAdvances + 1 >= 3 || (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) { finish_range(&curRange, gId - repeatedAdvances - wildCardsInRun - 2, AdvanceMetric::kRange); compose_advance_data(curRange, emSize, defaultAdvance, result.get()); curRange = AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1); curRange.fAdvance.append(1, &lastAdvance); finish_range(&curRange, gId - 1, AdvanceMetric::kRun); compose_advance_data(curRange, emSize, defaultAdvance, result.get()); prevRange = true; curRange = AdvanceMetric(gId); trailingWildCards = 0; } repeatedAdvances = 0; wildCardsInRun = trailingWildCards; trailingWildCards = 0; } curRange.fAdvance.append(1, &advance); if (advance != kDontCareAdvance) { lastAdvance = advance; } } if (curRange.fStartId == lastIndex) { if (!prevRange) { return nullptr; // https://crbug.com/567031 } } else { finish_range(&curRange, lastIndex - 1, AdvanceMetric::kRange); compose_advance_data(curRange, emSize, defaultAdvance, result.get()); } return result; }
void SkAdvancedTypefaceMetrics::setGlyphWidths( FontHandle fontHandle, int num_glyphs, const uint32_t* subsetGlyphIDs, uint32_t subsetGlyphIDsLength, bool (*getAdvance)(FontHandle fontHandle, int gId, int16_t* data)) { // Assuming that on average, the ASCII representation of an advance plus // a space is 8 characters and the ASCII representation of a glyph id is 3 // characters, then the following cut offs for using different range types // apply: // The cost of stopping and starting the range is 7 characers // a. Removing 4 0's or don't care's is a win // The cost of stopping and starting the range plus a run is 22 // characters // b. Removing 3 repeating advances is a win // c. Removing 2 repeating advances and 3 don't cares is a win // When not currently in a range the cost of a run over a range is 16 // characaters, so: // d. Removing a leading 0/don't cares is a win because it is omitted // e. Removing 2 repeating advances is a win WidthRange* prevRange = nullptr; int16_t lastAdvance = kInvalidAdvance; int repeatedAdvances = 0; int wildCardsInRun = 0; int trailingWildCards = 0; uint32_t subsetIndex = 0; // Limit the loop count to glyph id ranges provided. int firstIndex = 0; int lastIndex = num_glyphs; if (subsetGlyphIDs) { firstIndex = static_cast<int>(subsetGlyphIDs[0]); lastIndex = static_cast<int>(subsetGlyphIDs[subsetGlyphIDsLength - 1]) + 1; } WidthRange curRange(firstIndex); for (int gId = firstIndex; gId <= lastIndex; gId++) { int16_t advance = kInvalidAdvance; if (gId < lastIndex) { // Get glyph id only when subset is nullptr, or the id is in subset. SkASSERT(!subsetGlyphIDs || (subsetIndex < subsetGlyphIDsLength && static_cast<uint32_t>(gId) <= subsetGlyphIDs[subsetIndex])); if (!subsetGlyphIDs || (subsetIndex < subsetGlyphIDsLength && static_cast<uint32_t>(gId) == subsetGlyphIDs[subsetIndex])) { SkAssertResult(getAdvance(fontHandle, gId, &advance)); ++subsetIndex; } else { advance = kDontCareAdvance; } } if (advance == lastAdvance) { repeatedAdvances++; trailingWildCards = 0; } else if (advance == kDontCareAdvance) { wildCardsInRun++; trailingWildCards++; } else if (curRange.fAdvance.count() == repeatedAdvances + 1 + wildCardsInRun) { // All in run. if (lastAdvance == 0) { curRange.fStartId = gId; // reset curRange.fAdvance.setCount(0); trailingWildCards = 0; } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) { FinishRange(&curRange, gId - 1, WidthRange::kRun); prevRange = fGlyphWidths.emplace_back(std::move(curRange)); curRange = WidthRange(gId); trailingWildCards = 0; } repeatedAdvances = 0; wildCardsInRun = trailingWildCards; trailingWildCards = 0; } else { if (lastAdvance == 0 && repeatedAdvances + 1 + wildCardsInRun >= 4) { FinishRange(&curRange, gId - repeatedAdvances - wildCardsInRun - 2, WidthRange::kRange); prevRange = fGlyphWidths.emplace_back(std::move(curRange)); curRange = WidthRange(gId); trailingWildCards = 0; } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) { FinishRange(&curRange, gId - trailingWildCards - 1, WidthRange::kRange); prevRange = fGlyphWidths.emplace_back(std::move(curRange)); curRange = WidthRange(gId); trailingWildCards = 0; } else if (lastAdvance != 0 && (repeatedAdvances + 1 >= 3 || (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) { FinishRange(&curRange, gId - repeatedAdvances - wildCardsInRun - 2, WidthRange::kRange); (void)fGlyphWidths.emplace_back(std::move(curRange)); curRange = WidthRange(gId - repeatedAdvances - wildCardsInRun - 1); curRange.fAdvance.append(1, &lastAdvance); FinishRange(&curRange, gId - 1, WidthRange::kRun); prevRange = fGlyphWidths.emplace_back(std::move(curRange)); curRange = WidthRange(gId); trailingWildCards = 0; } repeatedAdvances = 0; wildCardsInRun = trailingWildCards; trailingWildCards = 0; } curRange.fAdvance.append(1, &advance); if (advance != kDontCareAdvance) { lastAdvance = advance; } } if (curRange.fStartId == lastIndex) { SkASSERT(prevRange); if (!prevRange) { fGlyphWidths.reset(); return; // https://crbug.com/567031 } } else { FinishRange(&curRange, lastIndex - 1, WidthRange::kRange); fGlyphWidths.emplace_back(std::move(curRange)); } }