Beispiel #1
0
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));
    }
}